@openpresentation/opf 0.20.5 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/browser.js +16 -16
  2. package/dist/{chunk-2M7U4WL3.js → chunk-23MOKE4B.js} +292 -104
  3. package/dist/{chunk-TCBEF5OY.js → chunk-2SENTA2R.js} +1 -1
  4. package/dist/{chunk-7PQZDC2H.js → chunk-3T7MNRBY.js} +1 -1
  5. package/dist/{chunk-VFMHM2IL.js → chunk-3UAVON3O.js} +28 -2
  6. package/dist/{chunk-IDMQWS6O.js → chunk-7XNAMCGT.js} +6 -6
  7. package/dist/{chunk-URUNMZFO.js → chunk-BULGAKBY.js} +2 -2
  8. package/dist/{chunk-WD4W7KKK.js → chunk-DY7H4RG6.js} +54 -11
  9. package/dist/{chunk-V66KJA3H.js → chunk-KUNXFN7B.js} +1 -1
  10. package/dist/{chunk-52GKVP3I.js → chunk-MAJHCGOW.js} +22 -12
  11. package/dist/{chunk-OIGCC6VA.js → chunk-MG34DCDB.js} +2 -2
  12. package/dist/{chunk-5SQ6CIWR.js → chunk-MLMTXXM4.js} +5 -5
  13. package/dist/{chunk-Z75YB54S.js → chunk-SBWIZSPB.js} +5 -5
  14. package/dist/{chunk-TZ5IZETE.js → chunk-SPCONMIY.js} +1 -1
  15. package/dist/{chunk-XAYMPBNE.js → chunk-VKNFZEMG.js} +403 -189
  16. package/dist/{chunk-S4FR7ATF.js → chunk-X3PQMMAY.js} +1 -1
  17. package/dist/{chunk-YOLDSF7U.js → chunk-YSJRBRHB.js} +1 -1
  18. package/dist/{chunk-DYGYMBBW.js → chunk-YUIEWE5B.js} +2 -2
  19. package/dist/{composition-QtS1rnhv.d.ts → composition-CkHn6JrM.d.ts} +139 -5
  20. package/dist/composition.d.ts +1 -1
  21. package/dist/composition.js +1 -1
  22. package/dist/conversion-3TTBY7OY.js +19 -0
  23. package/dist/{conversion-Cqwu0Ds9.d.ts → conversion-DS4OiVls.d.ts} +6 -5
  24. package/dist/convert.d.ts +3 -3
  25. package/dist/convert.js +7 -7
  26. package/dist/data.d.ts +1 -1
  27. package/dist/data.js +2 -2
  28. package/dist/{deck-report-BdG5H3Qj.d.ts → deck-report-vnWmXBjq.d.ts} +2 -2
  29. package/dist/deck.d.ts +6 -6
  30. package/dist/deck.js +10 -10
  31. package/dist/diff.d.ts +1 -1
  32. package/dist/diff.js +5 -5
  33. package/dist/docs.js +18 -12
  34. package/dist/examples.d.ts +1 -1
  35. package/dist/{finding-DqgwzUmr.d.ts → finding-l9dlQ2NF.d.ts} +4 -0
  36. package/dist/format.js +2 -2
  37. package/dist/index.d.ts +21 -15
  38. package/dist/index.js +20 -20
  39. package/dist/markdown.d.ts +4 -4
  40. package/dist/markdown.js +7 -7
  41. package/dist/node-engine.d.ts +30 -9
  42. package/dist/node-engine.js +20 -20
  43. package/dist/{pagination-CAX6mHG6.d.ts → pagination-C4jzAtFy.d.ts} +2 -2
  44. package/dist/pagination.d.ts +2 -2
  45. package/dist/pagination.js +4 -4
  46. package/dist/patch.d.ts +1 -1
  47. package/dist/patch.js +4 -4
  48. package/dist/{presentation-BG4QCcdB.d.ts → presentation-fN6tORPZ.d.ts} +58 -8
  49. package/dist/repo-readme.js +1 -1
  50. package/dist/schemas.js +1 -1
  51. package/dist/spec/schemas/finding.schema.json +6 -1
  52. package/dist/spec/schemas/opf.schema.json +14 -2
  53. package/dist/types.d.ts +2 -2
  54. package/dist/{validation-types-DRaNnieo.d.ts → validation-types-B21fZfb2.d.ts} +3 -3
  55. package/dist/{validator-BJtXHJKh.d.ts → validator-Cflv4F9e.d.ts} +4 -10
  56. package/dist/validator.d.ts +5 -5
  57. package/dist/validator.js +3 -3
  58. package/dist/yaml.d.ts +4 -4
  59. package/dist/yaml.js +7 -7
  60. package/package.json +1 -1
  61. package/dist/conversion-DRCJIMWS.js +0 -19
@@ -1,4 +1,4 @@
1
- import { validate } from './chunk-2M7U4WL3.js';
1
+ import { validate } from './chunk-23MOKE4B.js';
2
2
 
3
3
  // src/convert/shared.ts
4
4
  var CONTENT_KEYS = ["text", "items", "bullets", "image", "video", "chart", "table", "code", "metric", "quote", "timeline"];
@@ -1,4 +1,4 @@
1
- import { isRecord, same } from './chunk-TCBEF5OY.js';
1
+ import { isRecord, same } from './chunk-2SENTA2R.js';
2
2
  import { parseDocument, YAMLMap, Scalar, stringify } from 'yaml';
3
3
 
4
4
  // src/not-checked.ts
@@ -1201,7 +1201,7 @@ var presentation = {
1201
1201
  "center",
1202
1202
  "right"
1203
1203
  ],
1204
- "description": "Default horizontal alignment for the title heading area in resolved layouts. Effective value: the slide's design, then the deck's design, then the theme's design.titleAlignment, then the layout record's design.titleAlignment, then the engine default."
1204
+ "description": "Default horizontal alignment for the title heading area (the title and the tag) in resolved layouts. Effective value: the slide's design, then the deck's design, then the theme's design.titleAlignment, then the layout record's design.titleAlignment, then the engine default."
1205
1205
  },
1206
1206
  "contentAlignment": {
1207
1207
  "type": "string",
@@ -1210,7 +1210,7 @@ var presentation = {
1210
1210
  "center",
1211
1211
  "right"
1212
1212
  ],
1213
- "description": "Default horizontal alignment for body/content regions in resolved layouts. Effective value: the slide's design, then the deck's design, then the theme's design.contentAlignment, then the layout record's design.contentAlignment, then the engine default. A cover's tag and subtitle follow titleAlignment unless the slide's own design sets contentAlignment."
1213
+ "description": "Default horizontal alignment for body/content regions in resolved layouts. Effective value: the slide's design, then the deck's design, then the theme's design.contentAlignment, then the layout record's design.contentAlignment, then the engine default. The tag follows titleAlignment (and a cover's subtitle with it) unless the slide's own design sets contentAlignment."
1214
1214
  },
1215
1215
  "contentBox": {
1216
1216
  "type": "boolean",
@@ -4653,6 +4653,21 @@ var presentation = {
4653
4653
  "Revenue grew from $12M in Q1 to $18M in Q2, with the steepest rise in the West region."
4654
4654
  ]
4655
4655
  },
4656
+ "colors": {
4657
+ "type": "array",
4658
+ "items": {
4659
+ "$ref": "#/$defs/ColorRef"
4660
+ },
4661
+ "minItems": 1,
4662
+ "maxItems": 24,
4663
+ "description": "Optional series colors, by position: entry i replaces palette color i, the color of series i (the i-th plotted value column), of slice or category i on a pie, doughnut, treemap or funnel chart, and of the i-th color a histogram, pareto, waterfall or box-and-whisker chart draws with. An entry is any ColorRef: a hex color, a color-scheme slot or role ('accent3', 'secondary') or a 'var:<id>' color variable; a scheme name keeps following the deck if its scheme changes, and is written to PowerPoint as a theme color. Positions past the last entry keep the deck palette (accent1 to accent6, then their tints). A color is kept at 3:1 contrast against the chart panel (a lighter or darker shade is used when it falls short) and 'chart.highlight' wins over it: highlighted marks take the primary color and the rest the muted neutral. A color that cannot be resolved falls back to the palette color for its position. Absent keeps the deck palette exactly.",
4664
+ "examples": [
4665
+ [
4666
+ "accent3",
4667
+ "#7B241C"
4668
+ ]
4669
+ ]
4670
+ },
4656
4671
  "highlight": {
4657
4672
  "$ref": "#/$defs/ChartHighlight",
4658
4673
  "description": "Optional emphasis: the series and/or categories that carry the message. The engines draw the highlighted marks in the deck's primary (accent) color and every other mark in a muted neutral derived from the theme (a light grey on a light chart panel, a dim grey on a dark one); there is no color field. A mark is highlighted when its series OR its category is named. Absent keeps today's colors exactly. Supported on column, bar and line charts (series and categories; on a line a category highlight marks that category's points), pie and doughnut charts (categories, one per slice), and area, scatter and radar charts (series); the histogram, pareto, waterfall, funnel, treemap, box-and-whisker, map and combo constructs drop the option with a 'chart-option-adapted' diagnostic, as does a part the type cannot highlight. A name that matches no column or row label is a 'chart-highlight-unknown-name' error."
@@ -5395,6 +5410,10 @@ var presentation = {
5395
5410
  "$ref": "#/$defs/ColorRef",
5396
5411
  "description": "Default text color, overridden by individual rich run colors. Accepts a hex color, a color-scheme slot or role name, or a 'var:<id>' variable reference."
5397
5412
  },
5413
+ "bold": {
5414
+ "type": "boolean",
5415
+ "description": "Bold cell text. Runs that set their own bold keep it; a number cell stays bold and still uses the cell's or column's number format."
5416
+ },
5398
5417
  "align": {
5399
5418
  "type": "string",
5400
5419
  "enum": [
@@ -8551,6 +8570,13 @@ var finding = {
8551
8570
  "params": {
8552
8571
  "type": "object",
8553
8572
  "additionalProperties": true
8573
+ },
8574
+ "alternatives": {
8575
+ "type": "array",
8576
+ "items": {
8577
+ "type": "string"
8578
+ },
8579
+ "description": "Present when the issue is the best match of a oneOf or anyOf: one line per other form the value was checked against and did not fit, such as `string: must be string`."
8554
8580
  }
8555
8581
  }
8556
8582
  },
@@ -1,9 +1,9 @@
1
- import { NOT_CHECKED, Ctx } from './chunk-7PQZDC2H.js';
2
- import { sortPresentationKeys } from './chunk-S4FR7ATF.js';
3
- import { same } from './chunk-TCBEF5OY.js';
4
- import { validate } from './chunk-2M7U4WL3.js';
5
- import { checkCatalogsOption } from './chunk-XAYMPBNE.js';
6
- import { presentation } from './chunk-VFMHM2IL.js';
1
+ import { NOT_CHECKED, Ctx } from './chunk-3T7MNRBY.js';
2
+ import { sortPresentationKeys } from './chunk-X3PQMMAY.js';
3
+ import { same } from './chunk-2SENTA2R.js';
4
+ import { validate } from './chunk-23MOKE4B.js';
5
+ import { checkCatalogsOption } from './chunk-VKNFZEMG.js';
6
+ import { presentation } from './chunk-3UAVON3O.js';
7
7
  import { Parser, parseDocument, isMap, Document, visit, isScalar, isAlias, isSeq } from 'yaml';
8
8
 
9
9
  var MAX_ALIAS_COUNT = 100;
@@ -1,5 +1,5 @@
1
- import { jsonEqual, formatPointer } from './chunk-YOLDSF7U.js';
2
- import { annotationText } from './chunk-XAYMPBNE.js';
1
+ import { jsonEqual, formatPointer } from './chunk-YSJRBRHB.js';
2
+ import { annotationText } from './chunk-VKNFZEMG.js';
3
3
 
4
4
  // src/diff-match.ts
5
5
  var DEFAULT_MATCH_THRESHOLD = 0.5;
@@ -1,11 +1,11 @@
1
- import { defaultCatalogs } from './chunk-OIGCC6VA.js';
2
- import { OPFApiError, parseSlideSelection, OPFExportError, asApiError, OPFImportError } from './chunk-52GKVP3I.js';
3
- import { deckFormatOf, readDeckReport, stringify } from './chunk-5SQ6CIWR.js';
4
- import { paginate } from './chunk-DYGYMBBW.js';
5
- import { validate, OPFValidationError } from './chunk-2M7U4WL3.js';
6
- import { stat, readdir, lstat, mkdir, open, rename, link, unlink, readFile } from 'fs/promises';
1
+ import { defaultCatalogs } from './chunk-MG34DCDB.js';
2
+ import { localAssetSources, OPFApiError, parseSlideSelection, OPFExportError, asApiError, OPFImportError } from './chunk-MAJHCGOW.js';
3
+ import { deckFormatOf, readDeckReport, stringify } from './chunk-MLMTXXM4.js';
4
+ import { paginate } from './chunk-YUIEWE5B.js';
5
+ import { validate, OPFValidationError } from './chunk-23MOKE4B.js';
6
+ import { link, stat, readdir, lstat, readFile, open, unlink, mkdir, rename } from 'fs/promises';
7
7
  import path6 from 'path';
8
- import { readFileSync, realpathSync, statSync } from 'fs';
8
+ import { readFileSync, statSync, realpathSync } from 'fs';
9
9
  import { pathToFileURL, fileURLToPath } from 'url';
10
10
  import { createRequire } from 'module';
11
11
  import { randomUUID } from 'crypto';
@@ -74,6 +74,11 @@ function createImageResolver(root, reporter, passDirectory = "pass --asset-dir")
74
74
  return outcome;
75
75
  }
76
76
  return {
77
+ /** The reason a local source cannot be read (`missing`: no such file; `blocked`: outside the folder, not an image, too large), or undefined when it can, or is not a local file. */
78
+ check: (source) => {
79
+ const outcome = read(source);
80
+ return "problem" in outcome ? outcome : void 0;
81
+ },
77
82
  /** opf-render: a data URI string, or null for the placeholder (a missing file is reported by the renderer as unresolved-asset). */
78
83
  forSvg: (source, context) => {
79
84
  if (!source) return null;
@@ -91,6 +96,25 @@ function createImageResolver(root, reporter, passDirectory = "pass --asset-dir")
91
96
  }
92
97
  };
93
98
  }
99
+ function pointerToString(value, source, pointer = "") {
100
+ if (value === source) return pointer;
101
+ if (value === null || typeof value !== "object") return void 0;
102
+ for (const [key, child] of Object.entries(value)) {
103
+ const found = pointerToString(child, source, `${pointer}/${key.replaceAll("~", "~0").replaceAll("/", "~1")}`);
104
+ if (found !== void 0) return found;
105
+ }
106
+ return void 0;
107
+ }
108
+ function localAssetProblems(deck, root) {
109
+ const resolver = createImageResolver(root, { add() {
110
+ } });
111
+ const problems = [];
112
+ for (const source of localAssetSources(deck)) {
113
+ const found = resolver.check(source);
114
+ if (found) problems.push({ path: pointerToString(deck, source) ?? "", source, ...found });
115
+ }
116
+ return problems;
117
+ }
94
118
  var RENDER_PACKAGE = "@openpresentation/opf-render";
95
119
  var PPTX_PACKAGE = "@openpresentation/opf-pptx";
96
120
  var PEER_RANGES = { [RENDER_PACKAGE]: "^0.20.0", [PPTX_PACKAGE]: "^0.20.0" };
@@ -348,6 +372,25 @@ async function checkDestinations(files, overwrite, flags = true) {
348
372
  }
349
373
  }
350
374
  }
375
+ var NO_HARD_LINKS = /* @__PURE__ */ new Set(["EPERM", "ENOTSUP", "EOPNOTSUPP", "ENOSYS", "EXDEV"]);
376
+ async function publishNew(temporary, output, publish = link) {
377
+ try {
378
+ await publish(temporary, output);
379
+ return;
380
+ } catch (error) {
381
+ if (!NO_HARD_LINKS.has(error.code ?? "")) throw error;
382
+ }
383
+ const bytes = await readFile(temporary);
384
+ const handle = await open(output, "wx");
385
+ try {
386
+ await handle.writeFile(bytes);
387
+ await handle.close();
388
+ } catch (error) {
389
+ await handle.close().catch(() => void 0);
390
+ await unlink(output).catch(() => void 0);
391
+ throw error;
392
+ }
393
+ }
351
394
  async function writeFiles(files, overwrite, flags = true) {
352
395
  const unique = new Set(files.map((entry) => path6.resolve(entry.file)));
353
396
  if (unique.size !== files.length) throw new OPFApiError("Two outputs would write the same file.", "invalid-option");
@@ -372,7 +415,7 @@ async function writeFiles(files, overwrite, flags = true) {
372
415
  item.temporary = "";
373
416
  } else {
374
417
  try {
375
- await link(item.temporary, item.output);
418
+ await publishNew(item.temporary, item.output);
376
419
  } catch (error) {
377
420
  if (error.code === "EEXIST") throw outputExists(item.output, flags);
378
421
  throw error;
@@ -438,14 +481,14 @@ var Reporter = class {
438
481
  help: HELP[code] ?? "",
439
482
  ...Object.fromEntries(Object.entries(details).filter(([, value]) => value !== void 0))
440
483
  };
441
- const key = JSON.stringify([entry.ruleId, entry.path, entry.message]);
484
+ const key = JSON.stringify([entry.ruleId, entry.path, entry.message, details]);
442
485
  if (this.seen.has(key)) return;
443
486
  this.seen.add(key);
444
487
  this.findings.push(entry);
445
488
  }
446
489
  /** Add a finding as the library made it (the `findings` of a thrown OPFRenderError, OPFPptxError or core validation error). Identical entries are kept once. */
447
490
  addFinding(finding) {
448
- const key = JSON.stringify([finding.ruleId, finding.path, finding.message]);
491
+ const key = JSON.stringify(finding);
449
492
  if (this.seen.has(key)) return;
450
493
  this.seen.add(key);
451
494
  this.findings.push(finding);
@@ -1035,4 +1078,4 @@ async function saveDeck(presentation, file, options = {}) {
1035
1078
  return { path: file, format };
1036
1079
  }
1037
1080
 
1038
- export { EXPORT_FORMATS, EXPORT_TEXT, PEER_RANGES, PPTX_PACKAGE, RENDER_EXTRAS, RENDER_PACKAGE, Reporter, VERSIONS, checkDate, checkDestinations, checkOptions, checkOutputPattern, checkRenamedOptions, checkScale, convertFiles, createZip, deckFileFormat, deckStem, embeddedFor, exportFormatOf, finishReport, importPresentation, leaseSharedFonts, listFontDirectories, loadPptx, loadRenderer, locatePackage, missingPeerFrom, openDeck, padNumber, planConversion, pointerOf, prepareExport, prepareFonts, reaches, readInput, reportThrown, resolveExportOptions, runExport, runImport, runPreparedExport, saveDeck, stemOf, writeFiles, writePlanned };
1081
+ export { EXPORT_FORMATS, EXPORT_TEXT, PEER_RANGES, PPTX_PACKAGE, RENDER_EXTRAS, RENDER_PACKAGE, Reporter, VERSIONS, assetRoot, checkDate, checkDestinations, checkOptions, checkOutputPattern, checkRenamedOptions, checkScale, convertFiles, createZip, deckFileFormat, deckStem, embeddedFor, exportFormatOf, finishReport, importPresentation, leaseSharedFonts, listFontDirectories, loadPptx, loadRenderer, localAssetProblems, locatePackage, missingPeerFrom, openDeck, padNumber, planConversion, pointerOf, prepareExport, prepareFonts, publishNew, reaches, readInput, reportThrown, resolveExportOptions, runExport, runImport, runPreparedExport, saveDeck, stemOf, writeFiles, writePlanned };
@@ -1,4 +1,4 @@
1
- import { runText } from './chunk-TCBEF5OY.js';
1
+ import { runText } from './chunk-2SENTA2R.js';
2
2
 
3
3
  // src/convert/text-lines.ts
4
4
  var LIST_PREFIX = /^([ \t]*)(?:([-*•+]|\d{1,3}[.)])[ \t]+)?/;
@@ -1,7 +1,7 @@
1
- import { OPFDataImportError, parseTabularData } from './chunk-TZ5IZETE.js';
2
- import { applyPatchWithInverse } from './chunk-YOLDSF7U.js';
3
- import { validate, OPFValidationError } from './chunk-2M7U4WL3.js';
4
- import { embeddedCopy, checkCatalogsOption, catalogReferenceSites, parseReference, catalogGroupDeclared, resolveReference, dottedPath, unresolvedReference, recordReferenceSites, catalogGroupSource, registeredCatalog, catalogKinds, CATALOG_GROUP_PATTERN, isRecord, visitContentPayloads, annotationText, listVariables, resolveVariables, LOGO_SHAPES, resolveDesignRecords, resolveFontFamilies, resolveCanvasDimensions, imageBackground } from './chunk-XAYMPBNE.js';
1
+ import { OPFDataImportError, parseTabularData } from './chunk-SPCONMIY.js';
2
+ import { applyPatchWithInverse } from './chunk-YSJRBRHB.js';
3
+ import { validate, OPFValidationError } from './chunk-23MOKE4B.js';
4
+ import { embeddedCopy, checkCatalogsOption, catalogReferenceSites, parseReference, catalogGroupDeclared, resolveReference, dottedPath, unresolvedReference, recordReferenceSites, catalogGroupSource, registeredCatalog, catalogKinds, CATALOG_GROUP_PATTERN, isRecord, visitContentPayloads, annotationText, listVariables, resolveVariables, LOGO_SHAPES, resolveDesignRecords, resolveFontFamilies, resolveCanvasDimensions, imageBackground } from './chunk-VKNFZEMG.js';
5
5
 
6
6
  // src/api-errors.ts
7
7
  var OPFApiError = class extends Error {
@@ -429,6 +429,14 @@ function visitRuns(value, visit) {
429
429
  }
430
430
  }
431
431
  function stats(presentation2, options = {}) {
432
+ return compute(presentation2, options);
433
+ }
434
+ function localAssetSources(presentation2) {
435
+ const found = /* @__PURE__ */ new Set();
436
+ compute(presentation2, {}, (src) => found.add(src));
437
+ return [...found];
438
+ }
439
+ function compute(presentation2, options, onFile) {
432
440
  const catalogs = { catalogs: checkCatalogsOption(options.catalogs, "stats") };
433
441
  if (!isRecord(presentation2)) throw new TypeError("stats needs a presentation object.");
434
442
  const deck = presentation2;
@@ -439,9 +447,14 @@ function stats(presentation2, options = {}) {
439
447
  const registry = isRecord(deck.assets) ? deck.assets : {};
440
448
  const uses = { total: 0, references: 0, embedded: 0, files: 0, remote: 0 };
441
449
  let embeddedTotal = 0;
442
- const useAsset = (asset) => {
450
+ const useAsset = (asset, video = false) => {
443
451
  const src = srcOf(asset);
444
452
  if (src === void 0) return;
453
+ if (onFile && !video) {
454
+ let source = src;
455
+ for (let hop = 0; source !== void 0 && assetForm(source) === "reference" && hop < 8; hop++) source = srcOf(registry[source.slice("asset:".length)]);
456
+ if (source !== void 0 && assetForm(source) === "file" && !source.includes("{{")) onFile(source);
457
+ }
445
458
  const form = assetForm(src);
446
459
  uses.total++;
447
460
  uses[form === "reference" ? "references" : form === "embedded" ? "embedded" : form === "remote" ? "remote" : "files"]++;
@@ -562,7 +575,7 @@ function stats(presentation2, options = {}) {
562
575
  const datasetUse = /* @__PURE__ */ new Map();
563
576
  const payloadCounts = { text: 0, items: 0, bullets: 0, quote: 0, metric: 0, code: 0, timeline: 0, chart: 0, table: 0, image: 0, video: 0, blocks: 0, regions: 0, groups: 0, maxDepth: 0 };
564
577
  const layouts = /* @__PURE__ */ new Map(), chartTypes = /* @__PURE__ */ new Map(), extensions = /* @__PURE__ */ new Set();
565
- const chartData = { inline: 0, dataset: 0, source: 0 };
578
+ const chartData = { inline: 0, dataset: 0, withSource: 0 };
566
579
  const tableItems = [];
567
580
  let tableRows = 0, tableColumns = 0, datasetBackedTables = 0, chartTotal = 0, captions = 0;
568
581
  const hidden = [], withoutNotes = [], sections = [];
@@ -641,7 +654,7 @@ function stats(presentation2, options = {}) {
641
654
  }
642
655
  if (node.image !== void 0) slideImages += contentImage(node.image);
643
656
  if (node.video !== void 0) {
644
- useAsset(node.video);
657
+ useAsset(node.video, true);
645
658
  images.videos++;
646
659
  }
647
660
  if (isRecord(node.chart)) {
@@ -654,10 +667,7 @@ function stats(presentation2, options = {}) {
654
667
  chartData.dataset++;
655
668
  bump(datasetUse, data.dataset);
656
669
  } else if (Array.isArray(data.columns) || Array.isArray(data.rows)) chartData.inline++;
657
- else if (typeof data.src === "string") {
658
- chartData.source++;
659
- useAsset(data.src);
660
- }
670
+ if (isRecord(data.source)) chartData.withSource++;
661
671
  }
662
672
  }
663
673
  if (isRecord(node.table)) {
@@ -920,4 +930,4 @@ function summarize(decks) {
920
930
  return [...merged.values()];
921
931
  }
922
932
 
923
- export { OPFApiError, OPFExportError, OPFImportError, OPFMoveToCustomError, asApiError, copySlides, edit, embed, fill, fillRecords, moveToCustom, parseSlideSelection, sameRecord, stats, updateFromCatalog };
933
+ export { OPFApiError, OPFExportError, OPFImportError, OPFMoveToCustomError, asApiError, copySlides, edit, embed, fill, fillRecords, localAssetSources, moveToCustom, parseSlideSelection, sameRecord, stats, updateFromCatalog };
@@ -1,5 +1,5 @@
1
- import { OPFApiError } from './chunk-52GKVP3I.js';
2
- import { CATALOG_SCHEMA } from './chunk-2M7U4WL3.js';
1
+ import { OPFApiError } from './chunk-MAJHCGOW.js';
2
+ import { CATALOG_SCHEMA } from './chunk-23MOKE4B.js';
3
3
  import { CATALOG_SCHEMA as CATALOG_SCHEMA$1, gallery } from '@openpresentation/gallery';
4
4
 
5
5
  function galleryMismatch(declared, reads = CATALOG_SCHEMA) {
@@ -1,8 +1,8 @@
1
- import { fromMarkdown, toMarkdown } from './chunk-Z75YB54S.js';
2
- import { fromYaml, toYaml } from './chunk-IDMQWS6O.js';
3
- import { NOT_CHECKED } from './chunk-7PQZDC2H.js';
4
- import { parseSource, validate, OPFValidationError } from './chunk-2M7U4WL3.js';
5
- import { checkCatalogsOption } from './chunk-XAYMPBNE.js';
1
+ import { fromMarkdown, toMarkdown } from './chunk-SBWIZSPB.js';
2
+ import { fromYaml, toYaml } from './chunk-7XNAMCGT.js';
3
+ import { NOT_CHECKED } from './chunk-3T7MNRBY.js';
4
+ import { parseSource, validate, OPFValidationError } from './chunk-23MOKE4B.js';
5
+ import { checkCatalogsOption } from './chunk-VKNFZEMG.js';
6
6
 
7
7
  // src/deck-report.ts
8
8
  var DECK_FORMATS = ["json", "yaml", "markdown"];
@@ -1,8 +1,8 @@
1
- import { Ctx, splitLines, lineRange, readYamlMapping, NOT_CHECKED, OPFMarkdownError, writeYaml, readCsv, DECIMAL, csvField, scalarText } from './chunk-7PQZDC2H.js';
2
- import { parseQuoteLines, levelsFromIndents, parseCodeFence, splitWhen, fenceCode } from './chunk-V66KJA3H.js';
3
- import { same, isRecord, runText, isPlainRun, FORMATTING } from './chunk-TCBEF5OY.js';
4
- import { validate } from './chunk-2M7U4WL3.js';
5
- import { checkCatalogsOption, PROMOTED_REGION_KEY } from './chunk-XAYMPBNE.js';
1
+ import { Ctx, splitLines, lineRange, readYamlMapping, NOT_CHECKED, OPFMarkdownError, writeYaml, readCsv, DECIMAL, csvField, scalarText } from './chunk-3T7MNRBY.js';
2
+ import { parseQuoteLines, levelsFromIndents, parseCodeFence, splitWhen, fenceCode } from './chunk-KUNXFN7B.js';
3
+ import { same, isRecord, runText, isPlainRun, FORMATTING } from './chunk-2SENTA2R.js';
4
+ import { validate } from './chunk-23MOKE4B.js';
5
+ import { checkCatalogsOption, PROMOTED_REGION_KEY } from './chunk-VKNFZEMG.js';
6
6
 
7
7
  // src/markdown/canon.ts
8
8
  var FORMAT_KEYS = FORMATTING;
@@ -1,4 +1,4 @@
1
- import { chartNumber } from './chunk-XAYMPBNE.js';
1
+ import { chartNumber } from './chunk-VKNFZEMG.js';
2
2
 
3
3
  // src/data.ts
4
4
  var OPFDataImportError = class extends Error {