@openpresentation/opf 0.26.10 → 0.28.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.
- package/README.md +6 -0
- package/dist/browser.js +20 -17
- package/dist/{catalog-refs-BSfGELpt.d.ts → catalog-refs-kAefsZWT.d.ts} +2 -1
- package/dist/{catalog-schemas-DoxA2BgY.d.ts → catalog-schemas-CC1d_h8s.d.ts} +3 -2
- package/dist/{chart-data-BnNqgnC-.d.ts → chart-data-Ci9s_NDN.d.ts} +2 -1
- package/dist/{chunk-XRMV2GMB.js → chunk-2CUCYENF.js} +758 -232
- package/dist/chunk-43JWUIGF.js +8 -0
- package/dist/{chunk-F4HFDP6I.js → chunk-5Q4IYLMW.js} +31 -15
- package/dist/{chunk-GIWNHRTX.js → chunk-BQUWRXTR.js} +4 -4
- package/dist/chunk-CR72ZJ6W.js +236 -0
- package/dist/{chunk-L52N5FZZ.js → chunk-F6DCEGB3.js} +6 -6
- package/dist/chunk-GM7WFPGG.js +10 -0
- package/dist/chunk-JBARNYFR.js +23 -0
- package/dist/{chunk-EQ6S5SEZ.js → chunk-KELC4K62.js} +1 -1
- package/dist/{chunk-77KL2PMM.js → chunk-KXKN3W5Z.js} +3 -3
- package/dist/{chunk-D25BNPTW.js → chunk-LLEXM7TQ.js} +4 -4
- package/dist/{chunk-3S2XVDPN.js → chunk-MTFK7QEY.js} +6 -6
- package/dist/{chunk-TKQ2VFV5.js → chunk-N77N4AOD.js} +1 -1
- package/dist/{chunk-NVT2YDVC.js → chunk-OAIAFXMS.js} +2 -2
- package/dist/{chunk-PHP45MO7.js → chunk-P6PKYJTS.js} +1 -1
- package/dist/{chunk-H7XMO36O.js → chunk-PCU4XGKV.js} +5 -5
- package/dist/{chunk-Y4TZCE7R.js → chunk-SEZ4EPW6.js} +2 -2
- package/dist/{chunk-Y25DYRME.js → chunk-TNUTRV6E.js} +1 -1
- package/dist/{chunk-G5WJMJV3.js → chunk-UOHWG4OS.js} +1 -1
- package/dist/{chunk-A54NGT2K.js → chunk-VGGPAMP7.js} +2 -2
- package/dist/{chunk-IVPA6NG6.js → chunk-WPKCWQ6W.js} +494 -120
- package/dist/{chunk-VZBFQLCA.js → chunk-XZ23FORL.js} +6 -6
- package/dist/chunk-ZROVYWGU.js +1 -0
- package/dist/{composition-DIftf6iP.d.ts → composition-C-hd_Ci3.d.ts} +134 -14
- package/dist/composition.d.ts +3 -3
- package/dist/composition.js +2 -1
- package/dist/conversion-XJTDWQ5W.js +24 -0
- package/dist/{conversion-ChmGA8Ul.d.ts → conversion-hbZeS5kD.d.ts} +8 -7
- package/dist/convert.d.ts +6 -5
- package/dist/convert.js +9 -7
- package/dist/data.d.ts +4 -3
- package/dist/data.js +3 -2
- package/dist/{deck-report-5vwMGcQz.d.ts → deck-report-DQMsvyBI.d.ts} +5 -4
- package/dist/deck.d.ts +9 -8
- package/dist/deck.js +13 -11
- package/dist/diff.d.ts +3 -2
- package/dist/diff.js +6 -4
- package/dist/docs.d.ts +2 -1
- package/dist/docs.js +33 -19
- package/dist/examples.d.ts +3 -2
- package/dist/examples.js +92 -50
- package/dist/{explain-JSuESV-Y.d.ts → explain-iZeNOUc6.d.ts} +2 -1
- package/dist/font-policy.d.ts +2 -1
- package/dist/font-policy.js +1 -0
- package/dist/format.d.ts +2 -1
- package/dist/format.js +3 -2
- package/dist/ids.d.ts +114 -0
- package/dist/ids.js +6 -0
- package/dist/index.d.ts +40 -16
- package/dist/index.js +24 -21
- package/dist/markdown.d.ts +8 -7
- package/dist/markdown.js +10 -8
- package/dist/node-engine.d.ts +33 -10
- package/dist/node-engine.js +37 -28
- package/dist/{pagination-D_kJe4jH.d.ts → pagination-DyAKYpXu.d.ts} +4 -3
- package/dist/pagination.d.ts +4 -4
- package/dist/pagination.js +6 -4
- package/dist/patch.d.ts +89 -4
- package/dist/patch.js +5 -3
- package/dist/precompiled.d.ts +2 -0
- package/dist/precompiled.js +7 -0
- package/dist/{presentation-Bwo8Ko6D.d.ts → presentation-8jLSTFqL.d.ts} +11 -11
- package/dist/repo-readme.js +3 -1
- package/dist/schema-engine-ajv.js +37 -0
- package/dist/schema-engine-precompiled.js +3 -0
- package/dist/schema.d.ts +4 -3
- package/dist/schema.js +5 -3
- package/dist/schemas.d.ts +2 -1
- package/dist/schemas.js +2 -1
- package/dist/source.d.ts +5 -4
- package/dist/source.js +12 -10
- package/dist/spec/README.md +1 -1
- package/dist/spec/schemas/audience.schema.json +1 -0
- package/dist/spec/schemas/catalog-index.schema.json +1 -0
- package/dist/spec/schemas/catalog-manifest.schema.json +1 -0
- package/dist/spec/schemas/chart-type.schema.json +1 -0
- package/dist/spec/schemas/color-scheme.schema.json +1 -0
- package/dist/spec/schemas/finding.schema.json +1 -0
- package/dist/spec/schemas/font-scheme.schema.json +1 -0
- package/dist/spec/schemas/language.schema.json +1 -0
- package/dist/spec/schemas/layout-preview-index.schema.json +1 -0
- package/dist/spec/schemas/layout.schema.json +8 -6
- package/dist/spec/schemas/narrative.schema.json +1 -0
- package/dist/spec/schemas/opf.schema.json +9 -8
- package/dist/spec/schemas/purpose.schema.json +1 -0
- package/dist/spec/schemas/social-platform.schema.json +1 -0
- package/dist/spec/schemas/theme.schema.json +3 -1
- package/dist/spec/schemas/tone.schema.json +1 -0
- package/dist/spec-files.d.ts +2 -1
- package/dist/spec-files.js +1 -0
- package/dist/symbol-font-encodings.d.ts +2 -1
- package/dist/symbol-font-encodings.js +2 -0
- package/dist/types.d.ts +9 -9
- package/dist/{validation-types-3ARvTsB0.d.ts → validation-types-mNmfcY9A.d.ts} +4 -3
- package/dist/validator.d.ts +8 -8
- package/dist/validator.js +5 -3
- package/dist/yaml.d.ts +8 -7
- package/dist/yaml.js +9 -7
- package/package.json +30 -9
- package/dist/conversion-IVKCKMCN.js +0 -21
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { schemas, schemaEntries } from './chunk-
|
|
3
|
-
import
|
|
4
|
-
import
|
|
1
|
+
import { original } from './chunk-JBARNYFR.js';
|
|
2
|
+
import { schemas, schemaEntries } from './chunk-5Q4IYLMW.js';
|
|
3
|
+
import { promotedRegionKeys, VARIABLE_KINDS, resolveChartData, chartPaletteForFill, chartSeriesPalette, chartLeadFromScheme, normalizeHexColor, resolveChartColors, colorContrast, imageBackground, tableGrid, timelineTextColor, LOGO_SHAPES, visitContentPayloads, readingRows, visualReadingOrder, intrinsicImageSize, resolveReference, textWidthMeasurer, resolveColorRef, resolveDesignRecords, resolveFontFamilies, checkCatalogsOption, provenanceOf, unresolvedReference, OPFUnresolvedReferenceError, resolveColorRoles, resolveCanvasDimensions, resolveSlideVariables, normalizeColorVariant, isRecord, hasContentVariables, isTemplate, instantiateForValidation, layoutTemplateIssues, resolveScriptFonts, defaultSlideBackground, 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-2CUCYENF.js';
|
|
4
|
+
import { schemaEngine } from '#schema-engine';
|
|
5
5
|
import { parseTree, printParseErrorCode, getNodePath } from 'jsonc-parser';
|
|
6
6
|
|
|
7
7
|
// src/catalog-schemas.ts
|
|
@@ -88,38 +88,9 @@ function unusedReferenceWarnings(value) {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
// src/union-errors.ts
|
|
91
|
-
var compiled = /* @__PURE__ */ new WeakMap();
|
|
92
|
-
var origin = /* @__PURE__ */ new WeakMap();
|
|
93
91
|
var isUnion = (error) => (error.keyword === "oneOf" || error.keyword === "anyOf") && Array.isArray(error.schema);
|
|
94
92
|
var key = (error) => `${error.instancePath}\0${error.keyword}\0${error.message}\0${JSON.stringify(error.params)}`;
|
|
95
93
|
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
94
|
function branchLabel(branch, index) {
|
|
124
95
|
if (typeof branch.$ref === "string") return branch.$ref.slice(branch.$ref.lastIndexOf("/") + 1);
|
|
125
96
|
if (typeof branch.type === "string") return branch.type;
|
|
@@ -135,12 +106,12 @@ function describe(errors, base) {
|
|
|
135
106
|
const rest = shallow.instancePath.split("/").slice(base + 1).join("/");
|
|
136
107
|
return depth(shallow.instancePath) === base || !rest ? shallow.message ?? "does not match" : `${shallow.message} at /${rest}`;
|
|
137
108
|
}
|
|
138
|
-
function bestMatchErrors(
|
|
109
|
+
function bestMatchErrors(engine, rootId, errors) {
|
|
139
110
|
const unions = errors.filter(isUnion);
|
|
140
111
|
if (!unions.length) return errors;
|
|
141
112
|
const analyses = [];
|
|
142
113
|
for (const union of unions) {
|
|
143
|
-
const analysis = analyze(
|
|
114
|
+
const analysis = analyze(engine, rootId, union);
|
|
144
115
|
if (analysis) analyses.push(analysis);
|
|
145
116
|
}
|
|
146
117
|
if (!analyses.length) return errors;
|
|
@@ -156,19 +127,20 @@ function bestMatchErrors(ajv2, rootId, errors) {
|
|
|
156
127
|
}
|
|
157
128
|
return result;
|
|
158
129
|
}
|
|
159
|
-
function analyze(
|
|
130
|
+
function analyze(engine, rootId, union) {
|
|
160
131
|
const branches = union.schema;
|
|
161
132
|
const base = depth(union.instancePath);
|
|
162
133
|
const results = [];
|
|
163
134
|
for (const [index, branch] of branches.entries()) {
|
|
164
135
|
if (!branch || typeof branch !== "object") return void 0;
|
|
165
|
-
const validate2 =
|
|
136
|
+
const validate2 = engine.branch(branch, rootId);
|
|
137
|
+
if (!validate2) return void 0;
|
|
166
138
|
if (validate2(union.data) === true) return void 0;
|
|
167
139
|
const raw = (validate2.errors ?? []).map((error) => ({ ...error, instancePath: union.instancePath + error.instancePath }));
|
|
168
140
|
results.push({ label: branchLabel(branch, index), errors: raw });
|
|
169
141
|
}
|
|
170
142
|
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(
|
|
143
|
+
const reduced = results.map((result) => ({ label: result.label, errors: bestMatchErrors(engine, rootId, result.errors) }));
|
|
172
144
|
const mismatch = (error) => {
|
|
173
145
|
const level = depth(error.instancePath) - base;
|
|
174
146
|
return level === 0 && (error.keyword === "type" || isUnion(error)) || level === 1 && error.keyword === "const";
|
|
@@ -248,7 +220,6 @@ function validationDefinition(issue2) {
|
|
|
248
220
|
|
|
249
221
|
// src/schema-check.ts
|
|
250
222
|
var schemaNameByCatalogKind = catalogSchemaNames;
|
|
251
|
-
var ajv;
|
|
252
223
|
var promotedRegionKeySet = new Set(promotedRegionKeys);
|
|
253
224
|
var rootPayloadFields = [
|
|
254
225
|
"type",
|
|
@@ -326,23 +297,6 @@ var rowSpans = {
|
|
|
326
297
|
"middle+bottom": [1, 2],
|
|
327
298
|
"top+middle+bottom": [0, 1, 2]
|
|
328
299
|
};
|
|
329
|
-
function getAjv() {
|
|
330
|
-
if (ajv) {
|
|
331
|
-
return ajv;
|
|
332
|
-
}
|
|
333
|
-
const instance = new Ajv2020({
|
|
334
|
-
allErrors: true,
|
|
335
|
-
verbose: true,
|
|
336
|
-
strict: false,
|
|
337
|
-
allowUnionTypes: true
|
|
338
|
-
});
|
|
339
|
-
addFormats(instance);
|
|
340
|
-
for (const schema of Object.values(schemas)) {
|
|
341
|
-
instance.addSchema(schema);
|
|
342
|
-
}
|
|
343
|
-
ajv = instance;
|
|
344
|
-
return instance;
|
|
345
|
-
}
|
|
346
300
|
function isSchemaName(value) {
|
|
347
301
|
return typeof value === "string" && hasOwn(schemas, value);
|
|
348
302
|
}
|
|
@@ -350,17 +304,12 @@ function isCatalogKind(value) {
|
|
|
350
304
|
return typeof value === "string" && hasOwn(schemaNameByCatalogKind, value);
|
|
351
305
|
}
|
|
352
306
|
function resolveValidator(schemaOrKind) {
|
|
353
|
-
const instance = getAjv();
|
|
354
307
|
if (isSchemaName(schemaOrKind)) {
|
|
355
|
-
|
|
356
|
-
const validator = instance.getSchema(schema.$id) ?? instance.compile(schema);
|
|
357
|
-
return { validate: validator, schemaName: schemaOrKind };
|
|
308
|
+
return { validate: schemaEngine().root(schemaOrKind), schemaName: schemaOrKind };
|
|
358
309
|
}
|
|
359
310
|
if (isCatalogKind(schemaOrKind)) {
|
|
360
311
|
const schemaName = schemaNameByCatalogKind[schemaOrKind];
|
|
361
|
-
|
|
362
|
-
const validator = instance.getSchema(schema.$id) ?? instance.compile(schema);
|
|
363
|
-
return { validate: validator, schemaName, catalogKind: schemaOrKind };
|
|
312
|
+
return { validate: schemaEngine().root(schemaName), schemaName, catalogKind: schemaOrKind };
|
|
364
313
|
}
|
|
365
314
|
throw new TypeError(`Unknown schema or catalog kind ${JSON.stringify(schemaOrKind)}.`);
|
|
366
315
|
}
|
|
@@ -983,7 +932,6 @@ function typedVariableErrors(errors, value) {
|
|
|
983
932
|
if (!errors.some((error) => error.instancePath.startsWith("/variables/"))) return errors;
|
|
984
933
|
const variables = value.variables;
|
|
985
934
|
const kept = errors.filter((error) => !error.instancePath.startsWith("/variables/"));
|
|
986
|
-
const schemaId = schemas.presentation.$id;
|
|
987
935
|
for (const [id, entry2] of Object.entries(variables)) {
|
|
988
936
|
if (typeof entry2 === "string") {
|
|
989
937
|
if (!hexColorPattern.test(entry2)) kept.push(variableIssue(id, "", "type", "must be a hex color string or a variable object", {}));
|
|
@@ -999,7 +947,7 @@ function typedVariableErrors(errors, value) {
|
|
|
999
947
|
continue;
|
|
1000
948
|
}
|
|
1001
949
|
const definition = `${kind.charAt(0).toUpperCase()}${kind.slice(1)}Variable`;
|
|
1002
|
-
const check =
|
|
950
|
+
const check = schemaEngine().definition("presentation", definition);
|
|
1003
951
|
if (!check || check(entry2) === true) continue;
|
|
1004
952
|
for (const error of check.errors ?? []) {
|
|
1005
953
|
kept.push({ ...error, instancePath: `/variables/${id.replaceAll("~", "~0").replaceAll("/", "~1")}${error.instancePath}`, schemaPath: `#/$defs/${definition}${error.schemaPath.replace(/^#/, "")}` });
|
|
@@ -1020,7 +968,6 @@ function pointerValue(root, pointer4) {
|
|
|
1020
968
|
var datasetTableMessage = (field) => `'${field}' is not allowed on a dataset-backed table: it takes its headers, rows and column formats from the dataset`;
|
|
1021
969
|
function dataUnionErrors(errors, value) {
|
|
1022
970
|
let kept = errors;
|
|
1023
|
-
const schemaId = schemas.presentation.$id;
|
|
1024
971
|
for (const union of errors) {
|
|
1025
972
|
if (union.keyword !== "oneOf") continue;
|
|
1026
973
|
const chartData = /\/chart\/data$/.test(union.instancePath) && /\/properties\/data\/oneOf$/.test(union.schemaPath);
|
|
@@ -1029,7 +976,7 @@ function dataUnionErrors(errors, value) {
|
|
|
1029
976
|
const target = pointerValue(value, union.instancePath);
|
|
1030
977
|
if (!isRecord(target)) continue;
|
|
1031
978
|
const branch = chartData ? hasOwn(target, "dataset") ? "DatasetRef" : hasOwn(target, "rows") ? "ChartData" : void 0 : hasOwn(target, "value") ? "StyledTableCell" : hasOwn(target, "name") ? "DataColumn" : void 0;
|
|
1032
|
-
const check = branch ?
|
|
979
|
+
const check = branch ? schemaEngine().definition("presentation", branch) : void 0;
|
|
1033
980
|
if (!check || check(target) === true) continue;
|
|
1034
981
|
const branchErrors = (check.errors ?? []).map((error) => ({ ...error, instancePath: `${union.instancePath}${error.instancePath}`, schemaPath: `#/$defs/${branch}${error.schemaPath.replace(/^#/, "")}` }));
|
|
1035
982
|
const prefix = `${union.instancePath}/`;
|
|
@@ -1076,7 +1023,7 @@ function validateAgainstSchema(value, schemaOrKind = "presentation", options2 =
|
|
|
1076
1023
|
const valid = resolved.validate(subject) === true;
|
|
1077
1024
|
const ajvErrors = valid ? [] : typedVariableErrors(resolved.validate.errors ?? [], subject);
|
|
1078
1025
|
const specific = resolved.schemaName === "presentation" ? dataUnionErrors(ajvErrors, subject) : ajvErrors;
|
|
1079
|
-
const mapped = bestMatchErrors(
|
|
1026
|
+
const mapped = bestMatchErrors(schemaEngine(), schemas[resolved.schemaName].$id, specific).map(toIssue);
|
|
1080
1027
|
const errors = mapped;
|
|
1081
1028
|
if (resolved.schemaName === "layout" && valid) for (const issue2 of layoutTemplateIssues(subject)) errors.push(semanticIssue(issue2.path, issue2.message, { code: issue2.code }));
|
|
1082
1029
|
const warnings = [];
|
|
@@ -1625,7 +1572,7 @@ var formatRules = [
|
|
|
1625
1572
|
"error",
|
|
1626
1573
|
"The document breaks the OPF schema or a structural rule the schema cannot express.",
|
|
1627
1574
|
"The schema is the contract every engine, exporter and editor relies on. A field of the wrong type, a missing required field, an unknown property or content fields that cannot be mixed make the document ambiguous or undrawable.",
|
|
1628
|
-
{ standard: SCHEMA, approximations: "All alternatives of a union are reported, with the failing schema location in `validation`. A required variable with no value is reported by `opf/variable-unfilled`, in the same category." }
|
|
1575
|
+
{ standard: SCHEMA, approximations: "All alternatives of a union are reported, with the failing schema location in `validation`. A required variable with no value is reported by `opf/variable-unfilled`, in the same category. A chart written in the Chart.js or ECharts shape (`categories` and `series`, or `labels` and `datasets`, and no `data`) is one finding on the chart whose hint shows its own values as `data: { columns, rows }`, with a patch fix; the additional-property findings that repeat it are dropped." }
|
|
1629
1576
|
),
|
|
1630
1577
|
rule("reference-id-duplicate", "format", "error", "Two references share an id.", "A citation names a reference by id; a repeated id makes it ambiguous which entry is cited.", { standard: SCHEMA }),
|
|
1631
1578
|
rule("cite-unknown-reference", "format", "error", "A citation names a reference that does not exist.", "A cited id with no entry in `references` has nothing to show in the footnote area.", { standard: SCHEMA }),
|
|
@@ -1707,7 +1654,7 @@ var referenceRules = [
|
|
|
1707
1654
|
"warning",
|
|
1708
1655
|
"A content reference resolves nowhere.",
|
|
1709
1656
|
"A layout, theme, colour scheme, font scheme, narrative, audience, purpose or tone reference that neither the document embeds nor a registered catalog defines falls back: a slide composes automatically, a design uses the engine default. A strict export fails instead. A slide with no layout is automatic composition and is never reported.",
|
|
1710
|
-
{ standard: SCHEMA, approximations:
|
|
1657
|
+
{ standard: SCHEMA, approximations: 'Resolved like every engine resolves it: catalogs.custom, then the records embedded under catalogs.default, then the catalog registered for its source (the first registered catalog when `default` is omitted); `name:id` in catalogs.<name>, then the catalog registered for its source. Nothing is fetched. Free-form audience and purpose text is not a reference. It is a warning, not an error, because catalogs are open and a host may register the id; `--fail-on warning` is the check that a deck is done. With a catalog registered, the hint names the nearest records that exist ("Did you mean `two-column`?").' }
|
|
1711
1658
|
),
|
|
1712
1659
|
rule(
|
|
1713
1660
|
"catalog-record-not-in-source",
|
|
@@ -1825,7 +1772,7 @@ var readingOrderRule = rule(
|
|
|
1825
1772
|
{
|
|
1826
1773
|
standard: 'WCAG 2.2 SC 1.3.2 Meaningful Sequence, level A (PowerPoint: "Check reading order")',
|
|
1827
1774
|
cost: "composition",
|
|
1828
|
-
approximations: "Compares the composed content order with a visual order recomputed from the composed boxes: items whose vertical centres fall in the same row are ordered along the reading direction (a right-to-left deck is checked by rows only), rows from top to bottom. Headings are expected first. Free-form overlap is not analysed. On a slide with a template layout (OPF 0.19) the expected order is the binding order instead (the regions in reading order, then the blocks of each region), and items outside a region (placed images, the row below the grid) are not compared."
|
|
1775
|
+
approximations: "Compares the composed content order with a visual order recomputed from the composed boxes: items whose vertical centres fall in the same row are ordered along the reading direction (a right-to-left deck is checked by rows only), rows from top to bottom. Headings are expected first. Content drawn entirely above the title, over the columns of the title, is reported; content in a column beside the title is read after it. Free-form overlap is not analysed. On a slide with a template layout (OPF 0.19) the expected order is the binding order instead (the regions in reading order, then the blocks of each region), and items outside a region (placed images, the row below the grid) are not compared."
|
|
1829
1776
|
}
|
|
1830
1777
|
);
|
|
1831
1778
|
var linkRule = rule(
|
|
@@ -2358,8 +2305,9 @@ var readingOrderRules = [
|
|
|
2358
2305
|
if (!composition) continue;
|
|
2359
2306
|
const body = composition.items.filter((item) => !["title", "subtitle", "tag"].includes(item.field));
|
|
2360
2307
|
const title = composition.items.find((item) => item.field === "title");
|
|
2361
|
-
|
|
2362
|
-
|
|
2308
|
+
const isAbove = (item) => item.box.y + item.box.height <= title.box.y + 1 && item.box.x < title.box.x + title.box.width && title.box.x < item.box.x + item.box.width;
|
|
2309
|
+
if (title && body.some(isAbove)) {
|
|
2310
|
+
const above = body.find(isAbove);
|
|
2363
2311
|
context.report(readingOrderRule, {
|
|
2364
2312
|
path: pointerOfDotted(above.path),
|
|
2365
2313
|
slide,
|
|
@@ -2457,7 +2405,8 @@ var chartRules = [
|
|
|
2457
2405
|
const count = slices ? data.rows.length : data.columns.length - 1;
|
|
2458
2406
|
if (count < 2) continue;
|
|
2459
2407
|
const surface = slide.design.colors.surface;
|
|
2460
|
-
const
|
|
2408
|
+
const paletteContext = chartColorContext(slide.design);
|
|
2409
|
+
const palette = chartPaletteForFill(surface, context.chartPalette ?? chartSeriesPalette(slide.design.colorScheme, chart.colors, paletteContext), { legibleLead: context.chartPalette === void 0 && chartLeadFromScheme(chart.colors, slide.design.colorScheme, paletteContext) });
|
|
2461
2410
|
if (!palette.length) continue;
|
|
2462
2411
|
const used = Array.from({ length: Math.min(count, 24) }, (_, i) => palette[i % palette.length]);
|
|
2463
2412
|
const pairs = [];
|
|
@@ -2897,6 +2846,60 @@ var layoutContentRules = [
|
|
|
2897
2846
|
// src/validation-rules.ts
|
|
2898
2847
|
var ruleImplementations = [...accessibilityRules, ...layoutContentRules, ...languageTagRules];
|
|
2899
2848
|
|
|
2849
|
+
// src/chart-shape.ts
|
|
2850
|
+
var FOREIGN_CHART_KEYS = ["categories", "series", "labels", "datasets"];
|
|
2851
|
+
var CHART_DEFINITION = "https://openpresentation.org/schema/opf/v1#/$defs/Chart";
|
|
2852
|
+
var isRecord2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2853
|
+
var isCell = (value) => value === null || ["string", "number", "boolean"].includes(typeof value);
|
|
2854
|
+
function foreignChartKeys(chart) {
|
|
2855
|
+
if (!isRecord2(chart) || Object.hasOwn(chart, "data")) return [];
|
|
2856
|
+
return FOREIGN_CHART_KEYS.filter((key2) => Object.hasOwn(chart, key2));
|
|
2857
|
+
}
|
|
2858
|
+
function convertChartData(chart) {
|
|
2859
|
+
const labels = chart.categories ?? chart.labels;
|
|
2860
|
+
const series = chart.series ?? chart.datasets;
|
|
2861
|
+
if (!Array.isArray(labels) || !labels.length || !labels.every(isCell) || !Array.isArray(series) || !series.length) return void 0;
|
|
2862
|
+
const columns = ["Category"];
|
|
2863
|
+
const values = [];
|
|
2864
|
+
for (const [index, entry2] of series.entries()) {
|
|
2865
|
+
if (!isRecord2(entry2)) return void 0;
|
|
2866
|
+
const list = entry2.values ?? entry2.data;
|
|
2867
|
+
const name = entry2.name ?? entry2.label;
|
|
2868
|
+
if (!Array.isArray(list) || list.length !== labels.length || !list.every(isCell)) return void 0;
|
|
2869
|
+
columns.push(typeof name === "string" && name ? name : `Series ${index + 1}`);
|
|
2870
|
+
values.push(list);
|
|
2871
|
+
}
|
|
2872
|
+
if (new Set(columns).size !== columns.length) return void 0;
|
|
2873
|
+
return { columns, rows: labels.map((label, row) => [label, ...values.map((list) => list[row])]) };
|
|
2874
|
+
}
|
|
2875
|
+
function chartShapePatch(chart, path) {
|
|
2876
|
+
if (!isRecord2(chart)) return void 0;
|
|
2877
|
+
const data = convertChartData(chart);
|
|
2878
|
+
const keys = foreignChartKeys(chart);
|
|
2879
|
+
if (!data || !keys.length) return void 0;
|
|
2880
|
+
return [{ op: "add", path: `${path}/data`, value: data }, ...keys.map((key2) => ({ op: "remove", path: `${path}/${key2}` }))];
|
|
2881
|
+
}
|
|
2882
|
+
var SHOWN_ROWS = 3;
|
|
2883
|
+
var json = (value) => JSON.stringify(value);
|
|
2884
|
+
function dataExample(chart) {
|
|
2885
|
+
const data = convertChartData(chart);
|
|
2886
|
+
if (!data) return '"data": { "columns": ["Category", "Series name"], "rows": [["Q1", 3], ["Q2", 8]] }';
|
|
2887
|
+
const rows = data.rows.slice(0, SHOWN_ROWS).map(json);
|
|
2888
|
+
return `"data": { "columns": ${json(data.columns)}, "rows": [${rows.join(",")}${data.rows.length > SHOWN_ROWS ? ",..." : ""}] }`;
|
|
2889
|
+
}
|
|
2890
|
+
function chartShapeHelp(chart) {
|
|
2891
|
+
const keys = foreignChartKeys(chart);
|
|
2892
|
+
if (!keys.length || !isRecord2(chart)) return void 0;
|
|
2893
|
+
const names2 = keys.map((key2) => `"${key2}"`).join(" and ");
|
|
2894
|
+
const example = dataExample(chart);
|
|
2895
|
+
const next = `replace ${names2} with ${example}. The first column holds the category labels and each further column is one series.`;
|
|
2896
|
+
return {
|
|
2897
|
+
message: `The chart has ${names2} (the Chart.js and ECharts shape), but an OPF chart keeps its values in "data": { "columns", "rows" }.`,
|
|
2898
|
+
next,
|
|
2899
|
+
help: `OPF charts use "data": { "columns", "rows" }, not ${names2}. Replace ${names2} with ${example}; the first column holds the category labels and each further column is one series. See the Chart definition: ${CHART_DEFINITION} (opf schema presentation '/$defs/Chart').`
|
|
2900
|
+
};
|
|
2901
|
+
}
|
|
2902
|
+
|
|
2900
2903
|
// src/check-document.ts
|
|
2901
2904
|
var own = (value, key2) => Object.hasOwn(value, key2);
|
|
2902
2905
|
var object = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -3219,12 +3222,42 @@ var HELP = {
|
|
|
3219
3222
|
"numbering-start-ignored": "Add a 'numbering' field to the payload, or remove 'start'.",
|
|
3220
3223
|
"slide-size-out-of-range": "Use a custom widthInches and heightInches between 1 and 56, or a preset. PowerPoint stores the slide size in 914400 to 51206400 EMU per side."
|
|
3221
3224
|
};
|
|
3225
|
+
function collapseChartShape(document, findings) {
|
|
3226
|
+
const chartAt = (path) => {
|
|
3227
|
+
let node = document;
|
|
3228
|
+
for (const segment of splitPointer(path)) node = Array.isArray(node) ? node[Number(segment)] : isRecord(node) ? node[segment] : void 0;
|
|
3229
|
+
return node;
|
|
3230
|
+
};
|
|
3231
|
+
const collapsed = /* @__PURE__ */ new Set();
|
|
3232
|
+
for (const [index, entry2] of findings.entries()) {
|
|
3233
|
+
if (entry2.ruleId !== "opf/schema" || entry2.validation?.keyword !== "required" || entry2.validation.params.missingProperty !== "data") continue;
|
|
3234
|
+
const chart = chartAt(entry2.path);
|
|
3235
|
+
const hint = chartShapeHelp(chart);
|
|
3236
|
+
if (!hint) continue;
|
|
3237
|
+
const patch2 = chartShapePatch(chart, entry2.path);
|
|
3238
|
+
findings[index] = {
|
|
3239
|
+
...entry2,
|
|
3240
|
+
message: hint.message,
|
|
3241
|
+
help: hint.help,
|
|
3242
|
+
...patch2 ? { fixes: [{ id: "convert-chart-data", title: "Convert to data: { columns, rows }", kind: "patch", safe: false, patch: patch2 }] } : {}
|
|
3243
|
+
};
|
|
3244
|
+
collapsed.add(entry2.path);
|
|
3245
|
+
}
|
|
3246
|
+
if (!collapsed.size) return;
|
|
3247
|
+
for (let index = findings.length - 1; index >= 0; index--) {
|
|
3248
|
+
const entry2 = findings[index];
|
|
3249
|
+
if (entry2?.ruleId !== "opf/schema" || entry2.validation?.keyword !== "additionalProperties") continue;
|
|
3250
|
+
const at2 = entry2.path.lastIndexOf("/");
|
|
3251
|
+
if (collapsed.has(entry2.path.slice(0, at2)) && FOREIGN_CHART_KEYS.includes(entry2.path.slice(at2 + 1))) findings.splice(index, 1);
|
|
3252
|
+
}
|
|
3253
|
+
}
|
|
3222
3254
|
function engineFindings(document, engine, enabled) {
|
|
3223
3255
|
const findings = [];
|
|
3224
3256
|
for (const issue2 of engine.errors) {
|
|
3225
3257
|
const ruleId = issueRuleId(issue2);
|
|
3226
3258
|
if (enabled(ruleId)) findings.push(issueFinding(issue2, ruleId));
|
|
3227
3259
|
}
|
|
3260
|
+
collapseChartShape(document, findings);
|
|
3228
3261
|
let numberFixes;
|
|
3229
3262
|
for (const issue2 of engine.warnings) {
|
|
3230
3263
|
const code2 = issue2.params.code;
|
|
@@ -3326,6 +3359,13 @@ function undeclaredCatalogFindings(document) {
|
|
|
3326
3359
|
}
|
|
3327
3360
|
return findings;
|
|
3328
3361
|
}
|
|
3362
|
+
var KIND_PLURAL = { layouts: "layouts", themes: "themes", colorSchemes: "color schemes", fontSchemes: "font schemes", narratives: "narratives", audiences: "audiences", purposes: "purposes", tones: "tones" };
|
|
3363
|
+
function nearestRecords(kind, reference, candidates) {
|
|
3364
|
+
if (!candidates.length) return "";
|
|
3365
|
+
const close = candidates.filter((value) => distance(reference, value) <= Math.max(2, Math.floor(reference.length / 4))).slice(0, 3);
|
|
3366
|
+
const quote = (values) => values.map((value) => `'${value}'`).join(", ");
|
|
3367
|
+
return close.length ? `Did you mean ${quote(close)}? ` : `The nearest ${KIND_PLURAL[kind]} that exist: ${quote(candidates.slice(0, 3))}. `;
|
|
3368
|
+
}
|
|
3329
3369
|
function contentReferenceFindings(document, options2, findings) {
|
|
3330
3370
|
const invalid = embeddedRecordFindings(document, options2, findings);
|
|
3331
3371
|
const registeredChecked = /* @__PURE__ */ new Set();
|
|
@@ -3346,7 +3386,7 @@ function contentReferenceFindings(document, options2, findings) {
|
|
|
3346
3386
|
finding("opf/unresolved-reference", {
|
|
3347
3387
|
path,
|
|
3348
3388
|
message: diagnostic.message,
|
|
3349
|
-
help: site.kind === "layouts" ? "Embed the layout record (embed(), or opf embed), register the catalog that defines it, choose one of the suggested layouts, or remove the reference to compose the slide automatically." : "Embed the record (embed(), or opf embed), register the catalog that defines it, or choose one of the suggested records."
|
|
3389
|
+
help: `${nearestRecords(site.kind, site.reference, suggestions.map((entry2) => entry2.value))}${site.kind === "layouts" ? "Embed the layout record (embed(), or opf embed), register the catalog that defines it, choose one of the suggested layouts, or remove the reference to compose the slide automatically." : "Embed the record (embed(), or opf embed), register the catalog that defines it, or choose one of the suggested records."}`,
|
|
3350
3390
|
definition: `${schemas.presentation.$id}#/$defs/Catalogs`,
|
|
3351
3391
|
lookup: ["opf", "catalog", site.kind],
|
|
3352
3392
|
suggestions
|
|
@@ -3526,6 +3566,157 @@ function contractFindings(document, contracts) {
|
|
|
3526
3566
|
return findings;
|
|
3527
3567
|
}
|
|
3528
3568
|
|
|
3569
|
+
// src/document-hash.ts
|
|
3570
|
+
function canonicalJson(value) {
|
|
3571
|
+
const stack = [];
|
|
3572
|
+
const write = (item) => {
|
|
3573
|
+
if (item === null || typeof item === "boolean" || typeof item === "string") return JSON.stringify(item);
|
|
3574
|
+
if (typeof item === "number") return JSON.stringify(item);
|
|
3575
|
+
if (typeof item === "bigint") throw new TypeError("A BigInt is not JSON.");
|
|
3576
|
+
if (typeof item !== "object") return void 0;
|
|
3577
|
+
if (stack.includes(item)) throw new TypeError("A cyclic value has no canonical JSON.");
|
|
3578
|
+
stack.push(item);
|
|
3579
|
+
let text2;
|
|
3580
|
+
if (Array.isArray(item)) {
|
|
3581
|
+
text2 = `[${item.map((entry2) => write(entry2) ?? "null").join(",")}]`;
|
|
3582
|
+
} else {
|
|
3583
|
+
const record = item;
|
|
3584
|
+
const members = [];
|
|
3585
|
+
for (const key2 of Object.keys(record).sort()) {
|
|
3586
|
+
const member = write(record[key2]);
|
|
3587
|
+
if (member !== void 0) members.push(`${JSON.stringify(key2)}:${member}`);
|
|
3588
|
+
}
|
|
3589
|
+
text2 = `{${members.join(",")}}`;
|
|
3590
|
+
}
|
|
3591
|
+
stack.pop();
|
|
3592
|
+
return text2;
|
|
3593
|
+
};
|
|
3594
|
+
return write(value) ?? "null";
|
|
3595
|
+
}
|
|
3596
|
+
var K = new Uint32Array([
|
|
3597
|
+
1116352408,
|
|
3598
|
+
1899447441,
|
|
3599
|
+
3049323471,
|
|
3600
|
+
3921009573,
|
|
3601
|
+
961987163,
|
|
3602
|
+
1508970993,
|
|
3603
|
+
2453635748,
|
|
3604
|
+
2870763221,
|
|
3605
|
+
3624381080,
|
|
3606
|
+
310598401,
|
|
3607
|
+
607225278,
|
|
3608
|
+
1426881987,
|
|
3609
|
+
1925078388,
|
|
3610
|
+
2162078206,
|
|
3611
|
+
2614888103,
|
|
3612
|
+
3248222580,
|
|
3613
|
+
3835390401,
|
|
3614
|
+
4022224774,
|
|
3615
|
+
264347078,
|
|
3616
|
+
604807628,
|
|
3617
|
+
770255983,
|
|
3618
|
+
1249150122,
|
|
3619
|
+
1555081692,
|
|
3620
|
+
1996064986,
|
|
3621
|
+
2554220882,
|
|
3622
|
+
2821834349,
|
|
3623
|
+
2952996808,
|
|
3624
|
+
3210313671,
|
|
3625
|
+
3336571891,
|
|
3626
|
+
3584528711,
|
|
3627
|
+
113926993,
|
|
3628
|
+
338241895,
|
|
3629
|
+
666307205,
|
|
3630
|
+
773529912,
|
|
3631
|
+
1294757372,
|
|
3632
|
+
1396182291,
|
|
3633
|
+
1695183700,
|
|
3634
|
+
1986661051,
|
|
3635
|
+
2177026350,
|
|
3636
|
+
2456956037,
|
|
3637
|
+
2730485921,
|
|
3638
|
+
2820302411,
|
|
3639
|
+
3259730800,
|
|
3640
|
+
3345764771,
|
|
3641
|
+
3516065817,
|
|
3642
|
+
3600352804,
|
|
3643
|
+
4094571909,
|
|
3644
|
+
275423344,
|
|
3645
|
+
430227734,
|
|
3646
|
+
506948616,
|
|
3647
|
+
659060556,
|
|
3648
|
+
883997877,
|
|
3649
|
+
958139571,
|
|
3650
|
+
1322822218,
|
|
3651
|
+
1537002063,
|
|
3652
|
+
1747873779,
|
|
3653
|
+
1955562222,
|
|
3654
|
+
2024104815,
|
|
3655
|
+
2227730452,
|
|
3656
|
+
2361852424,
|
|
3657
|
+
2428436474,
|
|
3658
|
+
2756734187,
|
|
3659
|
+
3204031479,
|
|
3660
|
+
3329325298
|
|
3661
|
+
]);
|
|
3662
|
+
function sha256Hex(bytes) {
|
|
3663
|
+
const length = bytes.length;
|
|
3664
|
+
const padded = new Uint8Array(length + 9 + 63 >> 6 << 6);
|
|
3665
|
+
padded.set(bytes);
|
|
3666
|
+
padded[length] = 128;
|
|
3667
|
+
const view = new DataView(padded.buffer);
|
|
3668
|
+
view.setUint32(padded.length - 8, Math.floor(length / 536870912), false);
|
|
3669
|
+
view.setUint32(padded.length - 4, length << 3 >>> 0, false);
|
|
3670
|
+
const h = new Uint32Array([1779033703, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635, 1541459225]);
|
|
3671
|
+
const w = new Uint32Array(64);
|
|
3672
|
+
for (let offset = 0; offset < padded.length; offset += 64) {
|
|
3673
|
+
for (let i = 0; i < 16; i += 1) w[i] = view.getUint32(offset + i * 4, false);
|
|
3674
|
+
for (let i = 16; i < 64; i += 1) {
|
|
3675
|
+
const a2 = w[i - 15], b2 = w[i - 2];
|
|
3676
|
+
const s0 = (a2 >>> 7 | a2 << 25) ^ (a2 >>> 18 | a2 << 14) ^ a2 >>> 3;
|
|
3677
|
+
const s1 = (b2 >>> 17 | b2 << 15) ^ (b2 >>> 19 | b2 << 13) ^ b2 >>> 10;
|
|
3678
|
+
w[i] = w[i - 16] + s0 + w[i - 7] + s1 | 0;
|
|
3679
|
+
}
|
|
3680
|
+
let a = h[0], b = h[1], c = h[2], d = h[3], e = h[4], f = h[5], g = h[6], hh = h[7];
|
|
3681
|
+
for (let i = 0; i < 64; i += 1) {
|
|
3682
|
+
const s1 = (e >>> 6 | e << 26) ^ (e >>> 11 | e << 21) ^ (e >>> 25 | e << 7);
|
|
3683
|
+
const choose = e & f ^ ~e & g;
|
|
3684
|
+
const t1 = hh + s1 + choose + K[i] + w[i] | 0;
|
|
3685
|
+
const s0 = (a >>> 2 | a << 30) ^ (a >>> 13 | a << 19) ^ (a >>> 22 | a << 10);
|
|
3686
|
+
const majority = a & b ^ a & c ^ b & c;
|
|
3687
|
+
const t2 = s0 + majority | 0;
|
|
3688
|
+
hh = g;
|
|
3689
|
+
g = f;
|
|
3690
|
+
f = e;
|
|
3691
|
+
e = d + t1 | 0;
|
|
3692
|
+
d = c;
|
|
3693
|
+
c = b;
|
|
3694
|
+
b = a;
|
|
3695
|
+
a = t1 + t2 | 0;
|
|
3696
|
+
}
|
|
3697
|
+
h[0] = h[0] + a | 0;
|
|
3698
|
+
h[1] = h[1] + b | 0;
|
|
3699
|
+
h[2] = h[2] + c | 0;
|
|
3700
|
+
h[3] = h[3] + d | 0;
|
|
3701
|
+
h[4] = h[4] + e | 0;
|
|
3702
|
+
h[5] = h[5] + f | 0;
|
|
3703
|
+
h[6] = h[6] + g | 0;
|
|
3704
|
+
h[7] = h[7] + hh | 0;
|
|
3705
|
+
}
|
|
3706
|
+
let hex = "";
|
|
3707
|
+
for (const word of h) hex += word.toString(16).padStart(8, "0");
|
|
3708
|
+
return hex;
|
|
3709
|
+
}
|
|
3710
|
+
function documentHash(document) {
|
|
3711
|
+
return `sha256:${sha256Hex(new TextEncoder().encode(canonicalJson(document)))}`;
|
|
3712
|
+
}
|
|
3713
|
+
var HASH_PATTERN = /^(?:sha256:)?([0-9a-fA-F]{64})$/;
|
|
3714
|
+
function normalizeDocumentHash(value) {
|
|
3715
|
+
if (typeof value !== "string") return void 0;
|
|
3716
|
+
const match2 = HASH_PATTERN.exec(value);
|
|
3717
|
+
return match2 ? `sha256:${match2[1].toLowerCase()}` : void 0;
|
|
3718
|
+
}
|
|
3719
|
+
|
|
3529
3720
|
// src/patch.ts
|
|
3530
3721
|
var OPFPatchError = class extends Error {
|
|
3531
3722
|
code;
|
|
@@ -3552,6 +3743,18 @@ var OPFPatchValidationError = class extends OPFPatchError {
|
|
|
3552
3743
|
this.validation = validation;
|
|
3553
3744
|
}
|
|
3554
3745
|
};
|
|
3746
|
+
var OPFPatchHashError = class extends OPFPatchError {
|
|
3747
|
+
/** The hash the caller expected, in the form `documentHash` returns. */
|
|
3748
|
+
expected;
|
|
3749
|
+
/** The hash of the document the patch was given. */
|
|
3750
|
+
actual;
|
|
3751
|
+
constructor(expected, actual) {
|
|
3752
|
+
super("patch-hash-mismatch", "The document changed since it was read: its hash is not the expected hash. Nothing was applied.");
|
|
3753
|
+
this.name = "OPFPatchHashError";
|
|
3754
|
+
this.expected = expected;
|
|
3755
|
+
this.actual = actual;
|
|
3756
|
+
}
|
|
3757
|
+
};
|
|
3555
3758
|
var own2 = (value, key2) => Object.prototype.hasOwnProperty.call(value, key2);
|
|
3556
3759
|
var isObject = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
3557
3760
|
var clone = (value) => structuredClone(value);
|
|
@@ -3597,13 +3800,83 @@ function splitPointer2(pointer4) {
|
|
|
3597
3800
|
if (!tokens.length) throw new OPFPatchError("invalid-json-pointer", "The root pointer has no parent.", { path: pointer4 });
|
|
3598
3801
|
return { parent: formatPointer(tokens.slice(0, -1)), token: tokens[tokens.length - 1] };
|
|
3599
3802
|
}
|
|
3803
|
+
var isIdToken = (token) => token.length > 1 && token.startsWith("@");
|
|
3804
|
+
var idToken = (id) => `@${id}`;
|
|
3805
|
+
var INDEX_TOKEN = /^(0|[1-9][0-9]*)$/;
|
|
3806
|
+
function indexOfId(array, id) {
|
|
3807
|
+
let found = -1;
|
|
3808
|
+
for (let i = 0; i < array.length; i += 1) {
|
|
3809
|
+
const item = array[i];
|
|
3810
|
+
if (isObject(item) && own2(item, "id") && item.id === id) {
|
|
3811
|
+
if (found !== -1) return -2;
|
|
3812
|
+
found = i;
|
|
3813
|
+
}
|
|
3814
|
+
}
|
|
3815
|
+
return found;
|
|
3816
|
+
}
|
|
3817
|
+
function uniqueIdAt(array, at2) {
|
|
3818
|
+
const item = array[at2];
|
|
3819
|
+
if (!isObject(item) || !own2(item, "id") || typeof item.id !== "string" || item.id === "") return void 0;
|
|
3820
|
+
return indexOfId(array, item.id) === at2 ? item.id : void 0;
|
|
3821
|
+
}
|
|
3822
|
+
function resolveTokens(document, tokens, pointer4) {
|
|
3823
|
+
const out = [];
|
|
3824
|
+
let cursor = document, walking = true;
|
|
3825
|
+
for (const token of tokens) {
|
|
3826
|
+
let resolved = token;
|
|
3827
|
+
if (walking && Array.isArray(cursor) && isIdToken(token)) {
|
|
3828
|
+
const at2 = indexOfId(cursor, token.slice(1));
|
|
3829
|
+
if (at2 === -1) throw new OPFPatchError("patch-id-not-found", `No element of ${formatPointer(out) || "/"} has the id '${token.slice(1)}'.`, { path: pointer4 });
|
|
3830
|
+
if (at2 === -2) throw new OPFPatchError("patch-id-ambiguous", `More than one element of ${formatPointer(out) || "/"} has the id '${token.slice(1)}'.`, { path: pointer4 });
|
|
3831
|
+
resolved = String(at2);
|
|
3832
|
+
}
|
|
3833
|
+
out.push(resolved);
|
|
3834
|
+
if (walking) {
|
|
3835
|
+
const next = readPointer(cursor, [resolved]);
|
|
3836
|
+
if (next.found) cursor = next.value;
|
|
3837
|
+
else walking = false;
|
|
3838
|
+
}
|
|
3839
|
+
}
|
|
3840
|
+
return out;
|
|
3841
|
+
}
|
|
3842
|
+
function resolveIdPointer(document, pointer4) {
|
|
3843
|
+
const tokens = parsePointer(pointer4);
|
|
3844
|
+
return tokens.some(isIdToken) ? formatPointer(resolveTokens(document, tokens, pointer4)) : pointer4;
|
|
3845
|
+
}
|
|
3846
|
+
function idTokens(document, tokens, convertLast) {
|
|
3847
|
+
const out = [];
|
|
3848
|
+
let cursor = document, walking = true;
|
|
3849
|
+
tokens.forEach((token, i) => {
|
|
3850
|
+
let named = token;
|
|
3851
|
+
if (walking && Array.isArray(cursor) && INDEX_TOKEN.test(token) && (convertLast || i < tokens.length - 1)) {
|
|
3852
|
+
const id = uniqueIdAt(cursor, Number(token));
|
|
3853
|
+
if (id !== void 0) named = idToken(id);
|
|
3854
|
+
}
|
|
3855
|
+
out.push(named);
|
|
3856
|
+
if (walking) {
|
|
3857
|
+
const next = readPointer(cursor, [token]);
|
|
3858
|
+
if (next.found) cursor = next.value;
|
|
3859
|
+
else walking = false;
|
|
3860
|
+
}
|
|
3861
|
+
});
|
|
3862
|
+
return out;
|
|
3863
|
+
}
|
|
3864
|
+
function toIdPointer(document, pointer4, options2 = {}) {
|
|
3865
|
+
return formatPointer(idTokens(document, resolveTokens(document, parsePointer(pointer4), pointer4), !options2.keepLast));
|
|
3866
|
+
}
|
|
3600
3867
|
function readPointer(document, pointer4) {
|
|
3601
3868
|
const tokens = typeof pointer4 === "string" ? parsePointer(pointer4) : pointer4;
|
|
3602
3869
|
let value = document;
|
|
3603
3870
|
for (const token of tokens) {
|
|
3604
3871
|
if (Array.isArray(value)) {
|
|
3605
|
-
|
|
3606
|
-
|
|
3872
|
+
let at2;
|
|
3873
|
+
if (isIdToken(token)) {
|
|
3874
|
+
at2 = indexOfId(value, token.slice(1));
|
|
3875
|
+
if (at2 < 0) return { found: false };
|
|
3876
|
+
} else {
|
|
3877
|
+
if (!INDEX_TOKEN.test(token)) return { found: false };
|
|
3878
|
+
at2 = Number(token);
|
|
3879
|
+
}
|
|
3607
3880
|
if (!Number.isSafeInteger(at2) || at2 >= value.length) return { found: false };
|
|
3608
3881
|
value = value[at2];
|
|
3609
3882
|
} else if (value && typeof value === "object" && own2(value, token)) value = value[token];
|
|
@@ -3622,7 +3895,7 @@ function getAtPointer(document, pointer4) {
|
|
|
3622
3895
|
var hasPointer = (document, pointer4) => readPointer(document, pointer4).found;
|
|
3623
3896
|
function arrayIndex(token, length, allowEnd, path) {
|
|
3624
3897
|
if (allowEnd && token === "-") return length;
|
|
3625
|
-
if (
|
|
3898
|
+
if (!INDEX_TOKEN.test(token)) throw new OPFPatchError("invalid-array-index", `Invalid array index: ${token}`, { path });
|
|
3626
3899
|
const at2 = Number(token);
|
|
3627
3900
|
if (!Number.isSafeInteger(at2) || at2 > length || !allowEnd && at2 >= length) throw new OPFPatchError("invalid-array-index", `Array index out of bounds: ${token}`, { path });
|
|
3628
3901
|
return at2;
|
|
@@ -3667,38 +3940,42 @@ function parentOf(document, tokens, path) {
|
|
|
3667
3940
|
}
|
|
3668
3941
|
var NONE = /* @__PURE__ */ Symbol("none");
|
|
3669
3942
|
function addAt(document, path, value) {
|
|
3670
|
-
const tokens = parsePointer(path);
|
|
3671
|
-
if (!tokens.length) return { document: clone(value), inverse: { op: "replace", path: "", value: clone(document) } };
|
|
3943
|
+
const tokens = resolveTokens(document, parsePointer(path), path);
|
|
3944
|
+
if (!tokens.length) return { document: clone(value), inverse: { op: "replace", path: "", value: clone(document) }, pointer: "" };
|
|
3672
3945
|
const { parent, key: key2 } = parentOf(document, tokens, path);
|
|
3673
3946
|
if (Array.isArray(parent)) {
|
|
3674
3947
|
const at2 = arrayIndex(key2, parent.length, true, path);
|
|
3675
3948
|
parent.splice(at2, 0, clone(value));
|
|
3676
|
-
|
|
3949
|
+
const pointer5 = formatPointer([...tokens.slice(0, -1), at2]);
|
|
3950
|
+
return { document, inverse: { op: "remove", path: pointer5 }, pointer: pointer5 };
|
|
3677
3951
|
}
|
|
3678
3952
|
const record = parent;
|
|
3679
3953
|
const previous = own2(record, key2) ? record[key2] : NONE;
|
|
3680
3954
|
Object.defineProperty(record, key2, { value: clone(value), enumerable: true, configurable: true, writable: true });
|
|
3681
|
-
|
|
3955
|
+
const pointer4 = formatPointer(tokens);
|
|
3956
|
+
return { document, inverse: previous === NONE ? { op: "remove", path: pointer4 } : { op: "replace", path: pointer4, value: clone(previous) }, pointer: pointer4 };
|
|
3682
3957
|
}
|
|
3683
3958
|
function replaceAt(document, path, value) {
|
|
3684
|
-
const tokens = parsePointer(path);
|
|
3685
|
-
if (!tokens.length) return { document: clone(value), inverse: { op: "replace", path: "", value: clone(document) } };
|
|
3959
|
+
const tokens = resolveTokens(document, parsePointer(path), path);
|
|
3960
|
+
if (!tokens.length) return { document: clone(value), inverse: { op: "replace", path: "", value: clone(document) }, pointer: "" };
|
|
3686
3961
|
const { parent, key: key2 } = parentOf(document, tokens, path);
|
|
3687
3962
|
let previous;
|
|
3963
|
+
let pointer4 = formatPointer(tokens);
|
|
3688
3964
|
if (Array.isArray(parent)) {
|
|
3689
3965
|
const at2 = arrayIndex(key2, parent.length, false, path);
|
|
3690
3966
|
previous = parent[at2];
|
|
3691
3967
|
parent[at2] = clone(value);
|
|
3968
|
+
pointer4 = formatPointer([...tokens.slice(0, -1), at2]);
|
|
3692
3969
|
} else {
|
|
3693
3970
|
const record = parent;
|
|
3694
3971
|
if (!own2(record, key2)) throw new OPFPatchError("patch-path-missing", `Patch path does not exist: ${path}.`, { path });
|
|
3695
3972
|
previous = record[key2];
|
|
3696
3973
|
Object.defineProperty(record, key2, { value: clone(value), enumerable: true, configurable: true, writable: true });
|
|
3697
3974
|
}
|
|
3698
|
-
return { document, inverse: { op: "replace", path, value: clone(previous) } };
|
|
3975
|
+
return { document, inverse: { op: "replace", path: pointer4, value: clone(previous) }, pointer: pointer4 };
|
|
3699
3976
|
}
|
|
3700
3977
|
function removeAt(document, path) {
|
|
3701
|
-
const tokens = parsePointer(path);
|
|
3978
|
+
const tokens = resolveTokens(document, parsePointer(path), path);
|
|
3702
3979
|
if (!tokens.length) throw new OPFPatchError("patch-root-remove", "The document root cannot be removed.", { path });
|
|
3703
3980
|
const { parent, key: key2 } = parentOf(document, tokens, path);
|
|
3704
3981
|
let previous;
|
|
@@ -3706,60 +3983,71 @@ function removeAt(document, path) {
|
|
|
3706
3983
|
const at2 = arrayIndex(key2, parent.length, false, path);
|
|
3707
3984
|
previous = parent[at2];
|
|
3708
3985
|
parent.splice(at2, 1);
|
|
3709
|
-
|
|
3986
|
+
const pointer5 = formatPointer([...tokens.slice(0, -1), at2]);
|
|
3987
|
+
return { document, inverse: { op: "add", path: pointer5, value: clone(previous) }, pointer: pointer5 };
|
|
3710
3988
|
}
|
|
3711
3989
|
const record = parent;
|
|
3712
3990
|
if (!own2(record, key2)) throw new OPFPatchError("patch-path-missing", `Patch path does not exist: ${path}.`, { path });
|
|
3713
3991
|
previous = record[key2];
|
|
3714
3992
|
delete record[key2];
|
|
3715
|
-
|
|
3993
|
+
const pointer4 = formatPointer(tokens);
|
|
3994
|
+
return { document, inverse: { op: "add", path: pointer4, value: clone(previous) }, pointer: pointer4 };
|
|
3716
3995
|
}
|
|
3717
3996
|
function applyOne(document, operation) {
|
|
3718
3997
|
switch (operation.op) {
|
|
3719
3998
|
case "add": {
|
|
3720
3999
|
const r = addAt(document, operation.path, operation.value);
|
|
3721
|
-
return { document: r.document, inverse: [r.inverse] };
|
|
4000
|
+
return { document: r.document, inverse: [r.inverse], resolved: { op: "add", path: r.pointer, value: operation.value } };
|
|
3722
4001
|
}
|
|
3723
4002
|
case "replace": {
|
|
3724
4003
|
const r = replaceAt(document, operation.path, operation.value);
|
|
3725
|
-
return { document: r.document, inverse: [r.inverse] };
|
|
4004
|
+
return { document: r.document, inverse: [r.inverse], resolved: { op: "replace", path: r.pointer, value: operation.value } };
|
|
3726
4005
|
}
|
|
3727
4006
|
case "remove": {
|
|
3728
4007
|
const r = removeAt(document, operation.path);
|
|
3729
|
-
return { document: r.document, inverse: [r.inverse] };
|
|
4008
|
+
return { document: r.document, inverse: [r.inverse], resolved: { op: "remove", path: r.pointer } };
|
|
3730
4009
|
}
|
|
3731
4010
|
case "test": {
|
|
3732
4011
|
const found = readPointer(document, operation.path);
|
|
3733
4012
|
if (!found.found || !jsonEqual(found.value, operation.value)) throw new OPFPatchError("patch-test-failed", `Test failed at ${operation.path || "/"}: the value changed.`, { path: operation.path });
|
|
3734
|
-
return { document, inverse: [] };
|
|
4013
|
+
return { document, inverse: [], resolved: { op: "test", path: resolveIdPointer(document, operation.path), value: operation.value } };
|
|
3735
4014
|
}
|
|
3736
4015
|
case "copy": {
|
|
3737
|
-
const
|
|
4016
|
+
const from = resolveIdPointer(document, operation.from);
|
|
4017
|
+
const value = clone(getAtPointer(document, from));
|
|
3738
4018
|
const r = addAt(document, operation.path, value);
|
|
3739
|
-
return { document: r.document, inverse: [r.inverse] };
|
|
4019
|
+
return { document: r.document, inverse: [r.inverse], resolved: { op: "copy", from, path: r.pointer } };
|
|
3740
4020
|
}
|
|
3741
4021
|
case "move": {
|
|
3742
|
-
const from = parsePointer(operation.from),
|
|
4022
|
+
const from = resolveTokens(document, parsePointer(operation.from), operation.from);
|
|
4023
|
+
let to;
|
|
4024
|
+
try {
|
|
4025
|
+
to = resolveTokens(document, parsePointer(operation.path), operation.path);
|
|
4026
|
+
} catch {
|
|
4027
|
+
to = parsePointer(operation.path);
|
|
4028
|
+
}
|
|
3743
4029
|
const value = clone(getAtPointer(document, from));
|
|
3744
|
-
if (from.length === to.length && from.every((token, i) => token === to[i])) return { document, inverse: [] };
|
|
4030
|
+
if (from.length === to.length && from.every((token, i) => token === to[i])) return { document, inverse: [], resolved: { op: "move", from: formatPointer(from), path: formatPointer(to) } };
|
|
3745
4031
|
if (to.length > from.length && from.every((token, i) => to[i] === token)) {
|
|
3746
4032
|
throw new OPFPatchError("patch-invalid-move", "Cannot move a value into its descendant.", { path: operation.path });
|
|
3747
4033
|
}
|
|
3748
|
-
const removed = removeAt(document,
|
|
4034
|
+
const removed = removeAt(document, formatPointer(from));
|
|
3749
4035
|
const added = addAt(removed.document, operation.path, value);
|
|
3750
|
-
return { document: added.document, inverse: [added.inverse, removed.inverse] };
|
|
4036
|
+
return { document: added.document, inverse: [added.inverse, removed.inverse], resolved: { op: "move", from: removed.pointer, path: added.pointer } };
|
|
3751
4037
|
}
|
|
3752
4038
|
}
|
|
3753
4039
|
}
|
|
3754
|
-
function
|
|
4040
|
+
function walkPatch(document, patch2, hooks = {}) {
|
|
3755
4041
|
const operations = normalizePatch(patch2);
|
|
3756
4042
|
let working = clone(document);
|
|
3757
4043
|
const inverse = [];
|
|
3758
4044
|
for (const [index, operation] of operations.entries()) {
|
|
3759
4045
|
try {
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
4046
|
+
hooks.before?.(index, operation, working);
|
|
4047
|
+
const applied = applyOne(working, operation);
|
|
4048
|
+
working = applied.document;
|
|
4049
|
+
inverse.unshift(...applied.inverse);
|
|
4050
|
+
hooks.after?.({ index, operation, resolved: applied.resolved, inverse: applied.inverse }, working);
|
|
3763
4051
|
} catch (error) {
|
|
3764
4052
|
if (error instanceof OPFPatchError && error.index === void 0) {
|
|
3765
4053
|
const wrapped = new OPFPatchError(error.code, `Operation ${index}: ${error.message}`, { path: error.path, index, operation });
|
|
@@ -3768,6 +4056,17 @@ function applyPatchWithInverse(document, patch2, options2 = {}) {
|
|
|
3768
4056
|
throw error;
|
|
3769
4057
|
}
|
|
3770
4058
|
}
|
|
4059
|
+
return { document: working, operations, inverse };
|
|
4060
|
+
}
|
|
4061
|
+
function assertExpectedHash(document, expectHash) {
|
|
4062
|
+
const expected = normalizeDocumentHash(expectHash);
|
|
4063
|
+
if (expected === void 0) throw new OPFPatchError("invalid-expect-hash", "expectHash must be a document hash: the value documentHash(document) returns.");
|
|
4064
|
+
const actual = documentHash(document);
|
|
4065
|
+
if (actual !== expected) throw new OPFPatchHashError(expected, actual);
|
|
4066
|
+
}
|
|
4067
|
+
function applyPatchWithInverse(document, patch2, options2 = {}) {
|
|
4068
|
+
if (options2.expectHash !== void 0) assertExpectedHash(document, options2.expectHash);
|
|
4069
|
+
const { document: working, operations, inverse } = walkPatch(document, patch2);
|
|
3771
4070
|
const result = { presentation: working, inverse, patch: operations };
|
|
3772
4071
|
if (options2.validate) {
|
|
3773
4072
|
const validator = typeof options2.validate === "function" ? options2.validate : (value) => validate(value, { only: options2.strict ? ["format", "references"] : ["format"] });
|
|
@@ -3783,6 +4082,50 @@ function applyPatch(document, patch2, options2 = {}) {
|
|
|
3783
4082
|
function invertPatch(document, patch2) {
|
|
3784
4083
|
return applyPatchWithInverse(document, patch2).inverse;
|
|
3785
4084
|
}
|
|
4085
|
+
function resolveIdPatch(document, patch2) {
|
|
4086
|
+
const resolved = [];
|
|
4087
|
+
walkPatch(document, patch2, { after: (step) => {
|
|
4088
|
+
resolved.push(step.resolved);
|
|
4089
|
+
} });
|
|
4090
|
+
return resolved;
|
|
4091
|
+
}
|
|
4092
|
+
function toIdPatch(document, patch2) {
|
|
4093
|
+
const out = [];
|
|
4094
|
+
const pending = /* @__PURE__ */ new Map();
|
|
4095
|
+
walkPatch(document, patch2, {
|
|
4096
|
+
before: (index, operation, working) => {
|
|
4097
|
+
const named = (pointer4) => toIdPointer(working, pointer4);
|
|
4098
|
+
switch (operation.op) {
|
|
4099
|
+
case "replace":
|
|
4100
|
+
case "remove":
|
|
4101
|
+
case "test":
|
|
4102
|
+
pending.set(index, { ...operation, path: named(operation.path) });
|
|
4103
|
+
break;
|
|
4104
|
+
case "copy":
|
|
4105
|
+
pending.set(index, { ...operation, from: named(operation.from), path: toIdPointer(working, operation.path, { keepLast: true }) });
|
|
4106
|
+
break;
|
|
4107
|
+
case "add":
|
|
4108
|
+
pending.set(index, { ...operation, path: toIdPointer(working, operation.path, { keepLast: true }) });
|
|
4109
|
+
break;
|
|
4110
|
+
case "move":
|
|
4111
|
+
pending.set(index, { ...operation, from: named(operation.from) });
|
|
4112
|
+
break;
|
|
4113
|
+
}
|
|
4114
|
+
},
|
|
4115
|
+
after: (step, working) => {
|
|
4116
|
+
const early = pending.get(step.index);
|
|
4117
|
+
pending.delete(step.index);
|
|
4118
|
+
if (step.operation.op !== "move") {
|
|
4119
|
+
out.push(early);
|
|
4120
|
+
return;
|
|
4121
|
+
}
|
|
4122
|
+
const appended = parsePointer(step.operation.path).at(-1) === "-";
|
|
4123
|
+
const destination = toIdPointer(working, step.resolved.path, { keepLast: true });
|
|
4124
|
+
out.push({ ...early, path: appended ? formatPointer([...parsePointer(destination).slice(0, -1), "-"]) : destination });
|
|
4125
|
+
}
|
|
4126
|
+
});
|
|
4127
|
+
return out;
|
|
4128
|
+
}
|
|
3786
4129
|
|
|
3787
4130
|
// src/schema-catalog-kinds.ts
|
|
3788
4131
|
var schemaCatalogKinds = {
|
|
@@ -5473,12 +5816,12 @@ function asNext(text2) {
|
|
|
5473
5816
|
const trimmed = text2.trim();
|
|
5474
5817
|
return /^[A-Z][a-z]/.test(trimmed) ? trimmed.charAt(0).toLowerCase() + trimmed.slice(1) : trimmed;
|
|
5475
5818
|
}
|
|
5476
|
-
var
|
|
5819
|
+
var isRecord3 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
5477
5820
|
function readAt(document, segments) {
|
|
5478
5821
|
let value = document;
|
|
5479
5822
|
for (const segment of segments) {
|
|
5480
5823
|
if (Array.isArray(value)) value = value[Number(segment)];
|
|
5481
|
-
else if (
|
|
5824
|
+
else if (isRecord3(value)) value = value[segment];
|
|
5482
5825
|
else return void 0;
|
|
5483
5826
|
}
|
|
5484
5827
|
return value;
|
|
@@ -5543,11 +5886,11 @@ function dotted(segments) {
|
|
|
5543
5886
|
}
|
|
5544
5887
|
function keysAt(helpers, path) {
|
|
5545
5888
|
const value = helpers.valueAt(path);
|
|
5546
|
-
return
|
|
5889
|
+
return isRecord3(value) ? Object.keys(value) : [];
|
|
5547
5890
|
}
|
|
5548
5891
|
function idsAt(helpers, path) {
|
|
5549
5892
|
const value = helpers.valueAt(path);
|
|
5550
|
-
return Array.isArray(value) ? value.flatMap((entry2) =>
|
|
5893
|
+
return Array.isArray(value) ? value.flatMap((entry2) => isRecord3(entry2) && typeof entry2.id === "string" ? [entry2.id] : []) : [];
|
|
5551
5894
|
}
|
|
5552
5895
|
function codeList(names2, max = 5, joiner = "and") {
|
|
5553
5896
|
const shown = names2.slice(0, max).map(code);
|
|
@@ -5588,7 +5931,7 @@ function freshName(base, taken = []) {
|
|
|
5588
5931
|
}
|
|
5589
5932
|
var BLOCK_KINDS = ["chart", "image", "video", "table", "code", "metric", "quote", "timeline", "items", "bullets", "text"];
|
|
5590
5933
|
function blockKind(node) {
|
|
5591
|
-
if (!
|
|
5934
|
+
if (!isRecord3(node)) return void 0;
|
|
5592
5935
|
if (typeof node.type === "string" && node.type !== "group") return node.type;
|
|
5593
5936
|
const found = BLOCK_KINDS.find((key2) => node[key2] !== void 0);
|
|
5594
5937
|
if (found === "items" || found === "bullets") return "list";
|
|
@@ -5797,13 +6140,13 @@ function regionNamesOf(slideLayout, helpers) {
|
|
|
5797
6140
|
const colon = slideLayout.indexOf(":");
|
|
5798
6141
|
const group = colon > 0 ? slideLayout.slice(0, colon) : void 0;
|
|
5799
6142
|
const id = colon > 0 ? slideLayout.slice(colon + 1) : slideLayout;
|
|
5800
|
-
const record = (group ? [group] : ["custom", "default"]).map((name) => helpers.valueAt(["catalogs", name, "layouts", id])).find(
|
|
6143
|
+
const record = (group ? [group] : ["custom", "default"]).map((name) => helpers.valueAt(["catalogs", name, "layouts", id])).find(isRecord3);
|
|
5801
6144
|
if (!record) return void 0;
|
|
5802
6145
|
const names2 = [];
|
|
5803
6146
|
const walk2 = (list) => {
|
|
5804
6147
|
if (!Array.isArray(list)) return;
|
|
5805
6148
|
for (const entry2 of list) {
|
|
5806
|
-
if (!
|
|
6149
|
+
if (!isRecord3(entry2)) continue;
|
|
5807
6150
|
if (typeof entry2.name === "string" && !["title", "subtitle", "tag"].includes(entry2.name)) names2.push(entry2.name);
|
|
5808
6151
|
walk2(entry2.regions);
|
|
5809
6152
|
}
|
|
@@ -5917,7 +6260,7 @@ var codeHighlightRangeReversed = (finding2) => {
|
|
|
5917
6260
|
};
|
|
5918
6261
|
};
|
|
5919
6262
|
var variableBuiltinMissing = (finding2, _context, helpers) => {
|
|
5920
|
-
const idParam =
|
|
6263
|
+
const idParam = isRecord3(finding2.validation?.params) ? finding2.validation.params.id : void 0;
|
|
5921
6264
|
const id = (typeof idParam === "string" ? idParam : void 0) ?? match(finding2.message, /^Built-in '(.+?)' has no value/)?.[1] ?? match(finding2.message, /'\{\{(.+?)\}\}'/)?.[1];
|
|
5922
6265
|
if (!id) return void 0;
|
|
5923
6266
|
const root = id.split(".")[0];
|
|
@@ -5939,7 +6282,7 @@ var durationOutsideNarrative2 = (finding2) => {
|
|
|
5939
6282
|
};
|
|
5940
6283
|
var narrativeDurationRange = (_finding, _context, helpers) => {
|
|
5941
6284
|
const range = helpers.valueAt(helpers.segments);
|
|
5942
|
-
if (
|
|
6285
|
+
if (isRecord3(range) && typeof range.min === "number" && typeof range.max === "number") {
|
|
5943
6286
|
return {
|
|
5944
6287
|
message: `The duration range has min ${range.min} greater than max ${range.max}.`,
|
|
5945
6288
|
next: `swap them: ${code(`min: ${range.max}`)} and ${code(`max: ${range.min}`)}.`
|
|
@@ -6032,7 +6375,7 @@ var AUDIT_TEXT = {
|
|
|
6032
6375
|
};
|
|
6033
6376
|
|
|
6034
6377
|
// src/finding-text-format.ts
|
|
6035
|
-
var params = (finding2) =>
|
|
6378
|
+
var params = (finding2) => isRecord3(finding2.validation?.params) ? finding2.validation.params : {};
|
|
6036
6379
|
var text = (value) => typeof value === "string" ? value : void 0;
|
|
6037
6380
|
var jsonSyntax = (finding2) => ({
|
|
6038
6381
|
message: keep(finding2.message),
|
|
@@ -6153,7 +6496,7 @@ var dataColumnDuplicate = (finding2, _context, helpers) => {
|
|
|
6153
6496
|
const name = unquote(match(finding2.message, /^column name ("(?:[^"\\]|\\.)*") is used by an earlier column/)?.[1]);
|
|
6154
6497
|
if (!name) return void 0;
|
|
6155
6498
|
const columns = helpers.valueAt(helpers.segments.slice(0, -1));
|
|
6156
|
-
const taken = Array.isArray(columns) ? columns.map((entry2) =>
|
|
6499
|
+
const taken = Array.isArray(columns) ? columns.map((entry2) => isRecord3(entry2) ? String(entry2.name) : String(entry2)) : [];
|
|
6157
6500
|
return {
|
|
6158
6501
|
message: `Two columns are named ${code(name)}. Series and mappings address columns by name.`,
|
|
6159
6502
|
next: `rename the second one (for example ${code(freshName(name, taken))}).`
|
|
@@ -6431,7 +6774,7 @@ var unresolvedReference2 = (finding2, _context, helpers) => {
|
|
|
6431
6774
|
const group = colon > 0 ? reference.slice(0, colon) : void 0;
|
|
6432
6775
|
const bare = colon > 0 ? reference.slice(colon + 1) : reference;
|
|
6433
6776
|
const embeddedIn = group ? [group] : ["custom", "default"];
|
|
6434
|
-
const embedded = kind && embeddedIn.some((name) =>
|
|
6777
|
+
const embedded = kind && embeddedIn.some((name) => isRecord3(helpers.valueAt(["catalogs", name, kind, bare])));
|
|
6435
6778
|
const suggestions = (finding2.suggestions ?? []).slice(0, 5).map((entry2) => String(entry2.value));
|
|
6436
6779
|
if (embedded) {
|
|
6437
6780
|
return {
|
|
@@ -6796,6 +7139,8 @@ function describeSchema(finding2, context, helpers) {
|
|
|
6796
7139
|
case "required": {
|
|
6797
7140
|
const property = String(params2.missingProperty ?? "");
|
|
6798
7141
|
const where = containerName(segments);
|
|
7142
|
+
const shape = property === "data" ? chartShapeHelp(actual) : void 0;
|
|
7143
|
+
if (shape) return { message: shape.message, next: shape.next };
|
|
6799
7144
|
const schema = context.schemaAt ? context.schemaAt([...segments, property]) : attempt(() => schemaAtPath(context.document, [...segments, property]), void 0);
|
|
6800
7145
|
if (format === "json") {
|
|
6801
7146
|
const sample2 = property === "slides" ? '[ { "title": "\u2026" } ]' : starterText(schema, property, "json");
|
|
@@ -6936,7 +7281,7 @@ function schemaFixes(finding2, document) {
|
|
|
6936
7281
|
switch (validation.keyword) {
|
|
6937
7282
|
case "required": {
|
|
6938
7283
|
const property = String(params2.missingProperty ?? "");
|
|
6939
|
-
if (!property || !
|
|
7284
|
+
if (!property || !isRecord3(readAt(document, segments)) || Object.hasOwn(readAt(document, segments), property)) return [];
|
|
6940
7285
|
const value = starterValue(document, segments, property);
|
|
6941
7286
|
if (value === void 0) return [];
|
|
6942
7287
|
return [patch(`add:${property}`, `Add \`${property}\``, [{ op: "add", path: pointerOf([...segments, property]), value }])];
|
|
@@ -6952,7 +7297,7 @@ function schemaFixes(finding2, document) {
|
|
|
6952
7297
|
const name = String(params2.additionalProperty ?? segments.at(-1) ?? "");
|
|
6953
7298
|
const parent = segments.slice(0, -1);
|
|
6954
7299
|
const owner = readAt(document, parent);
|
|
6955
|
-
if (!name || !
|
|
7300
|
+
if (!name || !isRecord3(owner) || !Object.hasOwn(owner, name)) return [];
|
|
6956
7301
|
const fixes = [];
|
|
6957
7302
|
for (const suggestion of finding2.suggestions ?? []) {
|
|
6958
7303
|
const target = String(suggestion.value);
|
|
@@ -6961,14 +7306,14 @@ function schemaFixes(finding2, document) {
|
|
|
6961
7306
|
if (allowsKey(document, parent, "extensions") && name !== "extensions") {
|
|
6962
7307
|
const existing = owner.extensions;
|
|
6963
7308
|
if (existing === void 0) fixes.push(patch("move-to-extensions", "Move into extensions", [{ op: "add", path: pointerOf([...parent, "extensions"]), value: {} }, { op: "move", from: finding2.path, path: pointerOf([...parent, "extensions", name]) }]));
|
|
6964
|
-
else if (
|
|
7309
|
+
else if (isRecord3(existing) && !Object.hasOwn(existing, name)) fixes.push(patch("move-to-extensions", "Move into extensions", [{ op: "move", from: finding2.path, path: pointerOf([...parent, "extensions", name]) }]));
|
|
6965
7310
|
}
|
|
6966
7311
|
return fixes;
|
|
6967
7312
|
}
|
|
6968
7313
|
case "type": {
|
|
6969
7314
|
const current = readAt(document, segments);
|
|
6970
7315
|
if (current === void 0) return [];
|
|
6971
|
-
if (params2.type === "array" && (typeof current === "string" ||
|
|
7316
|
+
if (params2.type === "array" && (typeof current === "string" || isRecord3(current))) return [patch("wrap-in-list", "Wrap in a list", [{ op: "replace", path: finding2.path, value: [current] }], typeof current === "string")];
|
|
6972
7317
|
if (params2.type === "string" && (typeof current === "number" || typeof current === "boolean")) return [patch("convert-to-string", "Convert to string", [{ op: "replace", path: finding2.path, value: String(current) }], true)];
|
|
6973
7318
|
return [];
|
|
6974
7319
|
}
|
|
@@ -6987,6 +7332,30 @@ function schemaFixes(finding2, document) {
|
|
|
6987
7332
|
}
|
|
6988
7333
|
}
|
|
6989
7334
|
|
|
7335
|
+
// src/drawn-font-families.ts
|
|
7336
|
+
function resolveDrawnFontFamilies(families, measurement, keepsName) {
|
|
7337
|
+
const resolve2 = measurement?.resolveStyle;
|
|
7338
|
+
if (typeof resolve2 !== "function") return families;
|
|
7339
|
+
const drawn = { ...families };
|
|
7340
|
+
for (const role of ["heading", "body", "code", "accent"]) {
|
|
7341
|
+
const named = families[role];
|
|
7342
|
+
if (typeof named !== "string" || !named) continue;
|
|
7343
|
+
try {
|
|
7344
|
+
const resolved = resolve2.call(measurement, { fontFamily: named, fontWeight: role === "heading" ? 700 : 400 });
|
|
7345
|
+
let keep3;
|
|
7346
|
+
if (keepsName) keep3 = keepsName(named, resolved.fontFamily);
|
|
7347
|
+
else {
|
|
7348
|
+
const regular = role === "heading" ? resolve2.call(measurement, { fontFamily: named, fontWeight: 400 }) : resolved;
|
|
7349
|
+
const encoded = resolved.symbolEncoding != null;
|
|
7350
|
+
keep3 = encoded || regular.fontWeight !== void 0 && regular.fontWeight !== 400 && resolved.fontFamily.toLowerCase() !== named.toLowerCase();
|
|
7351
|
+
}
|
|
7352
|
+
if (!keep3) drawn[role] = resolved.fontFamily;
|
|
7353
|
+
} catch {
|
|
7354
|
+
}
|
|
7355
|
+
}
|
|
7356
|
+
return drawn;
|
|
7357
|
+
}
|
|
7358
|
+
|
|
6990
7359
|
// src/script-measurement.ts
|
|
6991
7360
|
function scriptProfile(presentation, slideIndex, options2, language) {
|
|
6992
7361
|
let resolved;
|
|
@@ -7139,7 +7508,12 @@ function buildSlides(document, options2) {
|
|
|
7139
7508
|
const layout = lazy(() => resolved().options.layout);
|
|
7140
7509
|
const composed = lazy(() => {
|
|
7141
7510
|
const result = { layoutDiagnostics: [] };
|
|
7142
|
-
|
|
7511
|
+
let fontFamilies;
|
|
7512
|
+
const compose = (input, withLayout) => {
|
|
7513
|
+
const options3 = resolved().options;
|
|
7514
|
+
fontFamilies ??= options3.fontFamilies && resolveDrawnFontFamilies(options3.fontFamilies, options3.textMeasurement);
|
|
7515
|
+
return composeSlide(input, { ...options3, ...fontFamilies ? { fontFamilies } : {}, layout: withLayout });
|
|
7516
|
+
};
|
|
7143
7517
|
try {
|
|
7144
7518
|
result.composition = compose(resolved().slide, layout());
|
|
7145
7519
|
result.layoutDiagnostics.push(...result.composition.diagnostics.map((diagnostic) => ({ diagnostic, strict: false })));
|
|
@@ -7457,4 +7831,4 @@ function assertValidCatalogRecord(kind, value) {
|
|
|
7457
7831
|
if (!report2.valid) throw new OPFValidationError(report2);
|
|
7458
7832
|
}
|
|
7459
7833
|
|
|
7460
|
-
export { BLOCK_AS_VALUES, BLOCK_OPTION_KEYS, CATALOG_SCHEMA, COMMON_KEYS, DEFAULT_VALIDATION_THRESHOLDS, FENCE_ATTRIBUTES, FENCE_KINDS, LINE_KEYWORDS, METRIC_KEYS, OPFPatchError, OPFPatchValidationError, OPFValidationError, PATTERN_PHRASES, SLIDE_OPTION_KEYS, SOURCE_EXPLAIN, SPAN_FLAGS, SPAN_VALUES, UNRANKED_PRIORITY, activeSchema, analyzeJsonSyntax, applyPatch, applyPatchWithInverse, applyTextEdits, assertValid, assertValidCatalogRecord, catalogDisplayKinds, catalogKindAt, catalogSchemaNames, createLocator, createSchemaValue, describeField, describeFinding, distance2 as distance, escapePointerToken, findValidationRule, formatPointer, getAtPointer, hasPointer, invertPatch, isPromotedRegionKey, jsonEqual, listSchemaFields, nearest, normalizePatch, parsePointer, parseSource, pointerFromPath, readPointer, rememberByText, resolveSchema, resolveSlideContext, resolveSlideScriptMeasurement, ruleDocumentation, schemaAtPath, schemaCatalogKinds, schemaLabel, schemaType, schemaVariants, segmentsOf, splitOpfPath, splitPointer2 as splitPointer, starterValue, unescapePointerToken, us, validate, validateCatalogRecord, validationCategories, validationRules };
|
|
7834
|
+
export { BLOCK_AS_VALUES, BLOCK_OPTION_KEYS, CATALOG_SCHEMA, COMMON_KEYS, DEFAULT_VALIDATION_THRESHOLDS, FENCE_ATTRIBUTES, FENCE_KINDS, LINE_KEYWORDS, METRIC_KEYS, OPFPatchError, OPFPatchHashError, OPFPatchValidationError, OPFValidationError, PATTERN_PHRASES, SLIDE_OPTION_KEYS, SOURCE_EXPLAIN, SPAN_FLAGS, SPAN_VALUES, UNRANKED_PRIORITY, activeSchema, analyzeJsonSyntax, applyPatch, applyPatchWithInverse, applyTextEdits, assertValid, assertValidCatalogRecord, catalogDisplayKinds, catalogKindAt, catalogSchemaNames, createLocator, createSchemaValue, describeField, describeFinding, distance2 as distance, documentHash, escapePointerToken, findValidationRule, formatPointer, getAtPointer, hasPointer, idToken, invertPatch, isIdToken, isPromotedRegionKey, jsonEqual, listSchemaFields, nearest, normalizePatch, parsePointer, parseSource, pointerFromPath, readPointer, rememberByText, resolveDrawnFontFamilies, resolveIdPatch, resolveIdPointer, resolveSchema, resolveSlideContext, resolveSlideScriptMeasurement, ruleDocumentation, schemaAtPath, schemaCatalogKinds, schemaLabel, schemaType, schemaVariants, segmentsOf, splitOpfPath, splitPointer2 as splitPointer, starterValue, toIdPatch, toIdPointer, unescapePointerToken, us, validate, validateCatalogRecord, validationCategories, validationRules, walkPatch };
|