@json-to-office/core-docx 7.6.4 → 7.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -9,9 +9,9 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
9
9
  var __esm = (fn, res) => function __init() {
10
10
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
11
  };
12
- var __export = (target, all) => {
12
+ var __export = (target2, all) => {
13
13
  for (var name in all)
14
- __defProp(target, name, { get: all[name], enumerable: true });
14
+ __defProp(target2, name, { get: all[name], enumerable: true });
15
15
  };
16
16
 
17
17
  // src/utils/generationContext.ts
@@ -4357,15 +4357,15 @@ function canonicalizeEmbeddedFontKeys(zip) {
4357
4357
  const targets = /* @__PURE__ */ new Map();
4358
4358
  for (const [relationship] of rels.matchAll(/<Relationship\b[^>]*>/g)) {
4359
4359
  const id = /\bId="([^"]+)"/.exec(relationship)?.[1];
4360
- const target = /\bTarget="([^"]+)"/.exec(relationship)?.[1];
4361
- if (id && target) targets.set(id, target);
4360
+ const target2 = /\bTarget="([^"]+)"/.exec(relationship)?.[1];
4361
+ if (id && target2) targets.set(id, target2);
4362
4362
  }
4363
4363
  const rekey = /* @__PURE__ */ new Map();
4364
4364
  const parts = [];
4365
4365
  for (const { id, key } of embeds) {
4366
- const target = targets.get(id);
4367
- if (!target) continue;
4368
- const name = target.startsWith("/") ? target.slice(1) : posix.normalize(posix.join("word", target));
4366
+ const target2 = targets.get(id);
4367
+ if (!target2) continue;
4368
+ const name = target2.startsWith("/") ? target2.slice(1) : posix.normalize(posix.join("word", target2));
4369
4369
  const part = zip.getEntry(name);
4370
4370
  if (!part) continue;
4371
4371
  const font = xorFontKey(part.getData(), key);
@@ -5386,7 +5386,7 @@ function chromeSlots(set, Part, resources) {
5386
5386
  const part = set[slot];
5387
5387
  if (part) {
5388
5388
  out[slot] = new Part({
5389
- children: emitOutsideBody(() => partChildren(part, resources))
5389
+ children: part.children.length > 0 ? emitOutsideBody(() => partChildren(part, resources)) : [new Paragraph2({ style: Part === Header ? "Header" : "Footer" })]
5390
5390
  });
5391
5391
  }
5392
5392
  }
@@ -6622,15 +6622,16 @@ function section(value, ctx, closesDocument = false) {
6622
6622
  grid: { type: "default", linePitch: 360, charSpace: 0 }
6623
6623
  },
6624
6624
  children: sectionChildren2(value, ctx, closesDocument),
6625
- ...value.headers ? { headers: headerFooterSet(value.headers, ctx) } : {},
6626
- ...value.footers ? { footers: headerFooterSet(value.footers, ctx) } : {}
6625
+ ...value.headers ? { headers: headerFooterSet(value.headers, "Header", ctx) } : {},
6626
+ ...value.footers ? { footers: headerFooterSet(value.footers, "Footer", ctx) } : {}
6627
6627
  };
6628
6628
  }
6629
- function headerFooterSet(set, ctx) {
6629
+ function headerFooterSet(set, style, ctx) {
6630
6630
  const out = {};
6631
6631
  for (const slot of ["default", "first", "even"]) {
6632
6632
  const part = set[slot];
6633
- if (part) out[slot] = part.children.map((child) => block(child, ctx));
6633
+ if (!part) continue;
6634
+ out[slot] = part.children.length > 0 ? part.children.map((child) => block(child, ctx)) : [{ paragraph: { style, children: [] } }];
6634
6635
  }
6635
6636
  return out;
6636
6637
  }
@@ -7455,11 +7456,11 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
7455
7456
  );
7456
7457
  let fontsRejected = false;
7457
7458
  const requestFonts = () => fontsRejected || !options.fonts?.length ? void 0 : options.fonts;
7458
- const rasterizeOne = async (target) => {
7459
+ const rasterizeOne = async (target2) => {
7459
7460
  const fonts = requestFonts();
7460
7461
  const call = (withFonts) => rasterizeVisualSlide(
7461
- target.presentation,
7462
- target.dpi,
7462
+ target2.presentation,
7463
+ target2.dpi,
7463
7464
  void 0,
7464
7465
  serviceConfig,
7465
7466
  options.baseDir,
@@ -7483,8 +7484,8 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
7483
7484
  const rasterizeIndividually = async (chunk) => {
7484
7485
  await Promise.all(
7485
7486
  chunk.map(
7486
- (target) => limit(async () => {
7487
- map.set(target.key, await rasterizeOne(target));
7487
+ (target2) => limit(async () => {
7488
+ map.set(target2.key, await rasterizeOne(target2));
7488
7489
  })
7489
7490
  )
7490
7491
  );
@@ -7493,9 +7494,9 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
7493
7494
  for (const chunk of chunksOf(unique, MAX_RASTERIZE_BATCH_SLIDES)) {
7494
7495
  try {
7495
7496
  const response = await serviceConfig.renderBatch({
7496
- slides: chunk.map((target) => ({
7497
- presentation: target.presentation,
7498
- dpi: target.dpi
7497
+ slides: chunk.map((target2) => ({
7498
+ presentation: target2.presentation,
7499
+ dpi: target2.dpi
7499
7500
  })),
7500
7501
  ...options.baseDir !== void 0 && { baseDir: options.baseDir },
7501
7502
  ...options.fonts?.length ? { fonts: [...options.fonts] } : {}
@@ -7510,8 +7511,8 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
7510
7511
  await rasterizeIndividually(chunk);
7511
7512
  } else {
7512
7513
  const message = toErrorMessage(error);
7513
- for (const target of chunk) {
7514
- map.set(target.key, { ok: false, error: message });
7514
+ for (const target2 of chunk) {
7515
+ map.set(target2.key, { ok: false, error: message });
7515
7516
  }
7516
7517
  }
7517
7518
  }
@@ -7534,9 +7535,9 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
7534
7535
  url: serverUrl,
7535
7536
  path: "/rasterize/batch",
7536
7537
  body: {
7537
- slides: chunk.map((target) => ({
7538
- presentation: target.presentation,
7539
- dpi: target.dpi
7538
+ slides: chunk.map((target2) => ({
7539
+ presentation: target2.presentation,
7540
+ dpi: target2.dpi
7540
7541
  })),
7541
7542
  ...options.baseDir !== void 0 && { baseDir: options.baseDir },
7542
7543
  ...fonts?.length ? { fonts } : {}
@@ -7579,6 +7580,49 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
7579
7580
  return map;
7580
7581
  }
7581
7582
 
7583
+ // src/core/nodeOrigin.ts
7584
+ var NODE_ORIGIN = Symbol("json-to-office.nodeOrigin");
7585
+ function isComponentNode(value) {
7586
+ return typeof value.name === "string" && "props" in value;
7587
+ }
7588
+ function isPlainRecord(value) {
7589
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
7590
+ const proto = Object.getPrototypeOf(value);
7591
+ return proto === Object.prototype || proto === null;
7592
+ }
7593
+ function tagNodeOrigins(root) {
7594
+ const visit = (value, path4) => {
7595
+ if (Array.isArray(value)) {
7596
+ return value.map((item, index) => visit(item, join(path4, index)));
7597
+ }
7598
+ if (!isPlainRecord(value)) return value;
7599
+ const out = {};
7600
+ for (const [key, item] of Object.entries(value)) {
7601
+ out[key] = visit(item, join(path4, key));
7602
+ }
7603
+ if (path4 !== "" && isComponentNode(value)) {
7604
+ out[NODE_ORIGIN] = {
7605
+ standardPath: path4,
7606
+ kind: value.name
7607
+ };
7608
+ }
7609
+ return out;
7610
+ };
7611
+ return visit(root, "");
7612
+ }
7613
+ function join(path4, key) {
7614
+ return path4 === "" ? String(key) : `${path4}.${key}`;
7615
+ }
7616
+ function nodeOrigin(node) {
7617
+ if (!node || typeof node !== "object") return void 0;
7618
+ return node[NODE_ORIGIN];
7619
+ }
7620
+ function withNodeOrigin(original, next) {
7621
+ const origin = nodeOrigin(original);
7622
+ if (origin) next[NODE_ORIGIN] = origin;
7623
+ return next;
7624
+ }
7625
+
7582
7626
  // src/core/componentTransform.ts
7583
7627
  async function transformComponents(doc, replace) {
7584
7628
  return await walk(doc, replace);
@@ -7644,7 +7688,7 @@ function withNodeIdentity(original, replacement) {
7644
7688
  const out = { ...replacement };
7645
7689
  if (original.id !== void 0) out.id = original.id;
7646
7690
  if (original.enabled !== void 0) out.enabled = original.enabled;
7647
- return out;
7691
+ return withNodeOrigin(original, out);
7648
7692
  }
7649
7693
  function containsComponent(root, name) {
7650
7694
  const seen = /* @__PURE__ */ new WeakSet();
@@ -7718,15 +7762,7 @@ async function generateChart(config, servicesConfig, warnings, cache) {
7718
7762
  }
7719
7763
  const serverUrl = effectiveChartServerUrl(config, servicesConfig);
7720
7764
  assertExportServerAllowed(serverUrl, servicesConfig, warnings);
7721
- const requestBody = {
7722
- infile: config.options,
7723
- type: "png",
7724
- b64: true,
7725
- scale: config.scale,
7726
- // Forward resources verbatim only when present so the payload stays
7727
- // byte-identical to before for callers that omit it.
7728
- ...config.resources ? { resources: config.resources } : {}
7729
- };
7765
+ const requestBody = chartRequestBody(config);
7730
7766
  return sendChartRequest({
7731
7767
  cache,
7732
7768
  serverUrl,
@@ -7844,15 +7880,32 @@ function withChartFontFaces(config, theme, faces) {
7844
7880
  theme.fonts.heading.family
7845
7881
  ]);
7846
7882
  }
7847
- async function renderChartToImageProps(props, theme, servicesConfig, chartFonts, warnings, cache) {
7848
- const config = withChartFontFaces(
7883
+ function resolveChartConfig(props, theme, fonts) {
7884
+ return withChartFontFaces(
7849
7885
  withThemeTypography(
7850
7886
  withThemeColors(withThemePresets(props, theme), theme),
7851
7887
  theme
7852
7888
  ),
7853
7889
  theme,
7854
- chartFonts
7890
+ fonts
7855
7891
  );
7892
+ }
7893
+ function chartRequestBody(config) {
7894
+ return {
7895
+ infile: config.options,
7896
+ type: "png",
7897
+ b64: true,
7898
+ scale: config.scale,
7899
+ // Forward resources verbatim only when present so the payload stays
7900
+ // byte-identical to before for callers that omit it.
7901
+ ...config.resources ? { resources: config.resources } : {}
7902
+ };
7903
+ }
7904
+ function resolveChartRequest(props, renderTheme, fontFaces) {
7905
+ return chartRequestBody(resolveChartConfig(props, renderTheme, fontFaces));
7906
+ }
7907
+ async function renderChartToImageProps(props, theme, servicesConfig, chartFonts, warnings, cache) {
7908
+ const config = resolveChartConfig(props, theme, chartFonts);
7856
7909
  const chart = await generateChart(config, servicesConfig, warnings, cache);
7857
7910
  const hasConfigDimensions = config.width !== void 0 || config.height !== void 0;
7858
7911
  return {
@@ -10569,12 +10622,12 @@ function parseLinks(normalized, options) {
10569
10622
  continue;
10570
10623
  }
10571
10624
  const [, linkText] = match;
10572
- const target = decodeEscapes(match[2]);
10625
+ const target2 = decodeEscapes(match[2]);
10573
10626
  out.push({
10574
10627
  kind: "hyperlink",
10575
10628
  // A `#anchor` target names a bookmark in this document and needs no
10576
10629
  // relationship; anything else leaves the document.
10577
- target: target.startsWith("#") ? { kind: "bookmark", anchor: target.slice(1) } : { kind: "external", url: target },
10630
+ target: target2.startsWith("#") ? { kind: "bookmark", anchor: target2.slice(1) } : { kind: "external", url: target2 },
10578
10631
  children: parseDecorated(linkText, options)
10579
10632
  });
10580
10633
  }
@@ -10830,6 +10883,7 @@ function compileDocument(structure, layout2, warnings = [], images = /* @__PURE_
10830
10883
  numberedItems: outline.numberedItems,
10831
10884
  tocEntries: outline.entries,
10832
10885
  images,
10886
+ imageOrigins: /* @__PURE__ */ new WeakMap(),
10833
10887
  generatedAt: structure.metadata.date
10834
10888
  };
10835
10889
  ctx.features.require("paragraphs", "sections");
@@ -10883,9 +10937,19 @@ function compileDocument(structure, layout2, warnings = [], images = /* @__PURE_
10883
10937
  ir,
10884
10938
  required: ctx.features.list(),
10885
10939
  warnings: ctx.warnings,
10886
- unsupported: ctx.unsupported
10940
+ unsupported: ctx.unsupported,
10941
+ imageOrigins: ctx.imageOrigins
10887
10942
  };
10888
10943
  }
10944
+ function recordImageOrigin(ctx, component, images) {
10945
+ const origin = nodeOrigin(component);
10946
+ if (!origin) return;
10947
+ for (const image of images) {
10948
+ if (image.kind === "image" || image.kind === "picture") {
10949
+ ctx.imageOrigins.set(image, origin);
10950
+ }
10951
+ }
10952
+ }
10889
10953
  var AFTER_TABLE_TWIPS = 120;
10890
10954
  var BEFORE_TABLE_TWIPS = 240;
10891
10955
  var BODY_STYLE_IDS = /* @__PURE__ */ new Set([void 0, "Normal"]);
@@ -11213,6 +11277,7 @@ function compileChromeImage(component, scope) {
11213
11277
  heightEmu: pixelsToEmu(size.height),
11214
11278
  ...props.floating ? { floating: compileFloating(props.floating, ctx, path4) } : {}
11215
11279
  };
11280
+ recordImageOrigin(ctx, component, [image]);
11216
11281
  return [
11217
11282
  {
11218
11283
  kind: "paragraph",
@@ -12712,6 +12777,7 @@ function compileVisual(component, scope) {
12712
12777
  nativeVisualDeps(ctx, path4)
12713
12778
  );
12714
12779
  if (!group) return [];
12780
+ recordImageOrigin(ctx, component, group.children);
12715
12781
  const size = visualPlacementPixels(props, group.canvas, {
12716
12782
  widthPx: Math.round(twipsToPixels(scope.measureTwips)),
12717
12783
  heightPx: Math.round(twipsToPixels(getAvailableHeightTwips(ctx.theme)))
@@ -12838,6 +12904,7 @@ function compileImage2(component, scope) {
12838
12904
  ...typeof props.alt === "string" && props.alt ? { altText: props.alt } : {},
12839
12905
  ...props.floating ? { floating: compileFloating(props.floating, ctx, path4) } : {}
12840
12906
  };
12907
+ recordImageOrigin(ctx, component, [image]);
12841
12908
  ctx.features.require("images", path4);
12842
12909
  if (props.floating) ctx.features.require("floating-images", path4);
12843
12910
  const spacing = {};
@@ -13602,6 +13669,7 @@ function cellVisual(component, scope) {
13602
13669
  nativeVisualDeps(ctx, path4)
13603
13670
  );
13604
13671
  if (!group) return [];
13672
+ recordImageOrigin(ctx, component, group.children);
13605
13673
  const size = visualPlacementPixels(props, group.canvas, {
13606
13674
  widthPx: CELL_DRAWING_REFERENCE.width,
13607
13675
  heightPx: CELL_DRAWING_REFERENCE.height
@@ -13647,14 +13715,14 @@ function cellImage(component, base, ctx) {
13647
13715
  const mediaType = detectImageType(source, loaded.contentType);
13648
13716
  if (mediaType === "svg") ctx.features.require("svg-images", "table");
13649
13717
  ctx.features.require("images", "table");
13650
- return [
13651
- {
13652
- kind: "image",
13653
- resourceId: declareResource(loaded, mediaType, ctx),
13654
- widthEmu: pixelsToEmu(size.width),
13655
- heightEmu: pixelsToEmu(size.height)
13656
- }
13657
- ];
13718
+ const image = {
13719
+ kind: "image",
13720
+ resourceId: declareResource(loaded, mediaType, ctx),
13721
+ widthEmu: pixelsToEmu(size.width),
13722
+ heightEmu: pixelsToEmu(size.height)
13723
+ };
13724
+ recordImageOrigin(ctx, component, [image]);
13725
+ return [image];
13658
13726
  }
13659
13727
  function placeholderFormatting(base) {
13660
13728
  return {
@@ -16404,7 +16472,7 @@ async function compileDocumentScoped(document, options, warnings) {
16404
16472
  const embeddedFonts = embedding ? selectEmbeddedFonts(resolvedFonts, warnings) : [];
16405
16473
  const visualFonts = hasVisual ? toRasterizeFontFaces(resolvedFonts, warnings) : [];
16406
16474
  const chartFonts = hasHighcharts ? toChartFontFaces(resolvedFonts) : [];
16407
- const desugared = await desugarExternals(context.document, {
16475
+ const desugared = await desugarExternals(tagNodeOrigins(context.document), {
16408
16476
  theme: prepared.model.document.theme,
16409
16477
  ...options.services ? { services: options.services } : {},
16410
16478
  ...options.baseDir !== void 0 ? { baseDir: options.baseDir } : {},
@@ -16442,6 +16510,7 @@ async function compileDocumentScoped(document, options, warnings) {
16442
16510
  warnings: compiled.warnings,
16443
16511
  required: compiled.required,
16444
16512
  unsupported: compiled.unsupported,
16513
+ imageOrigins: compiled.imageOrigins,
16445
16514
  embeddedFonts
16446
16515
  };
16447
16516
  }
@@ -16469,7 +16538,12 @@ async function renderScoped(document, options, warnings) {
16469
16538
  ...compiled.embeddedFonts.length > 0 ? { embeddedFonts: compiled.embeddedFonts } : {},
16470
16539
  warnings: compiled.warnings
16471
16540
  });
16472
- return { buffer: Buffer.from(bytes), warnings: compiled.warnings };
16541
+ return {
16542
+ buffer: Buffer.from(bytes),
16543
+ warnings: compiled.warnings,
16544
+ ir: compiled.ir,
16545
+ imageOrigins: compiled.imageOrigins
16546
+ };
16473
16547
  }
16474
16548
  function toDate(value) {
16475
16549
  return value instanceof Date ? value : new Date(value);
@@ -16492,7 +16566,7 @@ import {
16492
16566
 
16493
16567
  // src/json/filesystem.ts
16494
16568
  import { promises as fs3 } from "fs";
16495
- import { join, resolve as resolve2, isAbsolute as isAbsolute2 } from "path";
16569
+ import { join as join2, resolve as resolve2, isAbsolute as isAbsolute2 } from "path";
16496
16570
  async function loadJsonDefinition(filePath) {
16497
16571
  try {
16498
16572
  const absolutePath = isAbsolute2(filePath) ? filePath : resolve2(filePath);
@@ -18063,7 +18137,7 @@ import {
18063
18137
  import { collectPlaceholders as collectPlaceholders2 } from "@json-to-office/quality";
18064
18138
  import { existsSync, readdirSync, readFileSync as readFileSync2 } from "fs";
18065
18139
  import { fileURLToPath as fileURLToPath2 } from "url";
18066
- import { dirname as dirname2, join as join2 } from "path";
18140
+ import { dirname as dirname2, join as join3 } from "path";
18067
18141
 
18068
18142
  // src/templates/blueprints/client-report.docx.blueprint.json
18069
18143
  var client_report_docx_blueprint_default = {
@@ -19258,11 +19332,11 @@ function scanned(known) {
19258
19332
  return [];
19259
19333
  }
19260
19334
  const directory = [
19261
- join2(here, "../templates/blueprints"),
19262
- join2(here, "templates/blueprints")
19335
+ join3(here, "../templates/blueprints"),
19336
+ join3(here, "templates/blueprints")
19263
19337
  ].find((path4) => existsSync(path4));
19264
19338
  if (!directory) return [];
19265
- return readdirSync(directory).filter((file) => file.endsWith(".docx.blueprint.json")).map((file) => JSON.parse(readFileSync2(join2(directory, file), "utf8"))).filter((candidate) => {
19339
+ return readdirSync(directory).filter((file) => file.endsWith(".docx.blueprint.json")).map((file) => JSON.parse(readFileSync2(join3(directory, file), "utf8"))).filter((candidate) => {
19266
19340
  const id = candidate?.id;
19267
19341
  return !(typeof id === "string" && id in known);
19268
19342
  });
@@ -19442,6 +19516,36 @@ var textSpaceAfterComponent = createComponent({
19442
19516
  }
19443
19517
  });
19444
19518
 
19519
+ // src/components/highchartsOptions.ts
19520
+ init_layoutUtils();
19521
+ function chartRenderTheme(input) {
19522
+ const document = {
19523
+ name: "docx",
19524
+ props: { ...input.documentProps },
19525
+ children: []
19526
+ };
19527
+ const context = resolveThemeContext(document, {
19528
+ ...input.fonts ? { fonts: input.fonts } : {},
19529
+ warnings: [],
19530
+ resolveNamedTheme: () => input.theme
19531
+ });
19532
+ const { theme } = resolveDocumentTree(context.document, context.theme);
19533
+ return themeForSectionPage(theme, input.page);
19534
+ }
19535
+ function resolveHighchartsRequest(input) {
19536
+ const props = {
19537
+ options: input.options,
19538
+ ...input.width !== void 0 && { width: input.width },
19539
+ ...input.height !== void 0 && { height: input.height },
19540
+ ...input.scale !== void 0 && { scale: input.scale },
19541
+ ...input.resources !== void 0 && { resources: input.resources }
19542
+ };
19543
+ return resolveChartRequest(props, chartRenderTheme(input), input.fontFaces);
19544
+ }
19545
+ function resolveHighchartsOptions(input) {
19546
+ return resolveHighchartsRequest(input).infile;
19547
+ }
19548
+
19445
19549
  // src/plugin/createDocumentGenerator.ts
19446
19550
  init_themes();
19447
19551
 
@@ -19671,7 +19775,280 @@ function mergeSchemas(customComponents, standardSchemas) {
19671
19775
  };
19672
19776
  }
19673
19777
 
19778
+ // src/core/renderManifest.ts
19779
+ init_units();
19780
+ import AdmZip6 from "adm-zip";
19781
+ import { posix as posix2 } from "path";
19782
+ var HEADER_FOOTER_TYPES = ["default", "first", "even"];
19783
+ function buildRenderManifest(buffer, ir, imageOrigins, sourceOrigins = /* @__PURE__ */ new Map()) {
19784
+ try {
19785
+ return {
19786
+ ok: true,
19787
+ manifest: collect(buffer, ir, imageOrigins, sourceOrigins)
19788
+ };
19789
+ } catch (error) {
19790
+ return {
19791
+ ok: false,
19792
+ reason: error instanceof Error ? error.message : String(error)
19793
+ };
19794
+ }
19795
+ }
19796
+ function collect(buffer, ir, imageOrigins, sourceOrigins) {
19797
+ const zip = new AdmZip6(buffer);
19798
+ const read = (entry) => zip.getEntry(entry)?.getData().toString("utf8");
19799
+ const media = /* @__PURE__ */ new Map();
19800
+ const mediaHash = (path4) => {
19801
+ let hash = media.get(path4);
19802
+ if (hash === void 0) {
19803
+ const entry = zip.getEntry(path4);
19804
+ if (!entry) throw new Error(`the package has no ${path4}`);
19805
+ hash = sha256Hex(new Uint8Array(entry.getData()));
19806
+ media.set(path4, hash);
19807
+ }
19808
+ return hash;
19809
+ };
19810
+ const resources = new Map(ir.resources.map((r) => [r.id, r]));
19811
+ const manifest = [];
19812
+ const pair = (part, partPath, xml, images) => {
19813
+ const rels = relationships(read(relsPathOf(partPath)), partPath);
19814
+ const blips = readBlips(xml);
19815
+ if (blips.length !== images.length) {
19816
+ throw new Error(
19817
+ `${partPath} embeds ${blips.length} image(s) where the IR placed ${images.length}`
19818
+ );
19819
+ }
19820
+ blips.forEach((blip, index) => {
19821
+ const image = images[index];
19822
+ const mediaPath = target(rels, blip.embed, partPath);
19823
+ const sha256 = mediaHash(mediaPath);
19824
+ const resource = resources.get(image.resourceId);
19825
+ if (!resource || !matchesResource(resource, blip, sha256, rels, partPath, mediaHash)) {
19826
+ throw new Error(
19827
+ `image ${index + 1} of ${partPath} (${mediaPath}) does not hold the bytes of IR resource ${image.resourceId}`
19828
+ );
19829
+ }
19830
+ const origin = imageOrigins.get(image);
19831
+ if (!origin) {
19832
+ throw new Error(
19833
+ `image ${index + 1} of ${partPath} has no standard-definition origin`
19834
+ );
19835
+ }
19836
+ const source = sourceOriginOf(origin.standardPath, sourceOrigins);
19837
+ manifest.push({
19838
+ part,
19839
+ partPath,
19840
+ mediaPath,
19841
+ sha256,
19842
+ standardPath: origin.standardPath,
19843
+ kind: origin.kind,
19844
+ ...source && {
19845
+ sourcePath: source.sourcePath,
19846
+ sourceKind: source.sourceKind
19847
+ }
19848
+ });
19849
+ });
19850
+ };
19851
+ const documentPath = "word/document.xml";
19852
+ const documentXml = read(documentPath);
19853
+ if (documentXml === void 0)
19854
+ throw new Error(`the package has no ${documentPath}`);
19855
+ pair(
19856
+ "body",
19857
+ documentPath,
19858
+ documentXml,
19859
+ ir.sections.flatMap((section2) => blockImages(section2.children))
19860
+ );
19861
+ const sectPrs = sectionProperties(documentXml);
19862
+ if (sectPrs.length !== ir.sections.length) {
19863
+ throw new Error(
19864
+ `${documentPath} has ${sectPrs.length} section(s) where the IR has ${ir.sections.length}`
19865
+ );
19866
+ }
19867
+ const documentRels = relationships(
19868
+ read(relsPathOf(documentPath)),
19869
+ documentPath
19870
+ );
19871
+ const seen = /* @__PURE__ */ new Set();
19872
+ ir.sections.forEach((section2, index) => {
19873
+ const references = chromeReferences(sectPrs[index]);
19874
+ for (const part of ["header", "footer"]) {
19875
+ const set = part === "header" ? section2.headers : section2.footers;
19876
+ for (const type of HEADER_FOOTER_TYPES) {
19877
+ const id = references.get(`${part}:${type}`);
19878
+ if (id === void 0) continue;
19879
+ const partPath = target(documentRels, id, documentPath);
19880
+ if (seen.has(partPath)) continue;
19881
+ seen.add(partPath);
19882
+ const xml = read(partPath);
19883
+ if (xml === void 0)
19884
+ throw new Error(`the package has no ${partPath}`);
19885
+ pair(part, partPath, xml, blockImages(set?.[type]?.children ?? []));
19886
+ }
19887
+ }
19888
+ });
19889
+ return manifest;
19890
+ }
19891
+ function sourceOriginOf(standardPath, sourceOrigins) {
19892
+ if (sourceOrigins.size === 0) return void 0;
19893
+ const segments = standardPath.split(".");
19894
+ for (let n = segments.length; n > 0; n--) {
19895
+ const hit = sourceOrigins.get(segments.slice(0, n).join("."));
19896
+ if (hit) return hit;
19897
+ }
19898
+ return void 0;
19899
+ }
19900
+ function matchesResource(resource, blip, sha256, rels, partPath, mediaHash) {
19901
+ if (sha256 === resource.sha256) return true;
19902
+ if (resource.mediaType !== "svg" || blip.svgEmbed === void 0) return false;
19903
+ return mediaHash(target(rels, blip.svgEmbed, partPath)) === resource.sha256;
19904
+ }
19905
+ function blockImages(blocks) {
19906
+ const out = [];
19907
+ const visitBlocks = (items) => {
19908
+ for (const block2 of items) {
19909
+ if (block2.kind === "paragraph") visitParagraph(block2);
19910
+ else if (block2.kind === "table") {
19911
+ for (const row of block2.rows) {
19912
+ for (const cell of row.cells) visitBlocks(cell.children);
19913
+ }
19914
+ }
19915
+ }
19916
+ };
19917
+ const visitParagraph = (paragraph2) => visitInlines(paragraph2.children);
19918
+ const visitInlines = (inlines) => {
19919
+ for (const inline of inlines) {
19920
+ switch (inline.kind) {
19921
+ case "image":
19922
+ out.push(inline);
19923
+ break;
19924
+ case "drawingGroup":
19925
+ for (const child of inline.children) {
19926
+ if (child.kind === "picture") out.push(child);
19927
+ }
19928
+ break;
19929
+ case "shape":
19930
+ inline.children.forEach(visitParagraph);
19931
+ break;
19932
+ case "hyperlink":
19933
+ case "revision":
19934
+ visitInlines(inline.children);
19935
+ break;
19936
+ default:
19937
+ break;
19938
+ }
19939
+ }
19940
+ };
19941
+ visitBlocks(blocks);
19942
+ return out;
19943
+ }
19944
+ function readBlips(xml) {
19945
+ const body = xml.replace(/<mc:Fallback\b[\s\S]*?<\/mc:Fallback>/g, "");
19946
+ const blips = [];
19947
+ const pattern = /<a:blip\b([^>]*?)(?:\/>|>([\s\S]*?)<\/a:blip>)/g;
19948
+ for (const match of body.matchAll(pattern)) {
19949
+ const embed = /\br:embed="([^"]+)"/.exec(match[1])?.[1];
19950
+ if (embed === void 0) continue;
19951
+ const svgEmbed = match[2] ? /<asvg:svgBlip\b[^>]*\br:embed="([^"]+)"/.exec(match[2])?.[1] : void 0;
19952
+ blips.push(svgEmbed === void 0 ? { embed } : { embed, svgEmbed });
19953
+ }
19954
+ return blips;
19955
+ }
19956
+ function sectionProperties(xml) {
19957
+ return [...xml.matchAll(/<w:sectPr\b(?:[^>]*\/>|[\s\S]*?<\/w:sectPr>)/g)].map(
19958
+ (m) => m[0]
19959
+ );
19960
+ }
19961
+ function chromeReferences(sectPr) {
19962
+ const out = /* @__PURE__ */ new Map();
19963
+ for (const match of sectPr.matchAll(
19964
+ /<w:(header|footer)Reference\b([^>]*)\/?>/g
19965
+ )) {
19966
+ const type = attribute(match[2], "w:type") ?? "default";
19967
+ const id = attribute(match[2], "r:id");
19968
+ if (id !== void 0) out.set(`${match[1]}:${type}`, id);
19969
+ }
19970
+ return out;
19971
+ }
19972
+ function relsPathOf(partPath) {
19973
+ return posix2.join(
19974
+ posix2.dirname(partPath),
19975
+ "_rels",
19976
+ `${posix2.basename(partPath)}.rels`
19977
+ );
19978
+ }
19979
+ function relationships(xml, partPath) {
19980
+ const out = /* @__PURE__ */ new Map();
19981
+ if (xml === void 0) return out;
19982
+ for (const match of xml.matchAll(/<Relationship\b([^>]*)\/?>/g)) {
19983
+ const id = attribute(match[1], "Id");
19984
+ const target2 = attribute(match[1], "Target");
19985
+ if (id !== void 0 && target2 !== void 0) out.set(id, target2);
19986
+ }
19987
+ if (out.size === 0 && /<Relationship\b/.test(xml)) {
19988
+ throw new Error(`the relationships of ${partPath} could not be read`);
19989
+ }
19990
+ return out;
19991
+ }
19992
+ function target(rels, id, partPath) {
19993
+ const raw = rels.get(id);
19994
+ if (raw === void 0) {
19995
+ throw new Error(`${partPath} references an unknown relationship ${id}`);
19996
+ }
19997
+ return raw.startsWith("/") ? raw.slice(1) : posix2.normalize(posix2.join(posix2.dirname(partPath), raw));
19998
+ }
19999
+ function attribute(attributes, name) {
20000
+ const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
20001
+ return new RegExp(`(?:^|\\s)${escaped}="([^"]*)"`).exec(attributes)?.[1];
20002
+ }
20003
+
19674
20004
  // src/plugin/createDocumentGenerator.ts
20005
+ var RENDER_MANIFEST_UNAVAILABLE = "W_DOCX_RENDER_MANIFEST_UNAVAILABLE";
20006
+ var ROOT_POSITION = {
20007
+ standard: "children",
20008
+ standardBase: 0,
20009
+ preserved: "children",
20010
+ preservedBase: 0
20011
+ };
20012
+ var DETACHED_POSITION = {
20013
+ standard: null,
20014
+ standardBase: 0,
20015
+ preserved: null,
20016
+ preservedBase: 0
20017
+ };
20018
+ function joinPath(path4, key) {
20019
+ return path4 === null ? null : `${path4}.${key}`;
20020
+ }
20021
+ function blockSourceOrigins(standard, preserved, preserveSet) {
20022
+ const origins = /* @__PURE__ */ new Map();
20023
+ const visit = (std, kept, path4) => {
20024
+ if (!std || !kept || typeof std !== "object" || typeof kept !== "object")
20025
+ return;
20026
+ const keptNode = kept;
20027
+ const stdNode = std;
20028
+ if (path4 !== "" && typeof keptNode.name === "string" && preserveSet.has(keptNode.name) && stdNode.name === "group") {
20029
+ origins.set(path4, { sourcePath: path4, sourceKind: keptNode.name });
20030
+ return;
20031
+ }
20032
+ for (const [key, value] of Object.entries(keptNode)) {
20033
+ if (key in stdNode) {
20034
+ visit(stdNode[key], value, path4 === "" ? key : `${path4}.${key}`);
20035
+ }
20036
+ }
20037
+ };
20038
+ visit(standard, preserved, "");
20039
+ return origins;
20040
+ }
20041
+ function manifestOf(buffer, ir, imageOrigins, sourceOrigins, warnings) {
20042
+ const built = buildRenderManifest(buffer, ir, imageOrigins, sourceOrigins);
20043
+ if (built.ok) return built.manifest;
20044
+ warnings.push({
20045
+ component: "docx",
20046
+ severity: "warning",
20047
+ message: `No render manifest: ${built.reason}.`,
20048
+ context: { code: RENDER_MANIFEST_UNAVAILABLE, reason: built.reason }
20049
+ });
20050
+ return void 0;
20051
+ }
19675
20052
  function createBuilderImpl(state) {
19676
20053
  const componentMap = new Map(state.components.map((c) => [c.name, c]));
19677
20054
  function resolveDocumentTheme(themeName, warnings, authored) {
@@ -19700,7 +20077,7 @@ function createBuilderImpl(state) {
19700
20077
  warnings
19701
20078
  });
19702
20079
  }
19703
- async function processDocumentComponents(components, preserveSet, warningsCollector, resolvedTheme, validateEmitted, depth = 0) {
20080
+ async function processDocumentComponents(components, preserveSet, warningsCollector, resolvedTheme, validateEmitted, at, origins, depth = 0) {
19704
20081
  if (depth > 20) {
19705
20082
  throw new Error(
19706
20083
  "Maximum component nesting depth exceeded (20). Check for circular component references."
@@ -19708,6 +20085,8 @@ function createBuilderImpl(state) {
19708
20085
  }
19709
20086
  const standardOut = [];
19710
20087
  const preservedOut = [];
20088
+ const nextStandardPath = () => joinPath(at.standard, at.standardBase + standardOut.length);
20089
+ const nextPreservedPath = () => joinPath(at.preserved, at.preservedBase + preservedOut.length);
19711
20090
  for (const componentData of components) {
19712
20091
  const componentName = componentData?.name;
19713
20092
  if (!componentName) {
@@ -19741,6 +20120,8 @@ function createBuilderImpl(state) {
19741
20120
  warningsCollector,
19742
20121
  resolvedTheme,
19743
20122
  validateEmitted,
20123
+ DETACHED_POSITION,
20124
+ origins,
19744
20125
  depth + 1
19745
20126
  );
19746
20127
  nestedChildren = nested.standard;
@@ -19764,16 +20145,34 @@ function createBuilderImpl(state) {
19764
20145
  if (validateEmitted) {
19765
20146
  validateEmitted(resultComponents, versionLabel);
19766
20147
  }
20148
+ const preservedHere = preserveSet?.has(componentName) === true;
20149
+ const preservedPath = nextPreservedPath();
20150
+ const firstIndex = at.standardBase + standardOut.length;
19767
20151
  const processedResult = await processDocumentComponents(
19768
20152
  resultComponents,
19769
20153
  preserveSet,
19770
20154
  warningsCollector,
19771
20155
  resolvedTheme,
19772
20156
  validateEmitted,
20157
+ {
20158
+ standard: at.standard,
20159
+ standardBase: firstIndex,
20160
+ preserved: preservedHere ? null : at.preserved,
20161
+ preservedBase: at.preservedBase + preservedOut.length
20162
+ },
20163
+ origins,
19773
20164
  depth + 1
19774
20165
  );
20166
+ if (preservedHere && at.standard !== null && preservedPath !== null) {
20167
+ processedResult.standard.forEach((_, index) => {
20168
+ origins.set(`${at.standard}.${firstIndex + index}`, {
20169
+ sourcePath: preservedPath,
20170
+ sourceKind: componentName
20171
+ });
20172
+ });
20173
+ }
19775
20174
  standardOut.push(...processedResult.standard);
19776
- if (preserveSet && preserveSet.has(componentName)) {
20175
+ if (preservedHere) {
19777
20176
  preservedOut.push(componentData);
19778
20177
  } else {
19779
20178
  preservedOut.push(...processedResult.preserved);
@@ -19794,12 +20193,21 @@ function createBuilderImpl(state) {
19794
20193
  }
19795
20194
  } else {
19796
20195
  if ("children" in componentData && Array.isArray(componentData.children)) {
20196
+ const standardPath = nextStandardPath();
20197
+ const preservedPath = nextPreservedPath();
19797
20198
  const processedNested = await processDocumentComponents(
19798
20199
  componentData.children,
19799
20200
  preserveSet,
19800
20201
  warningsCollector,
19801
20202
  resolvedTheme,
19802
20203
  validateEmitted,
20204
+ {
20205
+ standard: joinPath(standardPath, "children"),
20206
+ standardBase: 0,
20207
+ preserved: joinPath(preservedPath, "children"),
20208
+ preservedBase: 0
20209
+ },
20210
+ origins,
19803
20211
  depth + 1
19804
20212
  );
19805
20213
  standardOut.push({
@@ -19963,6 +20371,7 @@ function createBuilderImpl(state) {
19963
20371
  );
19964
20372
  const [modedDoc2] = normalizeDocument(expanded.document);
19965
20373
  return {
20374
+ sourceOrigins: preserveSet ? blockSourceOrigins(modedDoc2, expanded.preserved, preserveSet) : /* @__PURE__ */ new Map(),
19966
20375
  modedRoot,
19967
20376
  modedTheme,
19968
20377
  themeName,
@@ -19978,12 +20387,15 @@ function createBuilderImpl(state) {
19978
20387
  }
19979
20388
  };
19980
20389
  }
20390
+ const sourceOrigins = /* @__PURE__ */ new Map();
19981
20391
  const processed = await processDocumentComponents(
19982
20392
  modedRoot.children || [],
19983
20393
  preserveSet,
19984
20394
  warnings,
19985
20395
  modedTheme,
19986
- validateEmitted
20396
+ validateEmitted,
20397
+ ROOT_POSITION,
20398
+ sourceOrigins
19987
20399
  );
19988
20400
  const processedDocument = {
19989
20401
  ...modedRoot,
@@ -19997,7 +20409,8 @@ function createBuilderImpl(state) {
19997
20409
  processed,
19998
20410
  modedDoc,
19999
20411
  warnings,
20000
- preserveSet
20412
+ preserveSet,
20413
+ sourceOrigins
20001
20414
  };
20002
20415
  }
20003
20416
  async function expandStandardDefinition(document, options) {
@@ -20054,22 +20467,33 @@ function createBuilderImpl(state) {
20054
20467
  const deterministic = options?.deterministic ?? state.deterministic;
20055
20468
  const generatedAt = options?.generatedAt ?? state.generatedAt;
20056
20469
  const renderer = options?.renderer ?? state.renderer ?? prepared.renderer;
20057
- const { buffer } = await generateBufferViaIr(context.document, {
20058
- context,
20059
- prepared,
20060
- ...state.services ? { services: state.services } : {},
20061
- ...state.fonts ? { fonts: state.fonts } : {},
20062
- ...baseDir !== void 0 ? { baseDir } : {},
20063
- ...deterministic !== void 0 ? { deterministic } : {},
20064
- ...generatedAt !== void 0 ? { generatedAt } : {},
20065
- ...renderer !== void 0 ? { renderer } : {},
20470
+ const { buffer, ir, imageOrigins } = await generateBufferViaIr(
20471
+ context.document,
20472
+ {
20473
+ context,
20474
+ prepared,
20475
+ ...state.services ? { services: state.services } : {},
20476
+ ...state.fonts ? { fonts: state.fonts } : {},
20477
+ ...baseDir !== void 0 ? { baseDir } : {},
20478
+ ...deterministic !== void 0 ? { deterministic } : {},
20479
+ ...generatedAt !== void 0 ? { generatedAt } : {},
20480
+ ...renderer !== void 0 ? { renderer } : {},
20481
+ warnings
20482
+ }
20483
+ );
20484
+ const renderManifest = manifestOf(
20485
+ buffer,
20486
+ ir,
20487
+ imageOrigins,
20488
+ /* @__PURE__ */ new Map(),
20066
20489
  warnings
20067
- });
20490
+ );
20068
20491
  return {
20069
20492
  buffer,
20070
20493
  warnings: warnings.length > 0 ? warnings : null,
20071
20494
  standardDefinition: context.document,
20072
- preservedDefinition: void 0
20495
+ preservedDefinition: void 0,
20496
+ ...renderManifest && { renderManifest }
20073
20497
  };
20074
20498
  }
20075
20499
  async function generateBuffer(document, options) {
@@ -20085,13 +20509,14 @@ function createBuilderImpl(state) {
20085
20509
  sourceMap,
20086
20510
  blockPaths,
20087
20511
  warnings,
20088
- preserveSet
20512
+ preserveSet,
20513
+ sourceOrigins
20089
20514
  } = await expandDocument(document, options);
20090
20515
  const baseDir = options?.baseDir ?? state.baseDir;
20091
20516
  const deterministic = options?.deterministic ?? state.deterministic;
20092
20517
  const generatedAt = options?.generatedAt ?? state.generatedAt;
20093
20518
  const renderer = options?.renderer ?? state.renderer ?? modedRoot.renderer;
20094
- const { buffer } = await generateBufferViaIr(modedDoc, {
20519
+ const { buffer, ir, imageOrigins } = await generateBufferViaIr(modedDoc, {
20095
20520
  // The prologue already ran: the theme had to be resolved before custom
20096
20521
  // components expanded, because each one's `render` is handed it.
20097
20522
  context: {
@@ -20113,11 +20538,19 @@ function createBuilderImpl(state) {
20113
20538
  ...modedRoot,
20114
20539
  children: processed.preserved
20115
20540
  } : void 0;
20541
+ const renderManifest = manifestOf(
20542
+ buffer,
20543
+ ir,
20544
+ imageOrigins,
20545
+ sourceOrigins,
20546
+ warnings
20547
+ );
20116
20548
  return {
20117
20549
  buffer,
20118
20550
  warnings: warnings.length > 0 ? warnings : null,
20119
20551
  standardDefinition: modedDoc,
20120
- preservedDefinition
20552
+ preservedDefinition,
20553
+ ...renderManifest && { renderManifest }
20121
20554
  };
20122
20555
  } catch (error) {
20123
20556
  if (state.debug) {
@@ -20127,7 +20560,13 @@ function createBuilderImpl(state) {
20127
20560
  }
20128
20561
  }
20129
20562
  async function generateFile(document, outputPath, options) {
20130
- const { buffer, warnings, standardDefinition, preservedDefinition } = await generateBuffer(document, options);
20563
+ const {
20564
+ buffer,
20565
+ warnings,
20566
+ standardDefinition,
20567
+ preservedDefinition,
20568
+ renderManifest
20569
+ } = await generateBuffer(document, options);
20131
20570
  const fs6 = await import("fs/promises");
20132
20571
  await fs6.writeFile(outputPath, new Uint8Array(buffer));
20133
20572
  let preservedOutputPath;
@@ -20148,7 +20587,8 @@ function createBuilderImpl(state) {
20148
20587
  warnings,
20149
20588
  standardDefinition,
20150
20589
  preservedDefinition,
20151
- preservedOutputPath
20590
+ preservedOutputPath,
20591
+ ...renderManifest && { renderManifest }
20152
20592
  };
20153
20593
  }
20154
20594
  function getComponentNames() {
@@ -20244,6 +20684,7 @@ export {
20244
20684
  DOCX_DEFAULT_QUALITY_PROFILE,
20245
20685
  DOCX_QUALITY_PROFILES,
20246
20686
  DOCX_QUALITY_RULES,
20687
+ RENDER_MANIFEST_UNAVAILABLE,
20247
20688
  ThemeFileError,
20248
20689
  ThemeParseError,
20249
20690
  ThemeValidationError,
@@ -20310,6 +20751,8 @@ export {
20310
20751
  resetChartRequestStats,
20311
20752
  resetVisualPrepassStats,
20312
20753
  resolveDocxQualityProfile,
20754
+ resolveHighchartsOptions,
20755
+ resolveHighchartsRequest,
20313
20756
  runExample,
20314
20757
  themes,
20315
20758
  toAuthoredPointer,