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

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.
@@ -3,9 +3,9 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
3
3
  var __esm = (fn, res) => function __init() {
4
4
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
5
5
  };
6
- var __export = (target, all) => {
6
+ var __export = (target2, all) => {
7
7
  for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
8
+ __defProp(target2, name, { get: all[name], enumerable: true });
9
9
  };
10
10
 
11
11
  // src/themes/defaults.ts
@@ -4329,15 +4329,15 @@ function canonicalizeEmbeddedFontKeys(zip) {
4329
4329
  const targets = /* @__PURE__ */ new Map();
4330
4330
  for (const [relationship] of rels.matchAll(/<Relationship\b[^>]*>/g)) {
4331
4331
  const id = /\bId="([^"]+)"/.exec(relationship)?.[1];
4332
- const target = /\bTarget="([^"]+)"/.exec(relationship)?.[1];
4333
- if (id && target) targets.set(id, target);
4332
+ const target2 = /\bTarget="([^"]+)"/.exec(relationship)?.[1];
4333
+ if (id && target2) targets.set(id, target2);
4334
4334
  }
4335
4335
  const rekey = /* @__PURE__ */ new Map();
4336
4336
  const parts = [];
4337
4337
  for (const { id, key } of embeds) {
4338
- const target = targets.get(id);
4339
- if (!target) continue;
4340
- const name = target.startsWith("/") ? target.slice(1) : posix.normalize(posix.join("word", target));
4338
+ const target2 = targets.get(id);
4339
+ if (!target2) continue;
4340
+ const name = target2.startsWith("/") ? target2.slice(1) : posix.normalize(posix.join("word", target2));
4341
4341
  const part = zip.getEntry(name);
4342
4342
  if (!part) continue;
4343
4343
  const font = xorFontKey(part.getData(), key);
@@ -5358,7 +5358,7 @@ function chromeSlots(set, Part, resources) {
5358
5358
  const part = set[slot];
5359
5359
  if (part) {
5360
5360
  out[slot] = new Part({
5361
- children: emitOutsideBody(() => partChildren(part, resources))
5361
+ children: part.children.length > 0 ? emitOutsideBody(() => partChildren(part, resources)) : [new Paragraph2({ style: Part === Header ? "Header" : "Footer" })]
5362
5362
  });
5363
5363
  }
5364
5364
  }
@@ -6594,15 +6594,16 @@ function section(value, ctx, closesDocument = false) {
6594
6594
  grid: { type: "default", linePitch: 360, charSpace: 0 }
6595
6595
  },
6596
6596
  children: sectionChildren2(value, ctx, closesDocument),
6597
- ...value.headers ? { headers: headerFooterSet(value.headers, ctx) } : {},
6598
- ...value.footers ? { footers: headerFooterSet(value.footers, ctx) } : {}
6597
+ ...value.headers ? { headers: headerFooterSet(value.headers, "Header", ctx) } : {},
6598
+ ...value.footers ? { footers: headerFooterSet(value.footers, "Footer", ctx) } : {}
6599
6599
  };
6600
6600
  }
6601
- function headerFooterSet(set, ctx) {
6601
+ function headerFooterSet(set, style, ctx) {
6602
6602
  const out = {};
6603
6603
  for (const slot of ["default", "first", "even"]) {
6604
6604
  const part = set[slot];
6605
- if (part) out[slot] = part.children.map((child) => block(child, ctx));
6605
+ if (!part) continue;
6606
+ out[slot] = part.children.length > 0 ? part.children.map((child) => block(child, ctx)) : [{ paragraph: { style, children: [] } }];
6606
6607
  }
6607
6608
  return out;
6608
6609
  }
@@ -7712,11 +7713,11 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
7712
7713
  );
7713
7714
  let fontsRejected = false;
7714
7715
  const requestFonts = () => fontsRejected || !options.fonts?.length ? void 0 : options.fonts;
7715
- const rasterizeOne = async (target) => {
7716
+ const rasterizeOne = async (target2) => {
7716
7717
  const fonts = requestFonts();
7717
7718
  const call = (withFonts) => rasterizeVisualSlide(
7718
- target.presentation,
7719
- target.dpi,
7719
+ target2.presentation,
7720
+ target2.dpi,
7720
7721
  void 0,
7721
7722
  serviceConfig,
7722
7723
  options.baseDir,
@@ -7740,8 +7741,8 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
7740
7741
  const rasterizeIndividually = async (chunk) => {
7741
7742
  await Promise.all(
7742
7743
  chunk.map(
7743
- (target) => limit(async () => {
7744
- map.set(target.key, await rasterizeOne(target));
7744
+ (target2) => limit(async () => {
7745
+ map.set(target2.key, await rasterizeOne(target2));
7745
7746
  })
7746
7747
  )
7747
7748
  );
@@ -7750,9 +7751,9 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
7750
7751
  for (const chunk of chunksOf(unique, MAX_RASTERIZE_BATCH_SLIDES)) {
7751
7752
  try {
7752
7753
  const response = await serviceConfig.renderBatch({
7753
- slides: chunk.map((target) => ({
7754
- presentation: target.presentation,
7755
- dpi: target.dpi
7754
+ slides: chunk.map((target2) => ({
7755
+ presentation: target2.presentation,
7756
+ dpi: target2.dpi
7756
7757
  })),
7757
7758
  ...options.baseDir !== void 0 && { baseDir: options.baseDir },
7758
7759
  ...options.fonts?.length ? { fonts: [...options.fonts] } : {}
@@ -7767,8 +7768,8 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
7767
7768
  await rasterizeIndividually(chunk);
7768
7769
  } else {
7769
7770
  const message = toErrorMessage(error);
7770
- for (const target of chunk) {
7771
- map.set(target.key, { ok: false, error: message });
7771
+ for (const target2 of chunk) {
7772
+ map.set(target2.key, { ok: false, error: message });
7772
7773
  }
7773
7774
  }
7774
7775
  }
@@ -7791,9 +7792,9 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
7791
7792
  url: serverUrl,
7792
7793
  path: "/rasterize/batch",
7793
7794
  body: {
7794
- slides: chunk.map((target) => ({
7795
- presentation: target.presentation,
7796
- dpi: target.dpi
7795
+ slides: chunk.map((target2) => ({
7796
+ presentation: target2.presentation,
7797
+ dpi: target2.dpi
7797
7798
  })),
7798
7799
  ...options.baseDir !== void 0 && { baseDir: options.baseDir },
7799
7800
  ...fonts?.length ? { fonts } : {}
@@ -7836,6 +7837,49 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
7836
7837
  return map;
7837
7838
  }
7838
7839
 
7840
+ // src/core/nodeOrigin.ts
7841
+ var NODE_ORIGIN = Symbol("json-to-office.nodeOrigin");
7842
+ function isComponentNode(value) {
7843
+ return typeof value.name === "string" && "props" in value;
7844
+ }
7845
+ function isPlainRecord(value) {
7846
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
7847
+ const proto = Object.getPrototypeOf(value);
7848
+ return proto === Object.prototype || proto === null;
7849
+ }
7850
+ function tagNodeOrigins(root) {
7851
+ const visit = (value, path3) => {
7852
+ if (Array.isArray(value)) {
7853
+ return value.map((item, index) => visit(item, join(path3, index)));
7854
+ }
7855
+ if (!isPlainRecord(value)) return value;
7856
+ const out = {};
7857
+ for (const [key, item] of Object.entries(value)) {
7858
+ out[key] = visit(item, join(path3, key));
7859
+ }
7860
+ if (path3 !== "" && isComponentNode(value)) {
7861
+ out[NODE_ORIGIN] = {
7862
+ standardPath: path3,
7863
+ kind: value.name
7864
+ };
7865
+ }
7866
+ return out;
7867
+ };
7868
+ return visit(root, "");
7869
+ }
7870
+ function join(path3, key) {
7871
+ return path3 === "" ? String(key) : `${path3}.${key}`;
7872
+ }
7873
+ function nodeOrigin(node) {
7874
+ if (!node || typeof node !== "object") return void 0;
7875
+ return node[NODE_ORIGIN];
7876
+ }
7877
+ function withNodeOrigin(original, next) {
7878
+ const origin = nodeOrigin(original);
7879
+ if (origin) next[NODE_ORIGIN] = origin;
7880
+ return next;
7881
+ }
7882
+
7839
7883
  // src/core/componentTransform.ts
7840
7884
  async function transformComponents(doc, replace) {
7841
7885
  return await walk(doc, replace);
@@ -7901,7 +7945,7 @@ function withNodeIdentity(original, replacement) {
7901
7945
  const out = { ...replacement };
7902
7946
  if (original.id !== void 0) out.id = original.id;
7903
7947
  if (original.enabled !== void 0) out.enabled = original.enabled;
7904
- return out;
7948
+ return withNodeOrigin(original, out);
7905
7949
  }
7906
7950
  function containsComponent(root, name) {
7907
7951
  const seen = /* @__PURE__ */ new WeakSet();
@@ -7975,15 +8019,7 @@ async function generateChart(config, servicesConfig, warnings, cache) {
7975
8019
  }
7976
8020
  const serverUrl = effectiveChartServerUrl(config, servicesConfig);
7977
8021
  assertExportServerAllowed(serverUrl, servicesConfig, warnings);
7978
- const requestBody = {
7979
- infile: config.options,
7980
- type: "png",
7981
- b64: true,
7982
- scale: config.scale,
7983
- // Forward resources verbatim only when present so the payload stays
7984
- // byte-identical to before for callers that omit it.
7985
- ...config.resources ? { resources: config.resources } : {}
7986
- };
8022
+ const requestBody = chartRequestBody(config);
7987
8023
  return sendChartRequest({
7988
8024
  cache,
7989
8025
  serverUrl,
@@ -8101,15 +8137,29 @@ function withChartFontFaces(config, theme, faces) {
8101
8137
  theme.fonts.heading.family
8102
8138
  ]);
8103
8139
  }
8104
- async function renderChartToImageProps(props, theme, servicesConfig, chartFonts, warnings, cache) {
8105
- const config = withChartFontFaces(
8140
+ function resolveChartConfig(props, theme, fonts) {
8141
+ return withChartFontFaces(
8106
8142
  withThemeTypography(
8107
8143
  withThemeColors(withThemePresets(props, theme), theme),
8108
8144
  theme
8109
8145
  ),
8110
8146
  theme,
8111
- chartFonts
8147
+ fonts
8112
8148
  );
8149
+ }
8150
+ function chartRequestBody(config) {
8151
+ return {
8152
+ infile: config.options,
8153
+ type: "png",
8154
+ b64: true,
8155
+ scale: config.scale,
8156
+ // Forward resources verbatim only when present so the payload stays
8157
+ // byte-identical to before for callers that omit it.
8158
+ ...config.resources ? { resources: config.resources } : {}
8159
+ };
8160
+ }
8161
+ async function renderChartToImageProps(props, theme, servicesConfig, chartFonts, warnings, cache) {
8162
+ const config = resolveChartConfig(props, theme, chartFonts);
8113
8163
  const chart = await generateChart(config, servicesConfig, warnings, cache);
8114
8164
  const hasConfigDimensions = config.width !== void 0 || config.height !== void 0;
8115
8165
  return {
@@ -10826,12 +10876,12 @@ function parseLinks(normalized, options) {
10826
10876
  continue;
10827
10877
  }
10828
10878
  const [, linkText] = match;
10829
- const target = decodeEscapes(match[2]);
10879
+ const target2 = decodeEscapes(match[2]);
10830
10880
  out.push({
10831
10881
  kind: "hyperlink",
10832
10882
  // A `#anchor` target names a bookmark in this document and needs no
10833
10883
  // relationship; anything else leaves the document.
10834
- target: target.startsWith("#") ? { kind: "bookmark", anchor: target.slice(1) } : { kind: "external", url: target },
10884
+ target: target2.startsWith("#") ? { kind: "bookmark", anchor: target2.slice(1) } : { kind: "external", url: target2 },
10835
10885
  children: parseDecorated(linkText, options)
10836
10886
  });
10837
10887
  }
@@ -11087,6 +11137,7 @@ function compileDocument(structure, layout2, warnings = [], images = /* @__PURE_
11087
11137
  numberedItems: outline.numberedItems,
11088
11138
  tocEntries: outline.entries,
11089
11139
  images,
11140
+ imageOrigins: /* @__PURE__ */ new WeakMap(),
11090
11141
  generatedAt: structure.metadata.date
11091
11142
  };
11092
11143
  ctx.features.require("paragraphs", "sections");
@@ -11140,9 +11191,19 @@ function compileDocument(structure, layout2, warnings = [], images = /* @__PURE_
11140
11191
  ir,
11141
11192
  required: ctx.features.list(),
11142
11193
  warnings: ctx.warnings,
11143
- unsupported: ctx.unsupported
11194
+ unsupported: ctx.unsupported,
11195
+ imageOrigins: ctx.imageOrigins
11144
11196
  };
11145
11197
  }
11198
+ function recordImageOrigin(ctx, component, images) {
11199
+ const origin = nodeOrigin(component);
11200
+ if (!origin) return;
11201
+ for (const image of images) {
11202
+ if (image.kind === "image" || image.kind === "picture") {
11203
+ ctx.imageOrigins.set(image, origin);
11204
+ }
11205
+ }
11206
+ }
11146
11207
  var AFTER_TABLE_TWIPS = 120;
11147
11208
  var BEFORE_TABLE_TWIPS = 240;
11148
11209
  var BODY_STYLE_IDS = /* @__PURE__ */ new Set([void 0, "Normal"]);
@@ -11470,6 +11531,7 @@ function compileChromeImage(component, scope) {
11470
11531
  heightEmu: pixelsToEmu(size.height),
11471
11532
  ...props.floating ? { floating: compileFloating(props.floating, ctx, path3) } : {}
11472
11533
  };
11534
+ recordImageOrigin(ctx, component, [image]);
11473
11535
  return [
11474
11536
  {
11475
11537
  kind: "paragraph",
@@ -12969,6 +13031,7 @@ function compileVisual(component, scope) {
12969
13031
  nativeVisualDeps(ctx, path3)
12970
13032
  );
12971
13033
  if (!group) return [];
13034
+ recordImageOrigin(ctx, component, group.children);
12972
13035
  const size = visualPlacementPixels(props, group.canvas, {
12973
13036
  widthPx: Math.round(twipsToPixels(scope.measureTwips)),
12974
13037
  heightPx: Math.round(twipsToPixels(getAvailableHeightTwips(ctx.theme)))
@@ -13095,6 +13158,7 @@ function compileImage2(component, scope) {
13095
13158
  ...typeof props.alt === "string" && props.alt ? { altText: props.alt } : {},
13096
13159
  ...props.floating ? { floating: compileFloating(props.floating, ctx, path3) } : {}
13097
13160
  };
13161
+ recordImageOrigin(ctx, component, [image]);
13098
13162
  ctx.features.require("images", path3);
13099
13163
  if (props.floating) ctx.features.require("floating-images", path3);
13100
13164
  const spacing = {};
@@ -13859,6 +13923,7 @@ function cellVisual(component, scope) {
13859
13923
  nativeVisualDeps(ctx, path3)
13860
13924
  );
13861
13925
  if (!group) return [];
13926
+ recordImageOrigin(ctx, component, group.children);
13862
13927
  const size = visualPlacementPixels(props, group.canvas, {
13863
13928
  widthPx: CELL_DRAWING_REFERENCE.width,
13864
13929
  heightPx: CELL_DRAWING_REFERENCE.height
@@ -13904,14 +13969,14 @@ function cellImage(component, base, ctx) {
13904
13969
  const mediaType = detectImageType(source, loaded.contentType);
13905
13970
  if (mediaType === "svg") ctx.features.require("svg-images", "table");
13906
13971
  ctx.features.require("images", "table");
13907
- return [
13908
- {
13909
- kind: "image",
13910
- resourceId: declareResource(loaded, mediaType, ctx),
13911
- widthEmu: pixelsToEmu(size.width),
13912
- heightEmu: pixelsToEmu(size.height)
13913
- }
13914
- ];
13972
+ const image = {
13973
+ kind: "image",
13974
+ resourceId: declareResource(loaded, mediaType, ctx),
13975
+ widthEmu: pixelsToEmu(size.width),
13976
+ heightEmu: pixelsToEmu(size.height)
13977
+ };
13978
+ recordImageOrigin(ctx, component, [image]);
13979
+ return [image];
13915
13980
  }
13916
13981
  function placeholderFormatting(base) {
13917
13982
  return {
@@ -16466,7 +16531,7 @@ async function compileDocumentScoped(document, options, warnings) {
16466
16531
  const embeddedFonts = embedding ? selectEmbeddedFonts(resolvedFonts, warnings) : [];
16467
16532
  const visualFonts = hasVisual ? toRasterizeFontFaces(resolvedFonts, warnings) : [];
16468
16533
  const chartFonts = hasHighcharts ? toChartFontFaces(resolvedFonts) : [];
16469
- const desugared = await desugarExternals(context.document, {
16534
+ const desugared = await desugarExternals(tagNodeOrigins(context.document), {
16470
16535
  theme: prepared.model.document.theme,
16471
16536
  ...options.services ? { services: options.services } : {},
16472
16537
  ...options.baseDir !== void 0 ? { baseDir: options.baseDir } : {},
@@ -16504,6 +16569,7 @@ async function compileDocumentScoped(document, options, warnings) {
16504
16569
  warnings: compiled.warnings,
16505
16570
  required: compiled.required,
16506
16571
  unsupported: compiled.unsupported,
16572
+ imageOrigins: compiled.imageOrigins,
16507
16573
  embeddedFonts
16508
16574
  };
16509
16575
  }
@@ -16531,13 +16597,291 @@ async function renderScoped(document, options, warnings) {
16531
16597
  ...compiled.embeddedFonts.length > 0 ? { embeddedFonts: compiled.embeddedFonts } : {},
16532
16598
  warnings: compiled.warnings
16533
16599
  });
16534
- return { buffer: Buffer.from(bytes), warnings: compiled.warnings };
16600
+ return {
16601
+ buffer: Buffer.from(bytes),
16602
+ warnings: compiled.warnings,
16603
+ ir: compiled.ir,
16604
+ imageOrigins: compiled.imageOrigins
16605
+ };
16535
16606
  }
16536
16607
  function toDate(value) {
16537
16608
  return value instanceof Date ? value : new Date(value);
16538
16609
  }
16539
16610
 
16611
+ // src/core/renderManifest.ts
16612
+ init_units();
16613
+ import AdmZip6 from "adm-zip";
16614
+ import { posix as posix2 } from "path";
16615
+ var HEADER_FOOTER_TYPES = ["default", "first", "even"];
16616
+ function buildRenderManifest(buffer, ir, imageOrigins, sourceOrigins = /* @__PURE__ */ new Map()) {
16617
+ try {
16618
+ return {
16619
+ ok: true,
16620
+ manifest: collect(buffer, ir, imageOrigins, sourceOrigins)
16621
+ };
16622
+ } catch (error) {
16623
+ return {
16624
+ ok: false,
16625
+ reason: error instanceof Error ? error.message : String(error)
16626
+ };
16627
+ }
16628
+ }
16629
+ function collect(buffer, ir, imageOrigins, sourceOrigins) {
16630
+ const zip = new AdmZip6(buffer);
16631
+ const read = (entry) => zip.getEntry(entry)?.getData().toString("utf8");
16632
+ const media = /* @__PURE__ */ new Map();
16633
+ const mediaHash = (path3) => {
16634
+ let hash = media.get(path3);
16635
+ if (hash === void 0) {
16636
+ const entry = zip.getEntry(path3);
16637
+ if (!entry) throw new Error(`the package has no ${path3}`);
16638
+ hash = sha256Hex(new Uint8Array(entry.getData()));
16639
+ media.set(path3, hash);
16640
+ }
16641
+ return hash;
16642
+ };
16643
+ const resources = new Map(ir.resources.map((r) => [r.id, r]));
16644
+ const manifest = [];
16645
+ const pair = (part, partPath, xml, images) => {
16646
+ const rels = relationships(read(relsPathOf(partPath)), partPath);
16647
+ const blips = readBlips(xml);
16648
+ if (blips.length !== images.length) {
16649
+ throw new Error(
16650
+ `${partPath} embeds ${blips.length} image(s) where the IR placed ${images.length}`
16651
+ );
16652
+ }
16653
+ blips.forEach((blip, index) => {
16654
+ const image = images[index];
16655
+ const mediaPath = target(rels, blip.embed, partPath);
16656
+ const sha256 = mediaHash(mediaPath);
16657
+ const resource = resources.get(image.resourceId);
16658
+ if (!resource || !matchesResource(resource, blip, sha256, rels, partPath, mediaHash)) {
16659
+ throw new Error(
16660
+ `image ${index + 1} of ${partPath} (${mediaPath}) does not hold the bytes of IR resource ${image.resourceId}`
16661
+ );
16662
+ }
16663
+ const origin = imageOrigins.get(image);
16664
+ if (!origin) {
16665
+ throw new Error(
16666
+ `image ${index + 1} of ${partPath} has no standard-definition origin`
16667
+ );
16668
+ }
16669
+ const source = sourceOriginOf(origin.standardPath, sourceOrigins);
16670
+ manifest.push({
16671
+ part,
16672
+ partPath,
16673
+ mediaPath,
16674
+ sha256,
16675
+ standardPath: origin.standardPath,
16676
+ kind: origin.kind,
16677
+ ...source && {
16678
+ sourcePath: source.sourcePath,
16679
+ sourceKind: source.sourceKind
16680
+ }
16681
+ });
16682
+ });
16683
+ };
16684
+ const documentPath = "word/document.xml";
16685
+ const documentXml = read(documentPath);
16686
+ if (documentXml === void 0)
16687
+ throw new Error(`the package has no ${documentPath}`);
16688
+ pair(
16689
+ "body",
16690
+ documentPath,
16691
+ documentXml,
16692
+ ir.sections.flatMap((section2) => blockImages(section2.children))
16693
+ );
16694
+ const sectPrs = sectionProperties(documentXml);
16695
+ if (sectPrs.length !== ir.sections.length) {
16696
+ throw new Error(
16697
+ `${documentPath} has ${sectPrs.length} section(s) where the IR has ${ir.sections.length}`
16698
+ );
16699
+ }
16700
+ const documentRels = relationships(
16701
+ read(relsPathOf(documentPath)),
16702
+ documentPath
16703
+ );
16704
+ const seen = /* @__PURE__ */ new Set();
16705
+ ir.sections.forEach((section2, index) => {
16706
+ const references = chromeReferences(sectPrs[index]);
16707
+ for (const part of ["header", "footer"]) {
16708
+ const set = part === "header" ? section2.headers : section2.footers;
16709
+ for (const type of HEADER_FOOTER_TYPES) {
16710
+ const id = references.get(`${part}:${type}`);
16711
+ if (id === void 0) continue;
16712
+ const partPath = target(documentRels, id, documentPath);
16713
+ if (seen.has(partPath)) continue;
16714
+ seen.add(partPath);
16715
+ const xml = read(partPath);
16716
+ if (xml === void 0)
16717
+ throw new Error(`the package has no ${partPath}`);
16718
+ pair(part, partPath, xml, blockImages(set?.[type]?.children ?? []));
16719
+ }
16720
+ }
16721
+ });
16722
+ return manifest;
16723
+ }
16724
+ function sourceOriginOf(standardPath, sourceOrigins) {
16725
+ if (sourceOrigins.size === 0) return void 0;
16726
+ const segments = standardPath.split(".");
16727
+ for (let n = segments.length; n > 0; n--) {
16728
+ const hit = sourceOrigins.get(segments.slice(0, n).join("."));
16729
+ if (hit) return hit;
16730
+ }
16731
+ return void 0;
16732
+ }
16733
+ function matchesResource(resource, blip, sha256, rels, partPath, mediaHash) {
16734
+ if (sha256 === resource.sha256) return true;
16735
+ if (resource.mediaType !== "svg" || blip.svgEmbed === void 0) return false;
16736
+ return mediaHash(target(rels, blip.svgEmbed, partPath)) === resource.sha256;
16737
+ }
16738
+ function blockImages(blocks) {
16739
+ const out = [];
16740
+ const visitBlocks = (items) => {
16741
+ for (const block2 of items) {
16742
+ if (block2.kind === "paragraph") visitParagraph(block2);
16743
+ else if (block2.kind === "table") {
16744
+ for (const row of block2.rows) {
16745
+ for (const cell of row.cells) visitBlocks(cell.children);
16746
+ }
16747
+ }
16748
+ }
16749
+ };
16750
+ const visitParagraph = (paragraph2) => visitInlines(paragraph2.children);
16751
+ const visitInlines = (inlines) => {
16752
+ for (const inline of inlines) {
16753
+ switch (inline.kind) {
16754
+ case "image":
16755
+ out.push(inline);
16756
+ break;
16757
+ case "drawingGroup":
16758
+ for (const child of inline.children) {
16759
+ if (child.kind === "picture") out.push(child);
16760
+ }
16761
+ break;
16762
+ case "shape":
16763
+ inline.children.forEach(visitParagraph);
16764
+ break;
16765
+ case "hyperlink":
16766
+ case "revision":
16767
+ visitInlines(inline.children);
16768
+ break;
16769
+ default:
16770
+ break;
16771
+ }
16772
+ }
16773
+ };
16774
+ visitBlocks(blocks);
16775
+ return out;
16776
+ }
16777
+ function readBlips(xml) {
16778
+ const body = xml.replace(/<mc:Fallback\b[\s\S]*?<\/mc:Fallback>/g, "");
16779
+ const blips = [];
16780
+ const pattern = /<a:blip\b([^>]*?)(?:\/>|>([\s\S]*?)<\/a:blip>)/g;
16781
+ for (const match of body.matchAll(pattern)) {
16782
+ const embed = /\br:embed="([^"]+)"/.exec(match[1])?.[1];
16783
+ if (embed === void 0) continue;
16784
+ const svgEmbed = match[2] ? /<asvg:svgBlip\b[^>]*\br:embed="([^"]+)"/.exec(match[2])?.[1] : void 0;
16785
+ blips.push(svgEmbed === void 0 ? { embed } : { embed, svgEmbed });
16786
+ }
16787
+ return blips;
16788
+ }
16789
+ function sectionProperties(xml) {
16790
+ return [...xml.matchAll(/<w:sectPr\b(?:[^>]*\/>|[\s\S]*?<\/w:sectPr>)/g)].map(
16791
+ (m) => m[0]
16792
+ );
16793
+ }
16794
+ function chromeReferences(sectPr) {
16795
+ const out = /* @__PURE__ */ new Map();
16796
+ for (const match of sectPr.matchAll(
16797
+ /<w:(header|footer)Reference\b([^>]*)\/?>/g
16798
+ )) {
16799
+ const type = attribute(match[2], "w:type") ?? "default";
16800
+ const id = attribute(match[2], "r:id");
16801
+ if (id !== void 0) out.set(`${match[1]}:${type}`, id);
16802
+ }
16803
+ return out;
16804
+ }
16805
+ function relsPathOf(partPath) {
16806
+ return posix2.join(
16807
+ posix2.dirname(partPath),
16808
+ "_rels",
16809
+ `${posix2.basename(partPath)}.rels`
16810
+ );
16811
+ }
16812
+ function relationships(xml, partPath) {
16813
+ const out = /* @__PURE__ */ new Map();
16814
+ if (xml === void 0) return out;
16815
+ for (const match of xml.matchAll(/<Relationship\b([^>]*)\/?>/g)) {
16816
+ const id = attribute(match[1], "Id");
16817
+ const target2 = attribute(match[1], "Target");
16818
+ if (id !== void 0 && target2 !== void 0) out.set(id, target2);
16819
+ }
16820
+ if (out.size === 0 && /<Relationship\b/.test(xml)) {
16821
+ throw new Error(`the relationships of ${partPath} could not be read`);
16822
+ }
16823
+ return out;
16824
+ }
16825
+ function target(rels, id, partPath) {
16826
+ const raw = rels.get(id);
16827
+ if (raw === void 0) {
16828
+ throw new Error(`${partPath} references an unknown relationship ${id}`);
16829
+ }
16830
+ return raw.startsWith("/") ? raw.slice(1) : posix2.normalize(posix2.join(posix2.dirname(partPath), raw));
16831
+ }
16832
+ function attribute(attributes, name) {
16833
+ const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
16834
+ return new RegExp(`(?:^|\\s)${escaped}="([^"]*)"`).exec(attributes)?.[1];
16835
+ }
16836
+
16540
16837
  // src/plugin/createDocumentGenerator.ts
16838
+ var RENDER_MANIFEST_UNAVAILABLE = "W_DOCX_RENDER_MANIFEST_UNAVAILABLE";
16839
+ var ROOT_POSITION = {
16840
+ standard: "children",
16841
+ standardBase: 0,
16842
+ preserved: "children",
16843
+ preservedBase: 0
16844
+ };
16845
+ var DETACHED_POSITION = {
16846
+ standard: null,
16847
+ standardBase: 0,
16848
+ preserved: null,
16849
+ preservedBase: 0
16850
+ };
16851
+ function joinPath(path3, key) {
16852
+ return path3 === null ? null : `${path3}.${key}`;
16853
+ }
16854
+ function blockSourceOrigins(standard, preserved, preserveSet) {
16855
+ const origins = /* @__PURE__ */ new Map();
16856
+ const visit = (std, kept, path3) => {
16857
+ if (!std || !kept || typeof std !== "object" || typeof kept !== "object")
16858
+ return;
16859
+ const keptNode = kept;
16860
+ const stdNode = std;
16861
+ if (path3 !== "" && typeof keptNode.name === "string" && preserveSet.has(keptNode.name) && stdNode.name === "group") {
16862
+ origins.set(path3, { sourcePath: path3, sourceKind: keptNode.name });
16863
+ return;
16864
+ }
16865
+ for (const [key, value] of Object.entries(keptNode)) {
16866
+ if (key in stdNode) {
16867
+ visit(stdNode[key], value, path3 === "" ? key : `${path3}.${key}`);
16868
+ }
16869
+ }
16870
+ };
16871
+ visit(standard, preserved, "");
16872
+ return origins;
16873
+ }
16874
+ function manifestOf(buffer, ir, imageOrigins, sourceOrigins, warnings) {
16875
+ const built = buildRenderManifest(buffer, ir, imageOrigins, sourceOrigins);
16876
+ if (built.ok) return built.manifest;
16877
+ warnings.push({
16878
+ component: "docx",
16879
+ severity: "warning",
16880
+ message: `No render manifest: ${built.reason}.`,
16881
+ context: { code: RENDER_MANIFEST_UNAVAILABLE, reason: built.reason }
16882
+ });
16883
+ return void 0;
16884
+ }
16541
16885
  function createBuilderImpl(state) {
16542
16886
  const componentMap = new Map(state.components.map((c) => [c.name, c]));
16543
16887
  function resolveDocumentTheme(themeName, warnings, authored) {
@@ -16566,7 +16910,7 @@ function createBuilderImpl(state) {
16566
16910
  warnings
16567
16911
  });
16568
16912
  }
16569
- async function processDocumentComponents(components, preserveSet, warningsCollector, resolvedTheme, validateEmitted, depth = 0) {
16913
+ async function processDocumentComponents(components, preserveSet, warningsCollector, resolvedTheme, validateEmitted, at, origins, depth = 0) {
16570
16914
  if (depth > 20) {
16571
16915
  throw new Error(
16572
16916
  "Maximum component nesting depth exceeded (20). Check for circular component references."
@@ -16574,6 +16918,8 @@ function createBuilderImpl(state) {
16574
16918
  }
16575
16919
  const standardOut = [];
16576
16920
  const preservedOut = [];
16921
+ const nextStandardPath = () => joinPath(at.standard, at.standardBase + standardOut.length);
16922
+ const nextPreservedPath = () => joinPath(at.preserved, at.preservedBase + preservedOut.length);
16577
16923
  for (const componentData of components) {
16578
16924
  const componentName = componentData?.name;
16579
16925
  if (!componentName) {
@@ -16607,6 +16953,8 @@ function createBuilderImpl(state) {
16607
16953
  warningsCollector,
16608
16954
  resolvedTheme,
16609
16955
  validateEmitted,
16956
+ DETACHED_POSITION,
16957
+ origins,
16610
16958
  depth + 1
16611
16959
  );
16612
16960
  nestedChildren = nested.standard;
@@ -16630,16 +16978,34 @@ function createBuilderImpl(state) {
16630
16978
  if (validateEmitted) {
16631
16979
  validateEmitted(resultComponents, versionLabel);
16632
16980
  }
16981
+ const preservedHere = preserveSet?.has(componentName) === true;
16982
+ const preservedPath = nextPreservedPath();
16983
+ const firstIndex = at.standardBase + standardOut.length;
16633
16984
  const processedResult = await processDocumentComponents(
16634
16985
  resultComponents,
16635
16986
  preserveSet,
16636
16987
  warningsCollector,
16637
16988
  resolvedTheme,
16638
16989
  validateEmitted,
16990
+ {
16991
+ standard: at.standard,
16992
+ standardBase: firstIndex,
16993
+ preserved: preservedHere ? null : at.preserved,
16994
+ preservedBase: at.preservedBase + preservedOut.length
16995
+ },
16996
+ origins,
16639
16997
  depth + 1
16640
16998
  );
16999
+ if (preservedHere && at.standard !== null && preservedPath !== null) {
17000
+ processedResult.standard.forEach((_, index) => {
17001
+ origins.set(`${at.standard}.${firstIndex + index}`, {
17002
+ sourcePath: preservedPath,
17003
+ sourceKind: componentName
17004
+ });
17005
+ });
17006
+ }
16641
17007
  standardOut.push(...processedResult.standard);
16642
- if (preserveSet && preserveSet.has(componentName)) {
17008
+ if (preservedHere) {
16643
17009
  preservedOut.push(componentData);
16644
17010
  } else {
16645
17011
  preservedOut.push(...processedResult.preserved);
@@ -16660,12 +17026,21 @@ function createBuilderImpl(state) {
16660
17026
  }
16661
17027
  } else {
16662
17028
  if ("children" in componentData && Array.isArray(componentData.children)) {
17029
+ const standardPath = nextStandardPath();
17030
+ const preservedPath = nextPreservedPath();
16663
17031
  const processedNested = await processDocumentComponents(
16664
17032
  componentData.children,
16665
17033
  preserveSet,
16666
17034
  warningsCollector,
16667
17035
  resolvedTheme,
16668
17036
  validateEmitted,
17037
+ {
17038
+ standard: joinPath(standardPath, "children"),
17039
+ standardBase: 0,
17040
+ preserved: joinPath(preservedPath, "children"),
17041
+ preservedBase: 0
17042
+ },
17043
+ origins,
16669
17044
  depth + 1
16670
17045
  );
16671
17046
  standardOut.push({
@@ -16829,6 +17204,7 @@ function createBuilderImpl(state) {
16829
17204
  );
16830
17205
  const [modedDoc2] = normalizeDocument(expanded.document);
16831
17206
  return {
17207
+ sourceOrigins: preserveSet ? blockSourceOrigins(modedDoc2, expanded.preserved, preserveSet) : /* @__PURE__ */ new Map(),
16832
17208
  modedRoot,
16833
17209
  modedTheme,
16834
17210
  themeName,
@@ -16844,12 +17220,15 @@ function createBuilderImpl(state) {
16844
17220
  }
16845
17221
  };
16846
17222
  }
17223
+ const sourceOrigins = /* @__PURE__ */ new Map();
16847
17224
  const processed = await processDocumentComponents(
16848
17225
  modedRoot.children || [],
16849
17226
  preserveSet,
16850
17227
  warnings,
16851
17228
  modedTheme,
16852
- validateEmitted
17229
+ validateEmitted,
17230
+ ROOT_POSITION,
17231
+ sourceOrigins
16853
17232
  );
16854
17233
  const processedDocument = {
16855
17234
  ...modedRoot,
@@ -16863,7 +17242,8 @@ function createBuilderImpl(state) {
16863
17242
  processed,
16864
17243
  modedDoc,
16865
17244
  warnings,
16866
- preserveSet
17245
+ preserveSet,
17246
+ sourceOrigins
16867
17247
  };
16868
17248
  }
16869
17249
  async function expandStandardDefinition(document, options) {
@@ -16920,22 +17300,33 @@ function createBuilderImpl(state) {
16920
17300
  const deterministic = options?.deterministic ?? state.deterministic;
16921
17301
  const generatedAt = options?.generatedAt ?? state.generatedAt;
16922
17302
  const renderer = options?.renderer ?? state.renderer ?? prepared.renderer;
16923
- const { buffer } = await generateBufferViaIr(context.document, {
16924
- context,
16925
- prepared,
16926
- ...state.services ? { services: state.services } : {},
16927
- ...state.fonts ? { fonts: state.fonts } : {},
16928
- ...baseDir !== void 0 ? { baseDir } : {},
16929
- ...deterministic !== void 0 ? { deterministic } : {},
16930
- ...generatedAt !== void 0 ? { generatedAt } : {},
16931
- ...renderer !== void 0 ? { renderer } : {},
17303
+ const { buffer, ir, imageOrigins } = await generateBufferViaIr(
17304
+ context.document,
17305
+ {
17306
+ context,
17307
+ prepared,
17308
+ ...state.services ? { services: state.services } : {},
17309
+ ...state.fonts ? { fonts: state.fonts } : {},
17310
+ ...baseDir !== void 0 ? { baseDir } : {},
17311
+ ...deterministic !== void 0 ? { deterministic } : {},
17312
+ ...generatedAt !== void 0 ? { generatedAt } : {},
17313
+ ...renderer !== void 0 ? { renderer } : {},
17314
+ warnings
17315
+ }
17316
+ );
17317
+ const renderManifest = manifestOf(
17318
+ buffer,
17319
+ ir,
17320
+ imageOrigins,
17321
+ /* @__PURE__ */ new Map(),
16932
17322
  warnings
16933
- });
17323
+ );
16934
17324
  return {
16935
17325
  buffer,
16936
17326
  warnings: warnings.length > 0 ? warnings : null,
16937
17327
  standardDefinition: context.document,
16938
- preservedDefinition: void 0
17328
+ preservedDefinition: void 0,
17329
+ ...renderManifest && { renderManifest }
16939
17330
  };
16940
17331
  }
16941
17332
  async function generateBuffer(document, options) {
@@ -16951,13 +17342,14 @@ function createBuilderImpl(state) {
16951
17342
  sourceMap,
16952
17343
  blockPaths,
16953
17344
  warnings,
16954
- preserveSet
17345
+ preserveSet,
17346
+ sourceOrigins
16955
17347
  } = await expandDocument(document, options);
16956
17348
  const baseDir = options?.baseDir ?? state.baseDir;
16957
17349
  const deterministic = options?.deterministic ?? state.deterministic;
16958
17350
  const generatedAt = options?.generatedAt ?? state.generatedAt;
16959
17351
  const renderer = options?.renderer ?? state.renderer ?? modedRoot.renderer;
16960
- const { buffer } = await generateBufferViaIr(modedDoc, {
17352
+ const { buffer, ir, imageOrigins } = await generateBufferViaIr(modedDoc, {
16961
17353
  // The prologue already ran: the theme had to be resolved before custom
16962
17354
  // components expanded, because each one's `render` is handed it.
16963
17355
  context: {
@@ -16979,11 +17371,19 @@ function createBuilderImpl(state) {
16979
17371
  ...modedRoot,
16980
17372
  children: processed.preserved
16981
17373
  } : void 0;
17374
+ const renderManifest = manifestOf(
17375
+ buffer,
17376
+ ir,
17377
+ imageOrigins,
17378
+ sourceOrigins,
17379
+ warnings
17380
+ );
16982
17381
  return {
16983
17382
  buffer,
16984
17383
  warnings: warnings.length > 0 ? warnings : null,
16985
17384
  standardDefinition: modedDoc,
16986
- preservedDefinition
17385
+ preservedDefinition,
17386
+ ...renderManifest && { renderManifest }
16987
17387
  };
16988
17388
  } catch (error) {
16989
17389
  if (state.debug) {
@@ -16993,7 +17393,13 @@ function createBuilderImpl(state) {
16993
17393
  }
16994
17394
  }
16995
17395
  async function generateFile(document, outputPath, options) {
16996
- const { buffer, warnings, standardDefinition, preservedDefinition } = await generateBuffer(document, options);
17396
+ const {
17397
+ buffer,
17398
+ warnings,
17399
+ standardDefinition,
17400
+ preservedDefinition,
17401
+ renderManifest
17402
+ } = await generateBuffer(document, options);
16997
17403
  const fs4 = await import("fs/promises");
16998
17404
  await fs4.writeFile(outputPath, new Uint8Array(buffer));
16999
17405
  let preservedOutputPath;
@@ -17014,7 +17420,8 @@ function createBuilderImpl(state) {
17014
17420
  warnings,
17015
17421
  standardDefinition,
17016
17422
  preservedDefinition,
17017
- preservedOutputPath
17423
+ preservedOutputPath,
17424
+ ...renderManifest && { renderManifest }
17018
17425
  };
17019
17426
  }
17020
17427
  function getComponentNames() {