@shbernal/ts-pptx 3.3.0 → 3.5.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 (66) hide show
  1. package/dist/{autopage-D1sqK6j7.js → autopage-BYlTzX-l.js} +8 -5
  2. package/dist/autopage-BYlTzX-l.js.map +1 -0
  3. package/dist/browser.d.ts +5 -5
  4. package/dist/browser.js +11 -11
  5. package/dist/browser.js.map +1 -1
  6. package/dist/{diagnostics-B2yWpcjB.d.ts → diagnostics-BDuR8UkG.d.ts} +39 -7
  7. package/dist/diagnostics-BDuR8UkG.d.ts.map +1 -0
  8. package/dist/{diagnostics-H1QzgRSw.js → diagnostics-CPVADSL1.js} +29 -3
  9. package/dist/{diagnostics-H1QzgRSw.js.map → diagnostics-CPVADSL1.js.map} +1 -1
  10. package/dist/{errors-fB1KDJKQ.d.ts → errors-CgnueTYL.d.ts} +3 -3
  11. package/dist/{errors-fB1KDJKQ.d.ts.map → errors-CgnueTYL.d.ts.map} +1 -1
  12. package/dist/{fit-CYJ1jkQI.js → fit-TjpNbMru.js} +3 -3
  13. package/dist/{fit-CYJ1jkQI.js.map → fit-TjpNbMru.js.map} +1 -1
  14. package/dist/{html-dom-CzewEdE1.js → html-dom-yUSdCExA.js} +5 -5
  15. package/dist/html-dom-yUSdCExA.js.map +1 -0
  16. package/dist/html.d.ts +3 -3
  17. package/dist/html.js +1 -1
  18. package/dist/index.d.ts +5 -5
  19. package/dist/index.js +16 -33
  20. package/dist/index.js.map +1 -1
  21. package/dist/inspect.d.ts +28 -4
  22. package/dist/inspect.d.ts.map +1 -1
  23. package/dist/inspect.js +43 -10
  24. package/dist/inspect.js.map +1 -1
  25. package/dist/math.d.ts +1 -1
  26. package/dist/measure.d.ts +2 -2
  27. package/dist/measure.js +1 -1
  28. package/dist/{st-enums-bVnezkMJ.js → namespaces-CcKuzeuE.js} +291 -200
  29. package/dist/namespaces-CcKuzeuE.js.map +1 -0
  30. package/dist/node.d.ts +5 -5
  31. package/dist/node.js +7 -19
  32. package/dist/node.js.map +1 -1
  33. package/dist/{notes-SCvpJz0l.js → notes-DNqAggXx.js} +221 -140
  34. package/dist/notes-DNqAggXx.js.map +1 -0
  35. package/dist/{pres-Cb-1xDne.d.ts → pres-Dybf7ZUl.d.ts} +2 -2
  36. package/dist/{pres-Cb-1xDne.d.ts.map → pres-Dybf7ZUl.d.ts.map} +1 -1
  37. package/dist/{presentation-DeKTJGHf.js → presentation-VfJ_FT7E.js} +306 -234
  38. package/dist/presentation-VfJ_FT7E.js.map +1 -0
  39. package/dist/{presentation-types-B50aOUFI.d.ts → presentation-types-CpkTx9Xa.d.ts} +352 -16
  40. package/dist/presentation-types-CpkTx9Xa.d.ts.map +1 -0
  41. package/dist/read.d.ts +4 -4
  42. package/dist/read.js +3 -3
  43. package/dist/script.d.ts +2 -2
  44. package/dist/script.d.ts.map +1 -1
  45. package/dist/script.js +128 -63
  46. package/dist/script.js.map +1 -1
  47. package/dist/{shapes-BXVgsk0F.js → shapes-Kt51vry6.js} +717 -54
  48. package/dist/shapes-Kt51vry6.js.map +1 -0
  49. package/dist/{slide-DWw9UoI6.d.ts → slide-B_aInw3N.d.ts} +208 -180
  50. package/dist/slide-B_aInw3N.d.ts.map +1 -0
  51. package/dist/{text-uM-zGton.js → text-D04NUMvA.js} +3563 -3437
  52. package/dist/text-D04NUMvA.js.map +1 -0
  53. package/dist/{units-internal-CGf4VrXy.js → units-internal-DNvK2I6o.js} +54 -34
  54. package/dist/{units-internal-CGf4VrXy.js.map → units-internal-DNvK2I6o.js.map} +1 -1
  55. package/dist/zip.d.ts +1 -1
  56. package/package.json +4 -4
  57. package/dist/autopage-D1sqK6j7.js.map +0 -1
  58. package/dist/diagnostics-B2yWpcjB.d.ts.map +0 -1
  59. package/dist/html-dom-CzewEdE1.js.map +0 -1
  60. package/dist/notes-SCvpJz0l.js.map +0 -1
  61. package/dist/presentation-DeKTJGHf.js.map +0 -1
  62. package/dist/presentation-types-B50aOUFI.d.ts.map +0 -1
  63. package/dist/shapes-BXVgsk0F.js.map +0 -1
  64. package/dist/slide-DWw9UoI6.d.ts.map +0 -1
  65. package/dist/st-enums-bVnezkMJ.js.map +0 -1
  66. package/dist/text-uM-zGton.js.map +0 -1
package/dist/script.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { a as TsPptxError, i as PackageReadError, n as InvalidOptionError, o as UnsupportedFeatureError, r as MediaError, t as InternalError } from "./errors-Bvln0H-7.js";
2
- import { a as isConnector, c as isPicture, i as isAutoShape, o as isGraphicFrame, s as isGroupShape } from "./shapes-BXVgsk0F.js";
2
+ import { t as OOXML_NS } from "./namespaces-CcKuzeuE.js";
3
+ import { a as isConnector, c as isPicture, i as isAutoShape, o as isGraphicFrame, s as isGroupShape } from "./shapes-Kt51vry6.js";
3
4
  //#region src/script/fidelity.ts
4
5
  /**
5
6
  * Accumulates notes while a deck is walked, so the walk itself stays a plain
@@ -350,12 +351,8 @@ function noteUncarriedGeometry(picture, notes, subject) {
350
351
  * Each check here is a standing argument for a real accessor. When one lands, the
351
352
  * corresponding function should be deleted, not kept in sync.
352
353
  */
353
- /** DrawingML main namespace — hosts `a:videoFile` / `a:audioFile` under `p:nvPr`. */
354
- const A_NS = "http://schemas.openxmlformats.org/drawingml/2006/main";
355
354
  /** Office MathML namespace — the equation body itself, wrapped by `a14:m` in a text run. */
356
355
  const MATH_NS = "http://schemas.openxmlformats.org/officeDocument/2006/math";
357
- /** PresentationML main namespace — `p:grpSpPr`, `p:txStyles`, `p:spTree`. */
358
- const P_NS = "http://schemas.openxmlformats.org/presentationml/2006/main";
359
356
  /** Shape-tree children that carry drawing content, as opposed to the tree's own properties. */
360
357
  const SHAPE_ELEMENTS = /* @__PURE__ */ new Set([
361
358
  "sp",
@@ -404,7 +401,7 @@ function children(element) {
404
401
  * without this check a video converts to a static image that looks deliberate.
405
402
  */
406
403
  function isAudioVideo(element) {
407
- return has(element, A_NS, "videoFile") || has(element, A_NS, "audioFile");
404
+ return has(element, OOXML_NS.a, "videoFile") || has(element, OOXML_NS.a, "audioFile");
408
405
  }
409
406
  /**
410
407
  * `true` when this shape's text body contains an OMML equation.
@@ -431,7 +428,7 @@ function hasEquation(element) {
431
428
  * would otherwise answer for its first child.
432
429
  */
433
430
  function isTextBox(element) {
434
- return child(child(element, P_NS, "nvSpPr"), P_NS, "cNvSpPr")?.getAttribute("txBox") === "1";
431
+ return child(child(element, OOXML_NS.p, "nvSpPr"), OOXML_NS.p, "cNvSpPr")?.getAttribute("txBox") === "1";
435
432
  }
436
433
  /**
437
434
  * `true` when a group's child coordinate space equals its own frame, so its children are
@@ -446,12 +443,12 @@ function isTextBox(element) {
446
443
  * `true` rather than unknown.
447
444
  */
448
445
  function hasIdentityChildSpace(element) {
449
- const xfrm = child(child(element, P_NS, "grpSpPr"), A_NS, "xfrm");
446
+ const xfrm = child(child(element, OOXML_NS.p, "grpSpPr"), OOXML_NS.a, "xfrm");
450
447
  if (!xfrm) return true;
451
- const off = child(xfrm, A_NS, "off");
452
- const ext = child(xfrm, A_NS, "ext");
453
- const chOff = child(xfrm, A_NS, "chOff");
454
- const chExt = child(xfrm, A_NS, "chExt");
448
+ const off = child(xfrm, OOXML_NS.a, "off");
449
+ const ext = child(xfrm, OOXML_NS.a, "ext");
450
+ const chOff = child(xfrm, OOXML_NS.a, "chOff");
451
+ const chExt = child(xfrm, OOXML_NS.a, "chExt");
455
452
  if (!off || !ext || !chOff || !chExt) return true;
456
453
  return off.getAttribute("x") === chOff.getAttribute("x") && off.getAttribute("y") === chOff.getAttribute("y") && ext.getAttribute("cx") === chExt.getAttribute("cx") && ext.getAttribute("cy") === chExt.getAttribute("cy");
457
454
  }
@@ -464,7 +461,7 @@ function hasIdentityChildSpace(element) {
464
461
  * scheme is repainted with Office's, and this is the only way to notice.
465
462
  */
466
463
  function hasFormatScheme(element) {
467
- return has(element, A_NS, "fmtScheme");
464
+ return has(element, OOXML_NS.a, "fmtScheme");
468
465
  }
469
466
  /**
470
467
  * `true` when this slide master declares per-level text styles (`p:txStyles`) with content.
@@ -474,7 +471,7 @@ function hasFormatScheme(element) {
474
471
  * converter and comes back as PowerPoint's built-in default.
475
472
  */
476
473
  function hasTextStyles(element) {
477
- return children(child(element, P_NS, "txStyles")).some((group) => children(group).length > 0);
474
+ return children(child(element, OOXML_NS.p, "txStyles")).some((group) => children(group).length > 0);
478
475
  }
479
476
  /**
480
477
  * `true` when this shape is a placeholder — the tier that *reserves* a region for a slide to
@@ -492,7 +489,7 @@ function hasTextStyles(element) {
492
489
  * cannot survive being flattened into loose objects.
493
490
  */
494
491
  function isPlaceholderShape(element) {
495
- return has(element, P_NS, "ph");
492
+ return has(element, OOXML_NS.p, "ph");
496
493
  }
497
494
  /**
498
495
  * `true` when this master or layout carries a shape that is not a placeholder — a logo, a
@@ -506,7 +503,7 @@ function isPlaceholderShape(element) {
506
503
  * rather than an unconditional note.
507
504
  */
508
505
  function hasDecorativeShapes(element) {
509
- return children(child(child(element, P_NS, "cSld"), P_NS, "spTree")).some((shape) => shape.namespaceURI === P_NS && SHAPE_ELEMENTS.has(shape.localName ?? "") && !isPlaceholderShape(shape));
506
+ return children(child(child(element, OOXML_NS.p, "cSld"), OOXML_NS.p, "spTree")).some((shape) => shape.namespaceURI === OOXML_NS.p && SHAPE_ELEMENTS.has(shape.localName ?? "") && !isPlaceholderShape(shape));
510
507
  }
511
508
  //#endregion
512
509
  //#region src/script/from-read/text.ts
@@ -1781,18 +1778,40 @@ function connectorCall(shape, notes) {
1781
1778
  ...nameOf(shape)
1782
1779
  };
1783
1780
  }
1781
+ /**
1782
+ * Why a graphic frame cannot be authored from a script, or `null` when it can.
1783
+ *
1784
+ * The single enumeration of the payloads with no write-API emitter, and the reason it is a
1785
+ * function rather than a condition spelled at each site: `graphicFrameCall` needs it to pick
1786
+ * a fidelity note, and `hasUnwritableContent` in `from-read/deck.ts` needs it to decide
1787
+ * whether the printer must copy the slide instead of transcribing it. Those were two
1788
+ * hand-maintained lists, they disagreed — the deck-level one named extended charts only — and
1789
+ * a SmartArt slide was therefore transcribed with a hole where the graphic had been. The two
1790
+ * consequences are the same for every member, so the membership has to be too.
1791
+ */
1792
+ function unwritableFramePayload(shape) {
1793
+ if (shape.table || shape.chart) return null;
1794
+ if (shape.hasChartEx) return "chartEx";
1795
+ if (shape.hasDiagram) return "diagram";
1796
+ return "unknown";
1797
+ }
1784
1798
  /** A `GraphicFrame` hosts a table or a chart; both have their own mapper. */
1785
1799
  function graphicFrameCall(shape, notes, assets) {
1786
1800
  const table = shape.table;
1787
1801
  if (table) return tableCall(shape, table, notes, assets);
1788
1802
  const chart = shape.chart;
1789
1803
  if (chart) return chartCall(shape, chart, notes);
1790
- if (shape.hasChartEx) {
1791
- notes.note("chartEx.all", "dropped", "unwritable", "an extended chart (waterfall, funnel, box-and-whisker, …) has a full reader but no write-API counterpart");
1792
- return null;
1804
+ switch (unwritableFramePayload(shape)) {
1805
+ case "chartEx":
1806
+ notes.note("chartEx.all", "dropped", "unwritable", "an extended chart (waterfall, funnel, box-and-whisker, …) has a full reader but no write-API counterpart");
1807
+ return null;
1808
+ case "diagram":
1809
+ notes.note("diagram.all", "dropped", "unwritable", "a SmartArt diagram has a full reader and its text can be edited in place through it (DiagramPoint.text), but no write API authors one from a script, so a converted script cannot describe this frame");
1810
+ return null;
1811
+ default:
1812
+ notes.note("graphicFrame.unknown", "dropped", "unread", "this graphic frame hosts none of a table, a chart or a SmartArt diagram (an OLE object or an ink annotation), which the read model does not decode");
1813
+ return null;
1793
1814
  }
1794
- notes.note("graphicFrame.unknown", "dropped", "unread", "this graphic frame hosts neither a table nor a chart (SmartArt or an OLE object), which the read model does not decode");
1795
- return null;
1796
1815
  }
1797
1816
  /**
1798
1817
  * A `GroupShape` becomes `addGroup`, with each child mapped and re-tagged into the
@@ -1840,6 +1859,28 @@ function groupCall(shape, notes, assets) {
1840
1859
  * `addGroup` excludes. The tagged form is a single-key object, not a `{ type, args }` pair.
1841
1860
  */
1842
1861
  function asGroupChild(call) {
1862
+ const shared = commonShapeVariant(call);
1863
+ if (shared) return shared;
1864
+ const [first, second] = call.args;
1865
+ switch (call.method) {
1866
+ case "addGroup": return { group: compact({
1867
+ children: first,
1868
+ options: second
1869
+ }) ?? {} };
1870
+ default: return null;
1871
+ }
1872
+ }
1873
+ /**
1874
+ * The three key-tagged variants both union-shaped call sites emit identically: a text box, an
1875
+ * auto shape, and an image. `null` when `call.method` is not one of them, which is the signal
1876
+ * for the caller to try its own extra arms.
1877
+ *
1878
+ * Shared rather than duplicated because this is exactly where a fourth common variant would be
1879
+ * added to one site and forgotten in the other. What is deliberately *not* shared is either
1880
+ * caller's `default`: a group child silently declines a chart, while a layout object reports it
1881
+ * as a fidelity loss, and that difference is the point of having two functions.
1882
+ */
1883
+ function commonShapeVariant(call) {
1843
1884
  const [first, second] = call.args;
1844
1885
  switch (call.method) {
1845
1886
  case "addText": return { text: compact({
@@ -1851,10 +1892,6 @@ function asGroupChild(call) {
1851
1892
  options: second
1852
1893
  }) ?? {} };
1853
1894
  case "addImage": return { image: first ?? {} };
1854
- case "addGroup": return { group: compact({
1855
- children: first,
1856
- options: second
1857
- }) ?? {} };
1858
1895
  default: return null;
1859
1896
  }
1860
1897
  }
@@ -1891,17 +1928,10 @@ function masterObject(shape, notes, assets) {
1891
1928
  }
1892
1929
  const call = shapeCall(shape, notes, assets);
1893
1930
  if (!call) return null;
1931
+ const shared = commonShapeVariant(call);
1932
+ if (shared) return shared;
1894
1933
  const [first, second] = call.args;
1895
1934
  switch (call.method) {
1896
- case "addText": return { text: compact({
1897
- text: first,
1898
- options: second
1899
- }) ?? {} };
1900
- case "addShape": return { shape: compact({
1901
- type: first,
1902
- options: second
1903
- }) ?? {} };
1904
- case "addImage": return { image: first ?? {} };
1905
1935
  case "addChart": {
1906
1936
  const options = second !== null && typeof second === "object" && !Array.isArray(second) && !isAssetRef(second) ? second : null;
1907
1937
  const type = options?.["type"];
@@ -2380,7 +2410,7 @@ function slideToIr(slide, number, collector, assets, layouts) {
2380
2410
  };
2381
2411
  const transition = transitionToIr(slide, notes, assets);
2382
2412
  const carried = hasUnwritableContent(slide);
2383
- if (carried) notes.note("slide.carried", "flattened", "unwritable", "this slide holds an extended chart (waterfall, funnel, box-and-whisker, …), which has a full reader but no write-API emitter; a printer that can copy the source slide does so instead of transcribing it, so it renders correctly but the emitted script does not describe its contents");
2413
+ if (carried) notes.note("slide.carried", "flattened", "unwritable", "this slide holds a graphic frame the write API cannot author (an extended chart, a SmartArt diagram, an OLE object or ink); a printer that can copy the source slide does so instead of transcribing it, so it renders correctly but the emitted script does not describe its contents. The per-shape note beside this one says which construct forced the copy");
2384
2414
  const calls = [];
2385
2415
  for (const shape of slide.shapes) {
2386
2416
  const call = shapeCall(shape, notes, assets);
@@ -2397,11 +2427,16 @@ function slideToIr(slide, number, collector, assets, layouts) {
2397
2427
  /**
2398
2428
  * `true` when the slide holds something with no write-API expression at all, forcing a
2399
2429
  * carried slide. Descends into groups, since a group can host a graphic frame.
2430
+ *
2431
+ * Membership comes from {@link unwritableFramePayload}, which `graphicFrameCall` also uses to
2432
+ * pick its note — one enumeration, so the two cannot drift apart again. This test named
2433
+ * extended charts alone until then, which is why a slide holding SmartArt (or an OLE object,
2434
+ * or ink) was transcribed as `authored` and rendered with a hole where the graphic had been.
2400
2435
  */
2401
2436
  function hasUnwritableContent(slide) {
2402
2437
  const check = (shapes) => shapes.some((shape) => {
2403
2438
  if (isGroupShape(shape)) return check(shape.shapes);
2404
- return isGraphicFrame(shape) && shape.hasChartEx;
2439
+ return isGraphicFrame(shape) && unwritableFramePayload(shape) !== null;
2405
2440
  });
2406
2441
  return check(slide.shapes);
2407
2442
  }
@@ -2709,6 +2744,28 @@ function wrap(text, width, continuation) {
2709
2744
  if (current) lines.push(current);
2710
2745
  return lines;
2711
2746
  }
2747
+ /**
2748
+ * Close out a printed script: the accumulated lines as one module source, plus the
2749
+ * asset side-car the caller has to write beside it.
2750
+ *
2751
+ * Both tiers end this way, and the `assetMode` test is the whole reason it is worth
2752
+ * naming. In `'inline'` mode the bytes are already in {@link PrintedScript.code} as
2753
+ * `data:` literals, so the map must come back **empty** — a tier that returned them
2754
+ * anyway would have its caller write every image to disk as well, and the script would
2755
+ * ignore the files it was handed.
2756
+ * @param {string[]} lines - the script's lines, in order
2757
+ * @param {DeckIr} ir - the IR being printed, for its assets
2758
+ * @param {AssetMode} assetMode - how image bytes reach the script
2759
+ * @param {FidelityNote[]} notes - the losses that apply to this output
2760
+ * @returns {PrintedScript} the finished script
2761
+ */
2762
+ function printedScript(lines, ir, assetMode, notes) {
2763
+ return {
2764
+ code: lines.join("\n"),
2765
+ assets: new Map(assetMode === "file" ? ir.assets.map((asset) => [asset.name, asset.bytes]) : []),
2766
+ notes
2767
+ };
2768
+ }
2712
2769
  //#endregion
2713
2770
  //#region src/script/print/script.ts
2714
2771
  /**
@@ -2794,19 +2851,22 @@ function printScript(ir, options = {}) {
2794
2851
  const assetLines = printAssetBindings(ir, assetNames, assetDir, assetMode);
2795
2852
  if (assetLines.length > 0) lines.push("", ...assetLines);
2796
2853
  lines.push("", "/**", " * A generator sized to the template. appendSlides compares slide sizes exactly and", " * throws when they differ, so the inches here must round-trip to the source EMU.", " */", "function generator(): TsPptx {", " const pptx = new TsPptx()", `\tpptx.defineLayout({ name: 'source', width: ${inches(ir.slideSize.widthEmu)}, height: ${inches(ir.slideSize.heightEmu)} })`, " pptx.layout = 'source'", " return pptx", "}", ...body, "", `await writeFile(here(${printString(outputPath)}), await deck.save())`, "");
2797
- return {
2798
- code: lines.join("\n"),
2799
- assets: new Map(assetMode === "file" ? ir.assets.map((asset) => [asset.name, asset.bytes]) : []),
2800
- notes
2801
- };
2854
+ return printedScript(lines, ir, assetMode, notes);
2802
2855
  }
2803
2856
  /**
2804
- * The slide statements, batched into generators.
2857
+ * The slide statements, batched into generators, preceded by the layout handles they bind to.
2805
2858
  *
2806
2859
  * A batch ends when the layout changes or a carried slide interrupts, because
2807
2860
  * `appendSlides` binds one layout per call and a carried slide is not authored at all.
2861
+ *
2862
+ * Every layout `const` is hoisted above the first statement rather than emitted where it is
2863
+ * first used. `deck.layouts()` is a snapshot of the gallery, and `importSlide` — the call a
2864
+ * carried slide prints — grows that gallery with the source slide's own layout and master.
2865
+ * Resolving a handle after one has run is therefore resolving against a deck that has already
2866
+ * moved; capturing every handle up front is the only ordering that cannot.
2808
2867
  */
2809
2868
  function printSlides$1(ir, collector, printAsset) {
2869
+ const declarations = [];
2810
2870
  const lines = [];
2811
2871
  let batch = [];
2812
2872
  let generatorIndex = 0;
@@ -2818,7 +2878,7 @@ function printSlides$1(ir, collector, printAsset) {
2818
2878
  const name = `gen${++generatorIndex}`;
2819
2879
  lines.push("", `const ${name} = generator()`);
2820
2880
  for (const slide of batch) lines.push(...printAuthoredSlide(slide, name, collector, printAsset));
2821
- lines.push("", ...printAppend(name, first, collector, declaredLayouts));
2881
+ lines.push("", printAppend(name, first, collector, declaredLayouts, declarations));
2822
2882
  batch = [];
2823
2883
  };
2824
2884
  for (const slide of ir.slides) {
@@ -2832,31 +2892,39 @@ function printSlides$1(ir, collector, printAsset) {
2832
2892
  batch.push(slide);
2833
2893
  }
2834
2894
  flush();
2835
- return lines;
2895
+ return declarations.length > 0 ? [
2896
+ "",
2897
+ ...declarations,
2898
+ ...lines
2899
+ ] : lines;
2836
2900
  }
2837
2901
  /**
2838
2902
  * The `appendSlides` call closing a batch, binding by layout name where that is
2839
- * unambiguous and by gallery position where it is not.
2903
+ * unambiguous and by gallery position where it is not. Any handle it needs is appended to
2904
+ * `declarations`, which the caller hoists above every statement.
2840
2905
  *
2841
2906
  * Binding by name is preferred because it survives being re-pointed at a different
2842
2907
  * template and because it is legible. But `appendSlides` *throws* on an ambiguous name
2843
- * rather than picking one, and a multi-master deck routinely repeats layout names, so the
2844
- * positional form is the only thing that resolves there.
2908
+ * rather than picking one, so the positional form resolves the case where the name does not
2909
+ * identify one layout: a multi-master deck that repeats layout names.
2910
+ *
2911
+ * A carried slide used to demote every binding in the script to a position too, because its
2912
+ * `importSlide` copied the source layout in under a second name-alike entry. `importSlide`
2913
+ * now binds to the chrome the template already holds (`read/api/ops/part-reuse.ts`), and
2914
+ * this deck's template *is* the source file, so the gallery no longer grows and the names
2915
+ * stay unambiguous.
2845
2916
  */
2846
- function printAppend(generatorName, first, collector, declared) {
2917
+ function printAppend(generatorName, first, collector, declared, declarations) {
2847
2918
  const layout = first.layout;
2848
- if (!layout) return [`await deck.appendSlides(${generatorName}, { layout: fallbackLayout })`];
2849
- if (layout.nameIsUnique) return [`await deck.appendSlides(${generatorName}, { layout: ${printString(layout.name)} })`];
2919
+ if (!layout) return `await deck.appendSlides(${generatorName}, { layout: fallbackLayout })`;
2920
+ if (layout.nameIsUnique) return `await deck.appendSlides(${generatorName}, { layout: ${printString(layout.name)} })`;
2850
2921
  scopeNotes(collector, first.number).note("slide.layout", "approximated", "unsupported", `more than one layout in the source deck is named ${JSON.stringify(layout.name)}, so this slide binds to gallery position ${layout.index} instead; re-pointing the script at a different template will not track the name`);
2851
2922
  const identifier = `layout${layout.index}`;
2852
- const append = `await deck.appendSlides(${generatorName}, { layout: ${identifier} })`;
2853
- if (declared.has(layout.index)) return [append];
2854
- declared.add(layout.index);
2855
- return [
2856
- `const ${identifier} = deck.layouts()[${layout.index}] // ${JSON.stringify(layout.name)}`,
2857
- `if (!${identifier}) throw new Error('the template has no layout at position ${layout.index}')`,
2858
- append
2859
- ];
2923
+ if (!declared.has(layout.index)) {
2924
+ declared.add(layout.index);
2925
+ declarations.push(`const ${identifier} = deck.layouts()[${layout.index}] // ${JSON.stringify(layout.name)}`, `if (!${identifier}) throw new Error('the template has no layout at position ${layout.index}')`);
2926
+ }
2927
+ return `await deck.appendSlides(${generatorName}, { layout: ${identifier} })`;
2860
2928
  }
2861
2929
  /** One authored slide, plus the layout-binding note this tier is responsible for. */
2862
2930
  function printAuthoredSlide(slide, generatorName, collector, printAsset) {
@@ -2928,11 +2996,7 @@ function printStandaloneScript(ir, options = {}) {
2928
2996
  if (assetLines.length > 0) lines.push("", ...assetLines);
2929
2997
  if (masters.length > 0) lines.push("", ...masters);
2930
2998
  lines.push(...body, "", `await pptx.writeFile({ fileName: here(${printString(outputPath)}) })`, "");
2931
- return {
2932
- code: lines.join("\n"),
2933
- assets: new Map(assetMode === "file" ? ir.assets.map((asset) => [asset.name, asset.bytes]) : []),
2934
- notes
2935
- };
2999
+ return printedScript(lines, ir, assetMode, notes);
2936
3000
  }
2937
3001
  /**
2938
3002
  * The document properties the write API can set.
@@ -3267,6 +3331,7 @@ const NOTE_FIELDS = {
3267
3331
  "deck.docProps": [],
3268
3332
  "deck.docPropsDefault": [],
3269
3333
  "deck.slideSize": ["widthEmu", "heightEmu"],
3334
+ "diagram.all": ["*"],
3270
3335
  "fill.gradient.path": ["gradient", "fill"],
3271
3336
  "fill.picture": ["fill", "color"],
3272
3337
  "fill.picture.geometry": [],