@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,5 +1,5 @@
1
- import { promotedRegionKeys, VARIABLE_KINDS, resolveChartData, chartPaletteForFill, imageBackground, tableGrid, timelineTextColor, LOGO_SHAPES, visitContentPayloads, readingRows, visualReadingOrder, intrinsicImageSize, resolveReference, textWidthMeasurer, normalizeHexColor, resolveColorRef, resolveDesignRecords, resolveFontFamilies, checkCatalogsOption, provenanceOf, unresolvedReference, OPFUnresolvedReferenceError, resolveColorRoles, resolveCanvasDimensions, resolveSlideVariables, defaultSlideBackground, isRecord, hasContentVariables, isTemplate, instantiateForValidation, layoutTemplateIssues, resolveScriptFonts, catalogReferenceSites, parseReference, catalogGroupDeclared, pointerPath, unusedDatasets, MAX_COMPOSITION_DEPTH, datasetDiagnostics, pathFor, catalogRecords, collectCitations, numberingFindings, walkCitationRuns, resolveTableData, resolveChartOptions, chartOptionTarget, codeHighlightLines, chartNumberFixesByCell, catalogKinds, catalogGroupSource, registeredCatalog, OPFCompositionError, composeSlide } from './chunk-XAYMPBNE.js';
2
- import { schemaEntries, schemas } from './chunk-VFMHM2IL.js';
1
+ import { promotedRegionKeys, VARIABLE_KINDS, resolveChartData, chartPaletteForFill, chartSeriesPalette, normalizeHexColor, resolveChartColors, colorContrast, imageBackground, tableGrid, timelineTextColor, LOGO_SHAPES, visitContentPayloads, readingRows, visualReadingOrder, intrinsicImageSize, resolveReference, textWidthMeasurer, resolveColorRef, resolveDesignRecords, resolveFontFamilies, checkCatalogsOption, provenanceOf, unresolvedReference, OPFUnresolvedReferenceError, resolveColorRoles, resolveCanvasDimensions, resolveSlideVariables, defaultSlideBackground, isRecord, hasContentVariables, isTemplate, instantiateForValidation, layoutTemplateIssues, resolveScriptFonts, catalogReferenceSites, parseReference, catalogGroupDeclared, pointerPath, unusedDatasets, MAX_COMPOSITION_DEPTH, datasetDiagnostics, pathFor, catalogRecords, collectCitations, numberingFindings, walkCitationRuns, resolveTableData, resolveChartOptions, chartOptionTarget, codeHighlightLines, chartNumberFixesByCell, catalogKinds, catalogGroupSource, registeredCatalog, OPFCompositionError, composeSlide } from './chunk-VKNFZEMG.js';
2
+ import { schemas, schemaEntries } from './chunk-3UAVON3O.js';
3
3
  import Ajv2020 from 'ajv/dist/2020.js';
4
4
  import addFormats from 'ajv-formats';
5
5
  import { parseTree, printParseErrorCode, getNodePath } from 'jsonc-parser';
@@ -87,6 +87,125 @@ function unusedReferenceWarnings(value) {
87
87
  return value.references.flatMap((reference, index) => isRecord(reference) && typeof reference.id === "string" && unused.includes(reference.id) ? [issue(`/references/${index}`, `reference '${reference.id}' is never cited; cite it with a run's cite field or remove it`, { code: "unused-reference", id: reference.id })] : []);
88
88
  }
89
89
 
90
+ // src/union-errors.ts
91
+ var compiled = /* @__PURE__ */ new WeakMap();
92
+ var origin = /* @__PURE__ */ new WeakMap();
93
+ var isUnion = (error) => (error.keyword === "oneOf" || error.keyword === "anyOf") && Array.isArray(error.schema);
94
+ var key = (error) => `${error.instancePath}\0${error.keyword}\0${error.message}\0${JSON.stringify(error.params)}`;
95
+ var depth = (pointer4) => pointer4 ? pointer4.split("/").length - 1 : 0;
96
+ var original = (node) => {
97
+ let current = node;
98
+ while (current && typeof current === "object" && origin.has(current)) current = origin.get(current);
99
+ return current;
100
+ };
101
+ function qualify(node, rootId) {
102
+ if (Array.isArray(node)) {
103
+ const copy = node.map((item) => qualify(item, rootId));
104
+ origin.set(copy, node);
105
+ return copy;
106
+ }
107
+ if (node && typeof node === "object") {
108
+ const copy = {};
109
+ for (const [name, value] of Object.entries(node)) copy[name] = name === "$ref" && typeof value === "string" && value.startsWith("#") ? rootId + value : qualify(value, rootId);
110
+ origin.set(copy, node);
111
+ return copy;
112
+ }
113
+ return node;
114
+ }
115
+ function branchValidator(ajv2, rootId, branch) {
116
+ let validate2 = compiled.get(branch);
117
+ if (!validate2) {
118
+ validate2 = ajv2.compile(qualify(branch, rootId));
119
+ compiled.set(branch, validate2);
120
+ }
121
+ return validate2;
122
+ }
123
+ function branchLabel(branch, index) {
124
+ if (typeof branch.$ref === "string") return branch.$ref.slice(branch.$ref.lastIndexOf("/") + 1);
125
+ if (typeof branch.type === "string") return branch.type;
126
+ if (Array.isArray(branch.type)) return branch.type.join("|");
127
+ if ("const" in branch) return JSON.stringify(branch.const);
128
+ return `option ${index + 1}`;
129
+ }
130
+ function describe(errors, base) {
131
+ const types = [...new Set(errors.filter((error) => depth(error.instancePath) === base && error.keyword === "type").flatMap((error) => [error.params.type].flat()))];
132
+ if (types.length) return `must be ${types.join(" or ")}`;
133
+ const shallow = [...errors].filter((error) => !isUnion(error) || errors.every(isUnion)).sort((a, b) => depth(a.instancePath) - depth(b.instancePath))[0];
134
+ if (!shallow) return "does not match";
135
+ const rest = shallow.instancePath.split("/").slice(base + 1).join("/");
136
+ return depth(shallow.instancePath) === base || !rest ? shallow.message ?? "does not match" : `${shallow.message} at /${rest}`;
137
+ }
138
+ function bestMatchErrors(ajv2, rootId, errors) {
139
+ const unions = errors.filter(isUnion);
140
+ if (!unions.length) return errors;
141
+ const analyses = [];
142
+ for (const union of unions) {
143
+ const analysis = analyze(ajv2, rootId, union);
144
+ if (analysis) analyses.push(analysis);
145
+ }
146
+ if (!analyses.length) return errors;
147
+ const within = (inner, other) => other !== inner && [...inner.span].every((entry) => other.span.has(entry)) && (other.span.size > inner.span.size || errors.indexOf(other.union) > errors.indexOf(inner.union));
148
+ const outer = analyses.filter((analysis) => !analyses.some((other) => within(analysis, other)));
149
+ const replaced = new Map(outer.map((analysis) => [analysis.union, analysis]));
150
+ const drop = new Set(outer.flatMap((analysis) => [...analysis.span]));
151
+ const result = [];
152
+ for (const error of errors) {
153
+ const analysis = replaced.get(error);
154
+ if (analysis) result.push(...analysis.replacement);
155
+ else if (!drop.has(key(error))) result.push(error);
156
+ }
157
+ return result;
158
+ }
159
+ function analyze(ajv2, rootId, union) {
160
+ const branches = union.schema;
161
+ const base = depth(union.instancePath);
162
+ const results = [];
163
+ for (const [index, branch] of branches.entries()) {
164
+ if (!branch || typeof branch !== "object") return void 0;
165
+ const validate2 = branchValidator(ajv2, rootId, branch);
166
+ if (validate2(union.data) === true) return void 0;
167
+ const raw = (validate2.errors ?? []).map((error) => ({ ...error, instancePath: union.instancePath + error.instancePath }));
168
+ results.push({ label: branchLabel(branch, index), errors: raw });
169
+ }
170
+ const span = /* @__PURE__ */ new Set([key(union), ...results.flatMap((result) => result.errors.map(key))]);
171
+ const reduced = results.map((result) => ({ label: result.label, errors: bestMatchErrors(ajv2, rootId, result.errors) }));
172
+ const mismatch = (error) => {
173
+ const level = depth(error.instancePath) - base;
174
+ return level === 0 && (error.keyword === "type" || isUnion(error)) || level === 1 && error.keyword === "const";
175
+ };
176
+ const matched = reduced.filter((result) => result.errors.length && !result.errors.some(mismatch));
177
+ const reach = (errors) => Math.min(...errors.map((error) => depth(error.instancePath)));
178
+ const ranked = [...matched].sort((a, b) => reach(b.errors) - reach(a.errors));
179
+ const summary = (list) => list.map((result) => `${result.label}: ${describe(result.errors, base)}`);
180
+ const named = (list) => list.length > 1 ? `${list.slice(0, -1).join(", ")} or ${list.at(-1)}` : list[0] ?? "";
181
+ const lead = ranked[0];
182
+ if (!lead) {
183
+ const rootTypes = reduced.map((result) => result.errors.filter((error) => depth(error.instancePath) === base && error.keyword === "type"));
184
+ const plain = rootTypes.every((list, index) => list.length === reduced[index]?.errors.length && list.length > 0);
185
+ const types = [...new Set(rootTypes.flatMap((list) => list.flatMap((error) => [error.params.type].flat())))].map(String);
186
+ return { union, span, replacement: [{ ...union, message: plain ? `must be ${named(types)}` : union.message, alternatives: summary(reduced) }] };
187
+ }
188
+ const top = ranked.filter((result) => reach(result.errors) === reach(lead.errors));
189
+ const others = reduced.filter((result) => !top.includes(result));
190
+ const single = (result) => {
191
+ const only = result.errors[0];
192
+ return result.errors.length === 1 && only && depth(only.instancePath) === base ? only : void 0;
193
+ };
194
+ const singles = top.map(single);
195
+ const keyword = singles[0]?.keyword;
196
+ if (top.length > 1 && (keyword === "format" || keyword === "required") && singles.every((error) => error?.keyword === keyword)) {
197
+ const values = singles.map((error) => JSON.stringify(keyword === "format" ? error?.params.format : error?.params.missingProperty).replace(/^"|"$/g, keyword === "format" ? '"' : "'"));
198
+ const message = keyword === "format" ? `must match format ${named(values)}` : `must have required property ${named(values)}`;
199
+ return { union, span, replacement: [{ ...singles[0], message, alternatives: summary(top) }] };
200
+ }
201
+ const chosen = top.flatMap((result) => result.errors).map((error, index) => {
202
+ const mapped = { ...error, parentSchema: original(error.parentSchema), schema: original(error.schema) };
203
+ if (index === 0 && others.length) mapped.alternatives = summary(others);
204
+ return mapped;
205
+ });
206
+ return { union, span, replacement: chosen };
207
+ }
208
+
90
209
  // src/validation-definitions.ts
91
210
  var schemaLocations;
92
211
  var issueLocations = /* @__PURE__ */ new WeakMap();
@@ -107,8 +226,8 @@ function rememberValidationDefinition(issue2, parentSchema, keyword) {
107
226
  pointer: current.pointer,
108
227
  uri: `${entry.schema.$id}#${current.pointer}`
109
228
  });
110
- for (const [key, value] of Object.entries(current.value)) {
111
- const segment = key.replaceAll("~", "~0").replaceAll("/", "~1");
229
+ for (const [key2, value] of Object.entries(current.value)) {
230
+ const segment = key2.replaceAll("~", "~0").replaceAll("/", "~1");
112
231
  stack.push({ value, pointer: `${current.pointer}/${segment}` });
113
232
  }
114
233
  }
@@ -254,7 +373,8 @@ function toIssue(error) {
254
373
  message: slideDimensions ? "a slide's design cannot set 'dimensions': a PPTX has one slide size, so set design.dimensions on the deck (or its theme)" : error.message ?? "failed validation",
255
374
  keyword: error.keyword,
256
375
  schemaPath: error.schemaPath,
257
- params: error.params
376
+ params: error.params,
377
+ ...error.alternatives?.length ? { alternatives: error.alternatives } : {}
258
378
  };
259
379
  rememberValidationDefinition(issue2, error.parentSchema, error.keyword);
260
380
  return issue2;
@@ -268,8 +388,8 @@ function semanticIssue(path, message, params = {}) {
268
388
  params
269
389
  };
270
390
  }
271
- function hasOwn(value, key) {
272
- return Object.hasOwn(value, key);
391
+ function hasOwn(value, key2) {
392
+ return Object.hasOwn(value, key2);
273
393
  }
274
394
  function isEnUkTag(value) {
275
395
  return typeof value === "string" && value.toLowerCase() === "en-uk";
@@ -391,20 +511,20 @@ function validateContentPayload(value, path, options = {}) {
391
511
  }
392
512
  return issues;
393
513
  }
394
- function slideRegion(key) {
395
- if (key.includes(":")) {
396
- const [rowPart, columnPart] = key.split(":");
514
+ function slideRegion(key2) {
515
+ if (key2.includes(":")) {
516
+ const [rowPart, columnPart] = key2.split(":");
397
517
  if (!rowPart || !columnPart) return void 0;
398
518
  const rows = rowSpans[rowPart];
399
519
  const columns = columnSpans[columnPart];
400
520
  return rows && columns ? { rows, columns } : void 0;
401
521
  }
402
- if (key in columnSpans) {
403
- const columns = columnSpans[key];
522
+ if (key2 in columnSpans) {
523
+ const columns = columnSpans[key2];
404
524
  return columns ? { rows: [0, 1, 2], columns } : void 0;
405
525
  }
406
- if (key in rowSpans) {
407
- const rows = rowSpans[key];
526
+ if (key2 in rowSpans) {
527
+ const rows = rowSpans[key2];
408
528
  return rows ? { rows, columns: [0, 1, 2] } : void 0;
409
529
  }
410
530
  return void 0;
@@ -417,7 +537,7 @@ function regionsOverlap(left, right) {
417
537
  }
418
538
  function validateSlideRegions(slide, slidePath) {
419
539
  const issues = [];
420
- const regionKeys = Object.keys(slide).filter((key) => promotedRegionKeySet.has(key));
540
+ const regionKeys = Object.keys(slide).filter((key2) => promotedRegionKeySet.has(key2));
421
541
  const rootFields = presentFields(slide, rootPayloadFields);
422
542
  if (regionKeys.length > 0 && rootFields.length > 0) {
423
543
  issues.push(semanticIssue(slidePath, "root content payload fields cannot be mixed with promoted region keys", {
@@ -428,10 +548,10 @@ function validateSlideRegions(slide, slidePath) {
428
548
  if (regionKeys.length === 0 && rootFields.length > 0) {
429
549
  issues.push(...validateContentPayload(slide, slidePath, { slideRoot: true }));
430
550
  }
431
- for (const key of regionKeys) {
432
- const value = slide[key];
551
+ for (const key2 of regionKeys) {
552
+ const value = slide[key2];
433
553
  if (isRecord(value)) {
434
- issues.push(...validateContentPayload(value, pathFor(slidePath, key)));
554
+ issues.push(...validateContentPayload(value, pathFor(slidePath, key2)));
435
555
  }
436
556
  }
437
557
  for (let leftIndex = 0; leftIndex < regionKeys.length; leftIndex += 1) {
@@ -455,19 +575,19 @@ function validateSlideRegions(slide, slidePath) {
455
575
  }
456
576
  function deckMetadataIssues(value) {
457
577
  const issues = [];
458
- const entries = (key) => {
459
- const field = value[key];
460
- if (Array.isArray(field)) return field.flatMap((entry, index) => isRecord(entry) ? [{ entry, path: `/${key}/${index}` }] : []);
461
- return isRecord(field) ? [{ entry: field, path: `/${key}` }] : [];
578
+ const entries = (key2) => {
579
+ const field = value[key2];
580
+ if (Array.isArray(field)) return field.flatMap((entry, index) => isRecord(entry) ? [{ entry, path: `/${key2}/${index}` }] : []);
581
+ return isRecord(field) ? [{ entry: field, path: `/${key2}` }] : [];
462
582
  };
463
583
  const organizationIds = /* @__PURE__ */ new Set();
464
- for (const key of ["organization", "speaker"]) {
584
+ for (const key2 of ["organization", "speaker"]) {
465
585
  const seen = /* @__PURE__ */ new Set();
466
- for (const { entry, path } of entries(key)) {
586
+ for (const { entry, path } of entries(key2)) {
467
587
  if (typeof entry.id !== "string") continue;
468
- if (seen.has(entry.id)) issues.push(semanticIssue(`${path}/id`, `${key} ids must be unique within a presentation`, { id: entry.id }));
588
+ if (seen.has(entry.id)) issues.push(semanticIssue(`${path}/id`, `${key2} ids must be unique within a presentation`, { id: entry.id }));
469
589
  seen.add(entry.id);
470
- if (key === "organization") organizationIds.add(entry.id);
590
+ if (key2 === "organization") organizationIds.add(entry.id);
471
591
  }
472
592
  }
473
593
  for (const { entry, path } of entries("speaker")) {
@@ -621,9 +741,9 @@ function dataIssues(value) {
621
741
  const seen = /* @__PURE__ */ new Set();
622
742
  const add = (diagnostics) => {
623
743
  for (const diagnostic of diagnostics) {
624
- const key = `${diagnostic.code}|${diagnostic.path}`;
625
- if (seen.has(key)) continue;
626
- seen.add(key);
744
+ const key2 = `${diagnostic.code}|${diagnostic.path}`;
745
+ if (seen.has(key2)) continue;
746
+ seen.add(key2);
627
747
  (diagnostic.severity === "error" ? out.errors : out.warnings).push(semanticIssue(diagnostic.path, diagnostic.message, { code: diagnostic.code }));
628
748
  }
629
749
  };
@@ -808,9 +928,9 @@ function presentationReferenceWarnings(value, catalogs) {
808
928
  };
809
929
  highlightWarnings(slide, slidePath);
810
930
  visitContentPayloads(slide, slidePath, highlightWarnings);
811
- for (const key of Object.keys(slide)) {
812
- if (promotedRegionKeySet.has(key)) {
813
- issues.push(...chartTypeWarnings(slide[key], pathFor(slidePath, key)));
931
+ for (const key2 of Object.keys(slide)) {
932
+ if (promotedRegionKeySet.has(key2)) {
933
+ issues.push(...chartTypeWarnings(slide[key2], pathFor(slidePath, key2)));
814
934
  }
815
935
  }
816
936
  });
@@ -835,7 +955,7 @@ function contentDepthIssues(value) {
835
955
  if (Array.isArray(slide.blocks)) slide.blocks.forEach((block, i) => {
836
956
  stack.push({ value: block, path: `/slides/${index}/blocks/${i}`, depth: 0, ancestors: [] });
837
957
  });
838
- for (const key of promotedRegionKeys) if (hasOwn(slide, key)) stack.push({ value: slide[key], path: `/slides/${index}/${key}`, depth: 0, ancestors: [] });
958
+ for (const key2 of promotedRegionKeys) if (hasOwn(slide, key2)) stack.push({ value: slide[key2], path: `/slides/${index}/${key2}`, depth: 0, ancestors: [] });
839
959
  });
840
960
  while (stack.length) {
841
961
  const entry = stack.pop();
@@ -890,9 +1010,9 @@ function typedVariableErrors(errors, value) {
890
1010
  function pointerValue(root, pointer4) {
891
1011
  let current = root;
892
1012
  for (const token of pointer4.split("/").slice(1)) {
893
- const key = token.replaceAll("~1", "/").replaceAll("~0", "~");
894
- if (Array.isArray(current)) current = current[Number(key)];
895
- else if (isRecord(current) && hasOwn(current, key)) current = current[key];
1013
+ const key2 = token.replaceAll("~1", "/").replaceAll("~0", "~");
1014
+ if (Array.isArray(current)) current = current[Number(key2)];
1015
+ else if (isRecord(current) && hasOwn(current, key2)) current = current[key2];
896
1016
  else return void 0;
897
1017
  }
898
1018
  return current;
@@ -955,7 +1075,8 @@ function validateAgainstSchema(value, schemaOrKind = "presentation", options = {
955
1075
  }
956
1076
  const valid = resolved.validate(subject) === true;
957
1077
  const ajvErrors = valid ? [] : typedVariableErrors(resolved.validate.errors ?? [], subject);
958
- const mapped = (resolved.schemaName === "presentation" ? dataUnionErrors(ajvErrors, subject) : ajvErrors).map(toIssue);
1078
+ const specific = resolved.schemaName === "presentation" ? dataUnionErrors(ajvErrors, subject) : ajvErrors;
1079
+ const mapped = bestMatchErrors(getAjv(), schemas[resolved.schemaName].$id, specific).map(toIssue);
959
1080
  const errors = mapped;
960
1081
  if (resolved.schemaName === "layout" && valid) for (const issue2 of layoutTemplateIssues(subject)) errors.push(semanticIssue(issue2.path, issue2.message, { code: issue2.code }));
961
1082
  const warnings = [];
@@ -1283,20 +1404,6 @@ function readableColor(candidates, sample, minimum) {
1283
1404
  if (worstContrast(candidate, sample).ratio >= minimum) return candidate;
1284
1405
  return void 0;
1285
1406
  }
1286
- var DEFAULT_CHART_PALETTE = [
1287
- "#2874A6",
1288
- "#1B4F72",
1289
- "#5499C7",
1290
- "#7BDBB2",
1291
- "#3AC67A",
1292
- "#24A89E",
1293
- "#F59E0B",
1294
- "#EF4444",
1295
- "#8B5CF6",
1296
- "#14B8A6",
1297
- "#0F172A",
1298
- "#64748B"
1299
- ];
1300
1407
 
1301
1408
  // src/rule-content.ts
1302
1409
  var pointer2 = (...parts2) => parts2.length ? "/" + parts2.map((part) => String(part).replaceAll("~", "~0").replaceAll("/", "~1")).join("/") : "";
@@ -1356,9 +1463,9 @@ function textValues(slide, slidePath) {
1356
1463
  const metric = node.metric;
1357
1464
  if (typeof metric === "string") push(at2("metric"), metric, "metric", "metric");
1358
1465
  else if (metric && typeof metric === "object")
1359
- for (const key of ["value", "label", "unit", "delta"]) {
1360
- const value = metric[key];
1361
- if (typeof value === "string") push(at2("metric", key), value, "metric", "metric");
1466
+ for (const key2 of ["value", "label", "unit", "delta"]) {
1467
+ const value = metric[key2];
1468
+ if (typeof value === "string") push(at2("metric", key2), value, "metric", "metric");
1362
1469
  }
1363
1470
  const timeline = node.timeline, events = Array.isArray(timeline) ? timeline : Array.isArray(rec(timeline).events) ? rec(timeline).events : [];
1364
1471
  if (typeof rec(timeline).name === "string") push(at2("timeline", "name"), rec(timeline).name, "timeline", "timeline");
@@ -1595,8 +1702,8 @@ var contrastRules = [
1595
1702
  }
1596
1703
  continue;
1597
1704
  }
1598
- const key = `${sample.source === "default" ? "default" : sample.path}|${sample.color}|${worst.against}|${large}`;
1599
- const known = aggregated.get(key);
1705
+ const key2 = `${sample.source === "default" ? "default" : sample.path}|${sample.color}|${worst.against}|${large}`;
1706
+ const known = aggregated.get(key2);
1600
1707
  if (known && sample.source === "default") {
1601
1708
  known.extra++;
1602
1709
  continue;
@@ -1617,7 +1724,7 @@ var contrastRules = [
1617
1724
  measured: { ratio: round(worst.ratio), needed, large, sizePt: round(sample.sizePx * PX_TO_PT), textColor: sample.color, backgroundColor: worst.against },
1618
1725
  fixes
1619
1726
  });
1620
- if (sample.source === "default") aggregated.set(key, { diagnostic, extra: 0 });
1727
+ if (sample.source === "default") aggregated.set(key2, { diagnostic, extra: 0 });
1621
1728
  }
1622
1729
  for (const { diagnostic, extra } of aggregated.values())
1623
1730
  if (extra) {
@@ -1893,7 +2000,7 @@ var chartColorRule = rule(
1893
2000
  {
1894
2001
  standard: "WCAG 2.2 SC 1.4.1 Use of Color, level A",
1895
2002
  thresholds: ["minSeriesColorDifference"],
1896
- approximations: "Uses the engine's series palette (ValidateOptions.chartPalette; default the opf-render/opf-pptx palette, adjusted for the card surface like the preview does) in series order: series i takes colour i, pie/doughnut/treemap/funnel slices take colours per category. Pairs are compared by CIE76 distance after simulating protanopia, deuteranopia, tritanopia (Machado 2009, severity 1) and greyscale. Single-series charts and chart types without a series legend are skipped."
2003
+ approximations: "Uses the engine's series palette (ValidateOptions.chartPalette; default chartSeriesPalette of each slide colour scheme (accent1 to accent6, then their tints), adjusted for the card surface like the preview does) in series order: series i takes colour i, pie/doughnut/treemap/funnel slices take colours per category. Pairs are compared by CIE76 distance after simulating protanopia, deuteranopia, tritanopia (Machado 2009, severity 1) and greyscale. Single-series charts and chart types without a series legend are skipped."
1897
2004
  }
1898
2005
  );
1899
2006
  var chartAltRule = rule(
@@ -1904,6 +2011,21 @@ var chartAltRule = rule(
1904
2011
  "A chart conveys a message; people who cannot see it need the message and ideally the numbers in text. The chart's alt field is that text alternative (the preview exposes it as the chart's accessible name and the PowerPoint export writes it as the frame's alternative text); a sentence or table beside the chart also serves. An empty alt marks a chart decorative, which is reported as info so the choice is reviewed: a chart rarely carries no message.",
1905
2012
  { standard: "WCAG 2.2 SC 1.1.1 Non-text Content, level A", approximations: `A chart passes when chart.alt has text. Without alt, it passes when the slide has any other text, list, table, quote or metric content besides title and tag, or a subtitle. It does not judge whether alt or that text states the chart's point (see opf/poor-alt-text for generic alt text). alt: "" is reported as a decorative chart, whatever else is on the slide.` }
1906
2013
  );
2014
+ var chartColorsRule = rule(
2015
+ "chart-colors-adjusted",
2016
+ "accessibility",
2017
+ "warning",
2018
+ "A chart colour cannot be used as authored.",
2019
+ "`chart.colors` sets the colour of series 1, 2, 3 and so on. A colour that cannot be resolved (a `var:` colour variable the deck does not define, or a name that is not a colour) is ignored and the deck palette colour of that position is used. A colour with under 3:1 contrast against the chart panel is kept for its hue but drawn lighter or darker, so the chart does not show the colour that was written.",
2020
+ {
2021
+ standard: "WCAG 2.2 SC 1.4.11 Non-text Contrast, level AA",
2022
+ approximations: "Resolves each entry like any colour reference (hex, colour-scheme slot or role, `var:` variable) against the slide's scheme and compares it with the chart panel (the slide surface colour) by WCAG contrast; 3:1 is the threshold the engines enforce. Translucent colours and unresolved panels are not measured. Colours that look alike to colour-vision deficiency are reported by opf/chart-color-only, which judges the authored colours."
2023
+ }
2024
+ );
2025
+ var chartColorContext = (design) => ({
2026
+ roles: { primary: design.colors.primary, secondary: design.colors.secondary, accent: design.colors.accent, background: design.colors.background, surface: design.colors.surface, text: design.colors.text, textSecondary: design.colors.mutedText },
2027
+ variables: design.variables
2028
+ });
1907
2029
  var chartSkip = /(histogram|box|pareto|waterfall|world|map)/;
1908
2030
  var perCategory = /(pie|doughnut|treemap|funnel)/;
1909
2031
  var chartRules = [
@@ -1922,7 +2044,7 @@ var chartRules = [
1922
2044
  const count = slices ? data.rows.length : data.columns.length - 1;
1923
2045
  if (count < 2) continue;
1924
2046
  const surface = slide.design.colors.surface;
1925
- const palette = chartPaletteForFill(surface, context.chartPalette);
2047
+ const palette = chartPaletteForFill(surface, context.chartPalette ?? chartSeriesPalette(slide.design.colorScheme, chart.colors, chartColorContext(slide.design)));
1926
2048
  if (!palette.length) continue;
1927
2049
  const used = Array.from({ length: Math.min(count, 24) }, (_, i) => palette[i % palette.length]);
1928
2050
  const pairs = [];
@@ -1939,17 +2061,51 @@ var chartRules = [
1939
2061
  if (!pairs.length && !cycles) continue;
1940
2062
  pairs.sort((x, y) => x.difference - y.difference);
1941
2063
  const names2 = slices ? data.rows.map((row) => String(row?.[0] ?? "")) : data.columns.slice(1).map(String);
1942
- const describe = (p) => `${JSON.stringify(names2[p.a] ?? `#${p.a + 1}`)} and ${JSON.stringify(names2[p.b] ?? `#${p.b + 1}`)} (${p.model}, difference ${p.difference.toFixed(1)})`;
2064
+ const describe2 = (p) => `${JSON.stringify(names2[p.a] ?? `#${p.a + 1}`)} and ${JSON.stringify(names2[p.b] ?? `#${p.b + 1}`)} (${p.model}, difference ${p.difference.toFixed(1)})`;
1943
2065
  context.report(chartColorRule, {
1944
2066
  path: `${payload.path === slide.path ? slide.path : payload.path}/chart`,
1945
2067
  slide,
1946
- message: `${slices ? "Slices" : "Series"} may be hard to tell apart without colour: ${pairs.slice(0, 3).map(describe).join("; ")}${cycles ? `${pairs.length ? "; " : ""}${count} ${slices ? "slices" : "series"} exceed the ${palette.length}-colour palette, so colours repeat` : ""}.`,
2068
+ message: `${slices ? "Slices" : "Series"} may be hard to tell apart without colour: ${pairs.slice(0, 3).map(describe2).join("; ")}${cycles ? `${pairs.length ? "; " : ""}${count} ${slices ? "slices" : "series"} exceed the ${palette.length}-colour palette, so colours repeat` : ""}.`,
1947
2069
  help: "Show fewer series per chart (split into two charts), state the key values in the slide text or a table next to the chart, or choose a chart type whose categories sit on an axis instead of in a legend.",
1948
2070
  measured: { series: count, confusablePairs: pairs.length, minDifference: pairs[0] ? round(pairs[0].difference) : null }
1949
2071
  });
1950
2072
  }
1951
2073
  }
1952
2074
  },
2075
+ {
2076
+ info: chartColorsRule,
2077
+ run(context) {
2078
+ for (const slide of context.slides)
2079
+ for (const payload of slidePayloads(slide.slide, slide.path)) {
2080
+ const chart = rec(payload.node.chart);
2081
+ if (!Array.isArray(chart.colors)) continue;
2082
+ const surface = normalizeHexColor(slide.design.colors.surface);
2083
+ const resolved = resolveChartColors(chart.colors, slide.design.colorScheme, chartColorContext(slide.design));
2084
+ resolved.forEach((color, index) => {
2085
+ const path = `${payload.path === slide.path ? slide.path : payload.path}/chart/colors/${index}`;
2086
+ const entry = chart.colors[index];
2087
+ if (color === void 0) {
2088
+ context.report(chartColorsRule, {
2089
+ path,
2090
+ slide,
2091
+ message: `Chart colour ${index + 1} (${JSON.stringify(entry)}) cannot be resolved, so the palette colour of that position is used.`,
2092
+ help: 'Use a hex colour, a colour-scheme name such as "accent2", or the id of a colour variable the deck defines (var:<id>).'
2093
+ });
2094
+ return;
2095
+ }
2096
+ const contrast = surface ? colorContrast(color, surface) : void 0;
2097
+ if (contrast === void 0 || contrast >= 3) return;
2098
+ context.report(chartColorsRule, {
2099
+ path,
2100
+ slide,
2101
+ message: `Chart colour ${index + 1} (${color}) has ${contrast.toFixed(1)}:1 contrast against the chart panel (${surface}); it is drawn lighter or darker to reach 3:1.`,
2102
+ help: "Choose a colour that already has at least 3:1 contrast against the slide surface, so the chart shows the colour you wrote.",
2103
+ measured: { contrast: round(contrast), panel: surface }
2104
+ });
2105
+ });
2106
+ }
2107
+ }
2108
+ },
1953
2109
  {
1954
2110
  info: chartAltRule,
1955
2111
  run(context) {
@@ -2196,6 +2352,18 @@ var unplacedRule = rule(
2196
2352
  { cost: "composition" }
2197
2353
  );
2198
2354
  var REGION_RULES = { "region-unknown": regionUnknownRule, "region-kind": regionKindRule, "region-full": regionFullRule, "layout-unplaced": unplacedRule };
2355
+ var MAX_FURNITURE_LINES = 2;
2356
+ var furnitureWrapsRule = rule(
2357
+ "furniture-wraps",
2358
+ "layout",
2359
+ "warning",
2360
+ `A header or footer zone wraps onto more than ${MAX_FURNITURE_LINES} lines.`,
2361
+ "Header and footer text repeats on every slide in a band at the slide edge. A zone that wraps onto three or more lines grows into the body, and long source lines read poorly at footer size. Footers carry short repeated text (a title, a date, a page number); sources belong in a caption or the speaker notes.",
2362
+ {
2363
+ cost: "composition",
2364
+ approximations: "Uses the lines core composed for the zone at the deck's slide size; without a host-supplied text measurement (ValidateOptions.fonts.textMeasurement) widths are core's portable estimates. A deck-level header or footer is reported once."
2365
+ }
2366
+ );
2199
2367
  var layoutRules = [
2200
2368
  {
2201
2369
  info: overflowRule,
@@ -2208,9 +2376,9 @@ var layoutRules = [
2208
2376
  for (const { diagnostic } of slide.layoutDiagnostics) {
2209
2377
  const path = pointerOfDotted(diagnostic.path);
2210
2378
  if (!path.startsWith("/slides/")) {
2211
- const key = `${diagnostic.code}|${path}|${diagnostic.message}`;
2212
- if (deckLevel.has(key)) continue;
2213
- deckLevel.add(key);
2379
+ const key2 = `${diagnostic.code}|${path}|${diagnostic.message}`;
2380
+ if (deckLevel.has(key2)) continue;
2381
+ deckLevel.add(key2);
2214
2382
  }
2215
2383
  if (diagnostic.code === "text-overflow")
2216
2384
  context.report(overflowRule, { path, slide, message: diagnostic.message, help: "Shorten the text, give it more space (fewer blocks, a different composition) or split the slide (paginate); raising the readable minimum makes it worse." });
@@ -2254,6 +2422,26 @@ var layoutRules = [
2254
2422
  }
2255
2423
  }
2256
2424
  }
2425
+ },
2426
+ {
2427
+ info: furnitureWrapsRule,
2428
+ run(context) {
2429
+ const reported = /* @__PURE__ */ new Set();
2430
+ for (const slide of context.slides)
2431
+ for (const part of slide.composition?.furniture?.parts ?? []) {
2432
+ if (part.type !== "text" || part.fit.lines.length <= MAX_FURNITURE_LINES) continue;
2433
+ const path = pointerOfDotted(part.sourcePath ?? part.path);
2434
+ if (reported.has(path)) continue;
2435
+ reported.add(path);
2436
+ context.report(furnitureWrapsRule, {
2437
+ path,
2438
+ slide,
2439
+ message: `The ${part.kind} ${part.zone} text wraps onto ${part.fit.lines.length} lines (at most ${MAX_FURNITURE_LINES}).`,
2440
+ help: "Shorten the text, or move sources and notes to a caption or the speaker notes; keep the footer for short repeated text.",
2441
+ measured: { lines: part.fit.lines.length, maximumLines: MAX_FURNITURE_LINES }
2442
+ });
2443
+ }
2444
+ }
2257
2445
  }
2258
2446
  ];
2259
2447
  var outsideRule = rule(
@@ -2648,7 +2836,7 @@ function ruleInfo(id) {
2648
2836
  }
2649
2837
 
2650
2838
  // src/check-document.ts
2651
- var own = (value, key) => Object.hasOwn(value, key);
2839
+ var own = (value, key2) => Object.hasOwn(value, key2);
2652
2840
  var object = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2653
2841
  var primitive = (value) => value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value);
2654
2842
  var pointer3 = (parts2) => parts2.length ? "/" + parts2.map((part) => String(part).replaceAll("~", "~0").replaceAll("/", "~1")).join("/") : "";
@@ -2660,7 +2848,7 @@ function parts(path) {
2660
2848
  }
2661
2849
  function at(value, path) {
2662
2850
  return parts(path).reduce(
2663
- (current, key) => object(current) || Array.isArray(current) ? own(current, key) ? current[key] : void 0 : void 0,
2851
+ (current, key2) => object(current) || Array.isArray(current) ? own(current, key2) ? current[key2] : void 0 : void 0,
2664
2852
  value
2665
2853
  );
2666
2854
  }
@@ -2670,13 +2858,13 @@ function checkDocumentOptions(options) {
2670
2858
  throw new TypeError("Validate contracts must be an array.");
2671
2859
  for (const contract of options.contracts ?? []) {
2672
2860
  if (!object(contract) || Object.keys(contract).some(
2673
- (key) => ![
2861
+ (key2) => ![
2674
2862
  "path",
2675
2863
  "allowedValues",
2676
2864
  "severity",
2677
2865
  "message",
2678
2866
  "documentation"
2679
- ].includes(key)
2867
+ ].includes(key2)
2680
2868
  ) || typeof contract.path !== "string" || !Array.isArray(contract.allowedValues) || !contract.allowedValues.every(primitive) || contract.severity !== void 0 && (typeof contract.severity !== "string" || !["error", "warning", "info"].includes(contract.severity)) || contract.message !== void 0 && typeof contract.message !== "string" || contract.documentation !== void 0 && typeof contract.documentation !== "string")
2681
2869
  throw new TypeError(
2682
2870
  "Invalid contract: provide a path and primitive allowedValues, with optional severity, message and documentation."
@@ -2754,13 +2942,13 @@ function score(schema, value) {
2754
2942
  if (own(schema, "const")) return schema.const === value ? 100 : -1e4;
2755
2943
  let result = 1;
2756
2944
  if (object(value) && object(schema.properties)) {
2757
- for (const [key, child] of Object.entries(schema.properties))
2758
- if (own(value, key) && object(child))
2759
- result += own(child, "const") ? child.const === value[key] ? 100 : -1e3 : 1;
2945
+ for (const [key2, child] of Object.entries(schema.properties))
2946
+ if (own(value, key2) && object(child))
2947
+ result += own(child, "const") ? child.const === value[key2] ? 100 : -1e3 : 1;
2760
2948
  }
2761
2949
  if (Array.isArray(schema.required)) {
2762
- for (const key of schema.required)
2763
- if (typeof key === "string" && (!object(value) || !own(value, key)))
2950
+ for (const key2 of schema.required)
2951
+ if (typeof key2 === "string" && (!object(value) || !own(value, key2)))
2764
2952
  result -= 2;
2765
2953
  }
2766
2954
  return result;
@@ -2782,7 +2970,7 @@ function active(cursor, value) {
2782
2970
  const selected = candidates.sort((a, b) => score(b.schema, value) - score(a.schema, value))[0];
2783
2971
  return selected ? { ...selected, baseSchemas: [...selected.baseSchemas ?? [], resolved] } : resolved;
2784
2972
  }
2785
- function childCursor(cursors, key) {
2973
+ function childCursor(cursors, key2) {
2786
2974
  for (const keyword of [
2787
2975
  "properties",
2788
2976
  "patternProperties",
@@ -2791,8 +2979,8 @@ function childCursor(cursors, key) {
2791
2979
  for (const cursor of cursors) {
2792
2980
  const declarations = cursor.schema[keyword];
2793
2981
  if (!object(declarations)) continue;
2794
- const name = keyword === "properties" ? key : keyword === "patternProperties" ? Object.keys(declarations).find(
2795
- (pattern) => new RegExp(pattern).test(key)
2982
+ const name = keyword === "properties" ? key2 : keyword === "patternProperties" ? Object.keys(declarations).find(
2983
+ (pattern) => new RegExp(pattern).test(key2)
2796
2984
  ) : void 0;
2797
2985
  const schema = keyword === "additionalProperties" ? declarations : name === void 0 ? void 0 : declarations[name];
2798
2986
  if (object(schema))
@@ -2851,13 +3039,13 @@ function fields(document) {
2851
3039
  });
2852
3040
  });
2853
3041
  else if (object(entry.value))
2854
- for (const [key, value] of Object.entries(entry.value)) {
2855
- if (entry.path.length === 0 && key === "catalogs") continue;
2856
- const cursor = childCursor(cursors, key);
3042
+ for (const [key2, value] of Object.entries(entry.value)) {
3043
+ if (entry.path.length === 0 && key2 === "catalogs") continue;
3044
+ const cursor = childCursor(cursors, key2);
2857
3045
  if (!cursor) continue;
2858
3046
  stack.push({
2859
3047
  value,
2860
- path: [...entry.path, key],
3048
+ path: [...entry.path, key2],
2861
3049
  cursor,
2862
3050
  ancestors
2863
3051
  });
@@ -3003,8 +3191,8 @@ function variableFindings(document, engine, schemaValid) {
3003
3191
  })
3004
3192
  );
3005
3193
  if (engine.template !== void 0 || !schemaValid) return findings;
3006
- const walk = (value, path, depth) => {
3007
- if (depth > 64) return;
3194
+ const walk = (value, path, depth2) => {
3195
+ if (depth2 > 64) return;
3008
3196
  if (typeof value === "string") {
3009
3197
  if (value.startsWith("data:") || !value.includes("{{")) return;
3010
3198
  for (const match of value.matchAll(VARIABLE_TOKEN))
@@ -3021,14 +3209,14 @@ function variableFindings(document, engine, schemaValid) {
3021
3209
  }
3022
3210
  if (Array.isArray(value)) {
3023
3211
  value.forEach((entry, index) => {
3024
- walk(entry, [...path, String(index)], depth + 1);
3212
+ walk(entry, [...path, String(index)], depth2 + 1);
3025
3213
  });
3026
3214
  return;
3027
3215
  }
3028
3216
  if (value && typeof value === "object")
3029
- for (const [key, entry] of Object.entries(value)) {
3030
- if (path.length === 0 && ["variables", "extensions", "catalogs", "assets"].includes(key)) continue;
3031
- walk(entry, [...path, key], depth + 1);
3217
+ for (const [key2, entry] of Object.entries(value)) {
3218
+ if (path.length === 0 && ["variables", "extensions", "catalogs", "assets"].includes(key2)) continue;
3219
+ walk(entry, [...path, key2], depth2 + 1);
3032
3220
  }
3033
3221
  };
3034
3222
  walk(document, [], 0);
@@ -3223,7 +3411,7 @@ function contractFindings(document, contracts) {
3223
3411
  };
3224
3412
  const message = (contract.message ?? "This value is outside the allowed values for {{path}}.").replace(
3225
3413
  /\{\{(path|value|allowed|file)\}\}/g,
3226
- (_, key) => values[key] ?? ""
3414
+ (_, key2) => values[key2] ?? ""
3227
3415
  );
3228
3416
  findings.push(
3229
3417
  finding("opf/contract", {
@@ -3241,9 +3429,9 @@ function contractFindings(document, contracts) {
3241
3429
  })
3242
3430
  );
3243
3431
  } else if (object(entry.value) || Array.isArray(entry.value)) {
3244
- const key = pattern[entry.depth];
3432
+ const key2 = pattern[entry.depth];
3245
3433
  for (const [name, value] of Object.entries(entry.value))
3246
- if (key === "*" || key === name)
3434
+ if (key2 === "*" || key2 === name)
3247
3435
  stack.push({
3248
3436
  value,
3249
3437
  path: [...entry.path, name],
@@ -3316,18 +3504,18 @@ function parseSource(source) {
3316
3504
  if (node.type === "object") {
3317
3505
  const keys = /* @__PURE__ */ new Set();
3318
3506
  for (const property of node.children ?? []) {
3319
- const key = property.children?.[0];
3320
- if (!key) continue;
3321
- if (keys.has(key.value))
3507
+ const key2 = property.children?.[0];
3508
+ if (!key2) continue;
3509
+ if (keys.has(key2.value))
3322
3510
  duplicates.push(
3323
3511
  finding("opf/duplicate-key", {
3324
- path: pointer3(getNodePath(key)),
3325
- message: `Duplicate JSON property ${JSON.stringify(key.value)}.`,
3512
+ path: pointer3(getNodePath(key2)),
3513
+ message: `Duplicate JSON property ${JSON.stringify(key2.value)}.`,
3326
3514
  help: "Resolve the duplicate explicitly, preserving the intended content from both occurrences. JSON.parse would otherwise hide an earlier value.",
3327
- location: location(key.offset, key.length)
3515
+ location: location(key2.offset, key2.length)
3328
3516
  })
3329
3517
  );
3330
- keys.add(key.value);
3518
+ keys.add(key2.value);
3331
3519
  }
3332
3520
  }
3333
3521
  stack.push(...node.children ?? []);
@@ -3368,7 +3556,7 @@ function scriptProfile(presentation, slideIndex, options, language) {
3368
3556
  }
3369
3557
  const slots = (role) => {
3370
3558
  const latin = options.fontFamilies[role];
3371
- const slot = (key) => !resolved || resolved.sources[key] === "latin" || resolved.sources[key] === "schemeFamily" ? latin : resolved[role][key] ?? latin;
3559
+ const slot = (key2) => !resolved || resolved.sources[key2] === "latin" || resolved.sources[key2] === "schemeFamily" ? latin : resolved[role][key2] ?? latin;
3372
3560
  return { latin, eastAsian: slot("eastAsian"), complexScript: slot("complexScript") };
3373
3561
  };
3374
3562
  return {
@@ -3588,7 +3776,7 @@ function names(list, what) {
3588
3776
  }
3589
3777
  function resolveOptions(options) {
3590
3778
  if (!isObject(options)) throw new TypeError("Validate options must be an object.");
3591
- for (const key of Object.keys(options)) if (!OPTION_KEYS.includes(key)) throw new TypeError(`Unknown validate option ${JSON.stringify(key)}. Options: ${OPTION_KEYS.join(", ")}.`);
3779
+ for (const key2 of Object.keys(options)) if (!OPTION_KEYS.includes(key2)) throw new TypeError(`Unknown validate option ${JSON.stringify(key2)}. Options: ${OPTION_KEYS.join(", ")}.`);
3592
3780
  checkDocumentOptions(options);
3593
3781
  const only = names(options.only, "only");
3594
3782
  const ignore = names(options.ignore, "ignore");
@@ -3617,10 +3805,10 @@ function resolveOptions(options) {
3617
3805
  const thresholds = { ...DEFAULT_VALIDATION_THRESHOLDS };
3618
3806
  if (options.thresholds !== void 0) {
3619
3807
  if (!isObject(options.thresholds)) throw new TypeError("Validate thresholds must be an object.");
3620
- for (const [key, value] of Object.entries(options.thresholds)) {
3621
- if (!(key in DEFAULT_VALIDATION_THRESHOLDS)) throw new TypeError(`Unknown validate threshold ${JSON.stringify(key)}. Thresholds: ${Object.keys(DEFAULT_VALIDATION_THRESHOLDS).join(", ")}.`);
3622
- if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) throw new TypeError(`Validate threshold ${key} must be a positive number.`);
3623
- thresholds[key] = value;
3808
+ for (const [key2, value] of Object.entries(options.thresholds)) {
3809
+ if (!(key2 in DEFAULT_VALIDATION_THRESHOLDS)) throw new TypeError(`Unknown validate threshold ${JSON.stringify(key2)}. Thresholds: ${Object.keys(DEFAULT_VALIDATION_THRESHOLDS).join(", ")}.`);
3810
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) throw new TypeError(`Validate threshold ${key2} must be a positive number.`);
3811
+ thresholds[key2] = value;
3624
3812
  }
3625
3813
  }
3626
3814
  if (options.fonts !== void 0) {
@@ -3644,7 +3832,7 @@ function resolveOptions(options) {
3644
3832
  },
3645
3833
  ignored: (info, path) => ignorePaths.some((entry) => entry.match(info) && entry.path.every((part, index) => path[index] === part)),
3646
3834
  thresholds,
3647
- chartPalette: options.chartPalette ?? DEFAULT_CHART_PALETTE
3835
+ chartPalette: options.chartPalette
3648
3836
  };
3649
3837
  }
3650
3838
  var order = new Map(validationRules.map((info, index) => [info.id, index]));
@@ -3824,4 +4012,4 @@ function assertValidCatalogRecord(kind, value) {
3824
4012
  if (!report2.valid) throw new OPFValidationError(report2);
3825
4013
  }
3826
4014
 
3827
- export { CATALOG_SCHEMA, DEFAULT_CHART_PALETTE, DEFAULT_VALIDATION_THRESHOLDS, OPFValidationError, assertValid, assertValidCatalogRecord, catalogDisplayKinds, catalogSchemaNames, findValidationRule, parseSource, resolveSlideContext, resolveSlideScriptMeasurement, validate, validateCatalogRecord, validationCategories, validationRules };
4015
+ export { CATALOG_SCHEMA, DEFAULT_VALIDATION_THRESHOLDS, OPFValidationError, assertValid, assertValidCatalogRecord, catalogDisplayKinds, catalogSchemaNames, findValidationRule, parseSource, resolveSlideContext, resolveSlideScriptMeasurement, validate, validateCatalogRecord, validationCategories, validationRules };