@openpresentation/opf 0.17.0 → 0.18.3

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 (67) hide show
  1. package/README.md +4 -4
  2. package/dist/browser.js +38 -0
  3. package/dist/{catalog-refs-C4K4y-vh.d.ts → catalog-refs-BSfGELpt.d.ts} +1 -1
  4. package/dist/{catalog-schemas-g7RFQBdc.d.ts → catalog-schemas-CinPh5WA.d.ts} +1 -1
  5. package/dist/catalog.d.ts +2 -2
  6. package/dist/{chart-data-DTxdRRT1.d.ts → chart-data-BnNqgnC-.d.ts} +1 -1
  7. package/dist/{chunk-RA64UQKI.js → chunk-2PEWUUBR.js} +97 -73
  8. package/dist/{chunk-TCD2FB2K.js → chunk-ECP7QPGK.js} +5 -5
  9. package/dist/{chunk-O2CX5NEH.js → chunk-FO3WGS4R.js} +6 -5
  10. package/dist/{chunk-N4EVOFEA.js → chunk-GVOLSWAJ.js} +4 -4
  11. package/dist/{chunk-WWYWFVOI.js → chunk-IM337HP5.js} +151 -25
  12. package/dist/{chunk-YT7FMQER.js → chunk-JCOSZTOI.js} +1 -1
  13. package/dist/{chunk-IPW5BS3X.js → chunk-K5EG3UMS.js} +190 -172
  14. package/dist/{chunk-NLNYNBTS.js → chunk-KA3ZPFVT.js} +84 -26
  15. package/dist/{chunk-M4UR3NPN.js → chunk-L5YACLWK.js} +2 -2
  16. package/dist/{chunk-CW7GEAV3.js → chunk-MBU42S5Y.js} +291 -133
  17. package/dist/{chunk-BIC3SWPK.js → chunk-MSFE2HUK.js} +30 -5
  18. package/dist/{chunk-ESRYBYLY.js → chunk-PNINP5IF.js} +1 -1
  19. package/dist/{chunk-IS5H5JKH.js → chunk-R7KIASS4.js} +1 -1
  20. package/dist/{chunk-PPROJP2E.js → chunk-TRELE6I6.js} +1 -1
  21. package/dist/{chunk-O3CVNJTL.js → chunk-WHHLGDCQ.js} +1 -1
  22. package/dist/{chunk-O263APNI.js → chunk-ZCFSDSUX.js} +3 -3
  23. package/dist/{composition-BbZ_9C-c.d.ts → composition-C-OoqvAr.d.ts} +80 -40
  24. package/dist/composition.d.ts +3 -3
  25. package/dist/composition.js +1 -1
  26. package/dist/conversion-4CLOEG6O.js +21 -0
  27. package/dist/{conversion-SBpTOwdg.d.ts → conversion-BxZbBd_0.d.ts} +96 -38
  28. package/dist/convert.d.ts +4 -4
  29. package/dist/convert.js +7 -7
  30. package/dist/data.d.ts +7 -7
  31. package/dist/data.js +2 -2
  32. package/dist/{deck-report-Bx3naFlF.d.ts → deck-report-DiDf_Vew.d.ts} +5 -5
  33. package/dist/deck.d.ts +8 -8
  34. package/dist/deck.js +10 -10
  35. package/dist/diff.d.ts +1 -1
  36. package/dist/diff.js +5 -5
  37. package/dist/docs.js +35 -29
  38. package/dist/examples.d.ts +1 -1
  39. package/dist/examples.js +181 -214
  40. package/dist/{finding-CDQ_wH8j.d.ts → finding-CT_f_vbD.d.ts} +1 -1
  41. package/dist/format.js +2 -2
  42. package/dist/index.d.ts +153 -20
  43. package/dist/index.js +62 -15
  44. package/dist/markdown.d.ts +12 -8
  45. package/dist/markdown.js +7 -7
  46. package/dist/node-engine.d.ts +37 -17
  47. package/dist/node-engine.js +39 -16
  48. package/dist/{pagination-BhX4M48Y.d.ts → pagination-BaUjDrTz.d.ts} +7 -4
  49. package/dist/pagination.d.ts +4 -4
  50. package/dist/pagination.js +4 -4
  51. package/dist/patch.d.ts +1 -1
  52. package/dist/patch.js +4 -4
  53. package/dist/{presentation-fb8CZmRq.d.ts → presentation-81rNihF0.d.ts} +271 -384
  54. package/dist/repo-readme.js +1 -1
  55. package/dist/schemas.d.ts +4 -2
  56. package/dist/schemas.js +1 -1
  57. package/dist/spec/README.md +1 -1
  58. package/dist/spec/schemas/opf.schema.json +67 -72
  59. package/dist/types.d.ts +3 -3
  60. package/dist/{validation-types-iZbXfES6.d.ts → validation-types-PbGDrNUr.d.ts} +12 -7
  61. package/dist/validator.d.ts +8 -8
  62. package/dist/validator.js +3 -3
  63. package/dist/yaml.d.ts +6 -6
  64. package/dist/yaml.js +7 -7
  65. package/package.json +14 -12
  66. package/dist/node.d.ts +0 -60
  67. package/dist/node.js +0 -54
@@ -1,6 +1,58 @@
1
- import { isRecord, visitContentPayloads, listVariables, resolveDesignRecords, resolveFontFamilies, resolveCanvasDimensions, imageBackground } from './chunk-CW7GEAV3.js';
1
+ import { OPFDataImportError, parseTabularData } from './chunk-ZCFSDSUX.js';
2
+ import { applyPatchWithInverse } from './chunk-WHHLGDCQ.js';
3
+ import { validate, OPFValidationError } from './chunk-KA3ZPFVT.js';
4
+ import { isRecord, visitContentPayloads, listVariables, resolveVariables, LOGO_SHAPES, resolveDesignRecords, resolveFontFamilies, resolveCanvasDimensions, imageBackground } from './chunk-MBU42S5Y.js';
2
5
  import { embeddedCopy, checkCatalogsOption, catalogReferenceSites, parseReference, catalogGroupDeclared, resolveReference, dottedPath, unresolvedReference, recordReferenceSites, catalogGroupSource, registeredCatalog, catalogKinds, CATALOG_GROUP_PATTERN } from './chunk-SPFV27O5.js';
3
6
 
7
+ // src/api-errors.ts
8
+ var OPFApiError = class extends Error {
9
+ code;
10
+ details;
11
+ findings;
12
+ constructor(message, code, extra = {}) {
13
+ super(message, extra.cause === void 0 ? void 0 : { cause: extra.cause });
14
+ this.name = new.target.name;
15
+ this.code = code;
16
+ this.details = extra.details ?? {};
17
+ this.findings = extra.findings ?? [];
18
+ }
19
+ };
20
+ var OPFExportError = class extends OPFApiError {
21
+ };
22
+ var OPFImportError = class extends OPFApiError {
23
+ };
24
+ function asApiError(Class, error, fallbackCode) {
25
+ if (error instanceof Class) return error;
26
+ if (error instanceof OPFApiError) return new Class(error.message, error.code, { details: error.details, findings: error.findings, cause: error });
27
+ const failure = error;
28
+ return new Class(failure?.message ?? String(error), typeof failure?.code === "string" ? failure.code : fallbackCode, { cause: error });
29
+ }
30
+
31
+ // src/slide-selection.ts
32
+ var isSlideNumber = (value) => typeof value === "number" && Number.isInteger(value) && value >= 1;
33
+ function parseSlideSelection(selection, total, label = "slides") {
34
+ if (!(total >= 1)) throw new OPFApiError("The presentation has no slides.", "no-slides");
35
+ const listed = typeof selection === "number" ? [selection] : Array.isArray(selection) ? selection : void 0;
36
+ if (listed) {
37
+ const bad = listed.find((value) => !isSlideNumber(value));
38
+ if (bad !== void 0 || listed.length === 0) throw new OPFApiError(`${label} needs slide numbers counted from 1 (got ${JSON.stringify(bad ?? listed)}).`, "invalid-option");
39
+ } else if (typeof selection !== "string") throw new OPFApiError(`${label} needs a slide number, a list of numbers or text like "1,3-5".`, "invalid-option");
40
+ const spec = listed ? listed.join(",") : selection;
41
+ const chosen = /* @__PURE__ */ new Set();
42
+ for (const part of spec.split(",")) {
43
+ const text = part.trim();
44
+ const match = /^(\d*)(-?)(\d*)$/.exec(text);
45
+ if (!text || !match || !match[1] && !match[3]) throw new OPFApiError(`${label} needs numbers like 1,3-5 (got "${spec}").`, "invalid-option");
46
+ const [, from, dash, to] = match;
47
+ const first = from ? Number(from) : 1;
48
+ const last = dash ? to ? Number(to) : total : first;
49
+ if (first < 1 || last < first) throw new OPFApiError(`${label} range "${text}" is not valid (slides count from 1).`, "invalid-option");
50
+ if (last > total) throw new OPFApiError(`${label} ${text} is outside the presentation, which has ${total} slide${total === 1 ? "" : "s"}.`, "invalid-option");
51
+ for (let n = first; n <= last; n++) chosen.add(n);
52
+ }
53
+ return [...chosen].sort((a, b) => a - b);
54
+ }
55
+
4
56
  // src/catalog-helpers.ts
5
57
  var isRec = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
6
58
  var rec = (value) => isRec(value) ? value : {};
@@ -294,9 +346,8 @@ function moveToCustom(document, ref, options = {}) {
294
346
  // src/stats.ts
295
347
  var DEFAULT_WORDS_PER_MINUTE = 130;
296
348
  var KIND_ORDER = ["text", "items", "bullets", "quote", "metric", "code", "timeline", "chart", "table", "image", "video"];
297
- var FURNITURE_FIELDS = ["logo", "image", "text", "socials", "date"];
349
+ var FURNITURE_FIELDS = ["image", "text", "socials", "date"];
298
350
  var ZONES = ["left", "center", "right"];
299
- var LOGO_VARIANTS = ["default", "light", "dark", "stacked", "stackedLight", "stackedDark", "icon", "iconLight", "iconDark", "wordmark", "wordmarkLight", "wordmarkDark"];
300
351
  var WORD = /[\p{L}\p{N}\p{M}]+(?:['’.,-][\p{L}\p{N}\p{M}]+)*/gu;
301
352
  var UNSPACED = /[฀-໿က-႟ក-៿぀-ヿ㐀-䶿一-鿿豈-﫿]/gu;
302
353
  var wordCount = (text) => {
@@ -417,7 +468,7 @@ function stats(presentation2, options = {}) {
417
468
  const images = { content: { total: 0, withAlt: 0, decorative: 0, missingAlt: 0 }, logos: 0, watermarks: { deck: false, slides: 0 }, backgrounds: { deck: false, slides: 0 }, headerFooter: 0, speakerPhotos: 0, videos: 0 };
418
469
  const contentImage = (asset) => {
419
470
  if (srcOf(asset) === void 0) return 0;
420
- useAsset(asset);
471
+ if (!String(srcOf(asset)).startsWith("var:organization.")) useAsset(asset);
421
472
  images.content.total++;
422
473
  const alt = altOf(asset);
423
474
  if (alt === void 0 || alt !== "" && alt.trim() === "") images.content.missingAlt++;
@@ -425,18 +476,14 @@ function stats(presentation2, options = {}) {
425
476
  else images.content.withAlt++;
426
477
  return 1;
427
478
  };
428
- const logoImages = (value) => {
429
- if (srcOf(value) !== void 0) {
430
- useAsset(value);
431
- images.logos++;
432
- return;
433
- }
434
- if (isRecord(value)) {
435
- for (const variant of LOGO_VARIANTS) if (srcOf(value[variant]) !== void 0) {
436
- useAsset(value[variant]);
437
- images.logos++;
438
- }
439
- }
479
+ const logoAssets = (value) => {
480
+ if (srcOf(value) !== void 0) return [value];
481
+ if (!isRecord(value)) return [];
482
+ return LOGO_SHAPES.flatMap((shape) => {
483
+ const entry = value[shape];
484
+ if (srcOf(entry) !== void 0) return [entry];
485
+ return isRecord(entry) ? [entry.onLight, entry.onDark].filter((tone2) => srcOf(tone2) !== void 0) : [];
486
+ });
440
487
  };
441
488
  const watermarkOf = (value) => {
442
489
  if (value === void 0 || value === false) return false;
@@ -453,15 +500,13 @@ function stats(presentation2, options = {}) {
453
500
  if (!isRecord(value)) return;
454
501
  for (const zone of ZONES) {
455
502
  const item = value[zone];
456
- if (isRecord(item) && srcOf(item.image) !== void 0) {
457
- useAsset(item.image);
458
- images.headerFooter++;
459
- }
503
+ if (!isRecord(item) || srcOf(item.image) === void 0) continue;
504
+ if (!String(srcOf(item.image)).startsWith("var:organization.")) useAsset(item.image);
505
+ images.headerFooter++;
460
506
  }
461
507
  };
462
508
  const designAssets = (value, scope) => {
463
509
  if (!isRecord(value)) return;
464
- logoImages(value.logo);
465
510
  if (watermarkOf(value.watermark)) {
466
511
  if (scope === "deck") images.watermarks.deck = true;
467
512
  else images.watermarks.slides++;
@@ -474,11 +519,12 @@ function stats(presentation2, options = {}) {
474
519
  furnitureImages(value.footer);
475
520
  };
476
521
  const organizations = list(deck.organization).filter(isRecord).map((entry) => {
477
- const hasLogo = srcOf(entry.logo) !== void 0;
478
- if (hasLogo) {
479
- useAsset(entry.logo);
522
+ const logos = logoAssets(entry.logo);
523
+ for (const logo of logos) {
524
+ useAsset(logo);
480
525
  images.logos++;
481
526
  }
527
+ const hasLogo = logos.length > 0;
482
528
  return { id: str(entry.id) ?? "", name: str(entry.name) ?? "", role: str(entry.role), hasLogo };
483
529
  });
484
530
  const speakers = list(deck.speaker).filter(isRecord).map((entry) => {
@@ -790,4 +836,84 @@ function stats(presentation2, options = {}) {
790
836
  return result;
791
837
  }
792
838
 
793
- export { OPFMoveToCustomError, copySlides, embed, moveToCustom, sameRecord, stats, updateFromCatalog };
839
+ // src/edit.ts
840
+ function edit(deck, patch, options = {}) {
841
+ const result = applyPatchWithInverse(deck, patch);
842
+ const presentation2 = result.presentation;
843
+ if (options.validate === false) return { presentation: presentation2, findings: [], inverse: result.inverse };
844
+ const report = validate(presentation2, { only: ["format", "references"], ...options.catalogs ? { catalogs: options.catalogs } : {} });
845
+ if (!report.valid) throw new OPFValidationError(report);
846
+ return { presentation: presentation2, findings: report.findings, inverse: result.inverse };
847
+ }
848
+
849
+ // src/fill.ts
850
+ var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
851
+ function fillRecords(raw, options = {}) {
852
+ const format2 = options.format ?? (/^[\s\uFEFF]*[[{]/.test(raw) ? "json" : "csv");
853
+ if (format2 === "json") {
854
+ let value;
855
+ try {
856
+ value = JSON.parse(raw.replace(/^\uFEFF/, ""));
857
+ } catch {
858
+ throw new OPFDataImportError("Invalid JSON data.");
859
+ }
860
+ if (isRecord2(value) && !("columns" in value && "rows" in value)) return [value];
861
+ if (Array.isArray(value) && value.length && value.every(isRecord2)) return value;
862
+ if (Array.isArray(value) && !value.length) throw new OPFDataImportError("Data contains no records.");
863
+ }
864
+ const table = parseTabularData(raw, { format: format2, header: options.header, delimiter: options.delimiter });
865
+ if (!table.rows.length) throw new OPFDataImportError("Data contains no records.");
866
+ return table.rows.map((row) => Object.fromEntries(table.columns.map((column, index) => [column, row[index] === "" ? null : row[index]])));
867
+ }
868
+ function fill(template, data, options = {}) {
869
+ if (!isRecord2(template)) throw new TypeError("fill expects a template object.");
870
+ const records = data === void 0 ? [{}] : typeof data === "string" ? fillRecords(data, options) : Array.isArray(data) ? [...data] : [data];
871
+ if (!records.length) throw new OPFDataImportError("Data contains no records.");
872
+ if (!records.every(isRecord2)) throw new OPFDataImportError("Each record must be an object keyed by variable id.");
873
+ const decks = records.map((record, offset) => ({ index: offset + 1, record, ...resolveVariables(template, record, { template: false, partial: options.partial === true, examples: options.examples === true }) }));
874
+ return {
875
+ decks: decks.map(({ index, record, presentation: presentation2, diagnostics, unfilled, complete }) => ({ index, record, presentation: presentation2, diagnostics, unfilled, complete })),
876
+ ...options.combine ? { presentation: combine(decks) } : {},
877
+ complete: decks.every((deck) => deck.complete),
878
+ unfilled: [...new Set(decks.flatMap((deck) => deck.unfilled))],
879
+ diagnostics: summarize(decks)
880
+ };
881
+ }
882
+ function combine(decks) {
883
+ const first = decks[0];
884
+ const seen = /* @__PURE__ */ new Set();
885
+ const slides = [];
886
+ const assets = {};
887
+ for (const deck of decks) {
888
+ for (const slide of Array.isArray(deck.presentation.slides) ? deck.presentation.slides : []) {
889
+ if (isRecord2(slide) && typeof slide.id === "string") {
890
+ let id = slide.id;
891
+ if (seen.has(id)) {
892
+ id = `${slide.id}-${deck.index}`;
893
+ for (let suffix = 2; seen.has(id); suffix++) id = `${slide.id}-${deck.index}-${suffix}`;
894
+ }
895
+ seen.add(id);
896
+ slides.push(id === slide.id ? slide : { ...slide, id });
897
+ } else slides.push(slide);
898
+ }
899
+ if (isRecord2(deck.presentation.assets)) {
900
+ for (const [key, value] of Object.entries(deck.presentation.assets)) if (!(key in assets)) assets[key] = value;
901
+ }
902
+ }
903
+ return { ...first.presentation, ...Object.keys(assets).length ? { assets } : {}, slides };
904
+ }
905
+ function summarize(decks) {
906
+ const merged = /* @__PURE__ */ new Map();
907
+ for (const deck of decks) {
908
+ for (const diagnostic of deck.diagnostics) {
909
+ if (diagnostic.severity === "info") continue;
910
+ const key = `${diagnostic.code}\0${diagnostic.id}\0${diagnostic.path}`;
911
+ const entry = merged.get(key);
912
+ if (entry) entry.records.push(deck.index);
913
+ else merged.set(key, { ...diagnostic, records: [deck.index] });
914
+ }
915
+ }
916
+ return [...merged.values()];
917
+ }
918
+
919
+ export { OPFApiError, OPFExportError, OPFImportError, OPFMoveToCustomError, asApiError, copySlides, edit, embed, fill, fillRecords, moveToCustom, parseSlideSelection, sameRecord, stats, updateFromCatalog };
@@ -1,4 +1,4 @@
1
- import { presentation } from './chunk-RA64UQKI.js';
1
+ import { presentation } from './chunk-2PEWUUBR.js';
2
2
 
3
3
  // src/format.ts
4
4
  var OPFFormatError = class extends Error {