@openpresentation/opf 0.16.0 → 0.17.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 +16 -2
- package/dist/{catalog-refs-_anZs-Qz.d.ts → catalog-refs-C4K4y-vh.d.ts} +1 -1
- package/dist/{catalog-schemas-BZCjgAxu.d.ts → catalog-schemas-g7RFQBdc.d.ts} +1 -1
- package/dist/catalog.d.ts +2 -2
- package/dist/catalog.js +3 -23712
- package/dist/{chart-data-BnNqgnC-.d.ts → chart-data-DTxdRRT1.d.ts} +1 -1
- package/dist/{chunk-FQSIIADJ.js → chunk-BIC3SWPK.js} +4 -4
- package/dist/{chunk-5PDN7BN6.js → chunk-CW7GEAV3.js} +151 -49
- package/dist/{chunk-NAWQR7MN.js → chunk-ESRYBYLY.js} +1 -1
- package/dist/chunk-IPW5BS3X.js +973 -0
- package/dist/{chunk-5UEUAW57.js → chunk-IS5H5JKH.js} +1 -1
- package/dist/{chunk-UM24JFUE.js → chunk-M4UR3NPN.js} +2 -2
- package/dist/{chunk-KINQFU6X.js → chunk-N4EVOFEA.js} +19 -12
- package/dist/{chunk-PX5AWL7Y.js → chunk-NLNYNBTS.js} +79 -10
- package/dist/{chunk-SMLMI6IZ.js → chunk-O263APNI.js} +1 -1
- package/dist/{chunk-BSYQDWT4.js → chunk-O2CX5NEH.js} +26 -14
- package/dist/{chunk-3XDRQYWZ.js → chunk-O3CVNJTL.js} +1 -1
- package/dist/{chunk-5TO6I3GB.js → chunk-PPROJP2E.js} +1 -1
- package/dist/{chunk-WEDGVC5W.js → chunk-RA64UQKI.js} +18 -42
- package/dist/{chunk-K4DQQIT4.js → chunk-TCD2FB2K.js} +5 -5
- package/dist/chunk-WCG3THTD.js +23712 -0
- package/dist/chunk-WWYWFVOI.js +793 -0
- package/dist/{chunk-6OR326EA.js → chunk-YT7FMQER.js} +1 -1
- package/dist/{composition-D4ADF5c-.d.ts → composition-BbZ_9C-c.d.ts} +152 -132
- package/dist/composition.d.ts +3 -3
- package/dist/composition.js +1 -1
- package/dist/conversion-SBpTOwdg.d.ts +444 -0
- package/dist/convert.d.ts +4 -4
- package/dist/convert.js +7 -7
- package/dist/data.d.ts +2 -2
- package/dist/data.js +2 -2
- package/dist/deck-report-Bx3naFlF.d.ts +40 -0
- package/dist/deck.d.ts +23 -53
- package/dist/deck.js +10 -10
- package/dist/diff.d.ts +1 -1
- package/dist/diff.js +5 -5
- package/dist/docs.js +29 -23
- package/dist/examples.d.ts +1 -1
- package/dist/examples.js +237 -237
- package/dist/{finding-CT_f_vbD.d.ts → finding-CDQ_wH8j.d.ts} +1 -1
- package/dist/format.js +2 -2
- package/dist/index.d.ts +42 -12
- package/dist/index.js +15 -807
- package/dist/markdown.d.ts +6 -6
- package/dist/markdown.js +7 -7
- package/dist/node-engine.d.ts +94 -0
- package/dist/node-engine.js +21 -0
- package/dist/node.d.ts +60 -0
- package/dist/node.js +54 -0
- package/dist/{pagination-DzZPFheM.d.ts → pagination-BhX4M48Y.d.ts} +21 -7
- package/dist/pagination.d.ts +4 -4
- package/dist/pagination.js +4 -4
- package/dist/patch.d.ts +1 -1
- package/dist/patch.js +4 -4
- package/dist/{presentation-COrFuj2g.d.ts → presentation-fb8CZmRq.d.ts} +12 -75
- package/dist/repo-readme.js +1 -1
- package/dist/schemas.js +1 -1
- package/dist/spec/catalogs/manifest.json +1 -1
- package/dist/spec/schemas/opf.schema.json +16 -37
- package/dist/types.d.ts +3 -3
- package/dist/{validation-types-HxIgJfKx.d.ts → validation-types-iZbXfES6.d.ts} +19 -8
- package/dist/validator.d.ts +8 -8
- package/dist/validator.js +3 -3
- package/dist/yaml.d.ts +6 -6
- package/dist/yaml.js +7 -7
- package/package.json +34 -1
package/dist/index.js
CHANGED
|
@@ -1,811 +1,19 @@
|
|
|
1
|
+
export { OPFMoveToCustomError, copySlides, embed, moveToCustom, sameRecord, stats, updateFromCatalog } from './chunk-WWYWFVOI.js';
|
|
1
2
|
export { specFileEntries, specFileKinds, specFilePaths } from './chunk-HXHOZ7AH.js';
|
|
2
|
-
export { OPFDataImportError, importData, parseTabularData } from './chunk-
|
|
3
|
-
export { DECK_FORMATS, deckFormatOf,
|
|
4
|
-
export { fromMarkdown, toMarkdown } from './chunk-
|
|
5
|
-
import './chunk-
|
|
6
|
-
export { OPFMarkdownError } from './chunk-
|
|
7
|
-
export { diff, merge } from './chunk-
|
|
8
|
-
export { OPFPatchError, OPFPatchValidationError, applyPatch } from './chunk-
|
|
9
|
-
export { OPFFormatError, format } from './chunk-
|
|
10
|
-
export { OPFPaginationError, paginate, paginateSlide } from './chunk-
|
|
11
|
-
import './chunk-
|
|
12
|
-
import './chunk-
|
|
13
|
-
export { DEFAULT_CHART_PALETTE, DEFAULT_VALIDATION_THRESHOLDS, OPFValidationError, assertValid, assertValidCatalogRecord, findValidationRule, resolveSlideContext, validate, validateCatalogRecord, validationCategories, validationRules } from './chunk-
|
|
14
|
-
|
|
15
|
-
export { CHART_TYPES, DEFAULT_VARIABLE_DATE_FORMAT, ENGINE_DEFAULT_CHART_TYPES, ENGINE_DEFAULT_COLOR_SCHEME, ENGINE_DEFAULT_FONT_SCHEME, ENGINE_DEFAULT_THEME, LANGUAGES, OPFVariableError, SOCIAL_PLATFORMS, VARIABLE_KINDS, chartNumber, coerceVariableValue, datasetDiagnostics, formatDataNumber, formatVariableNumber, fromExcelNumberFormat, hasContentVariables, inlineChartData, inlineDatasets, inlineTableData, isDatasetRef, isTemplate, isXYChartType, listBuiltinVariables, listVariables, normalizeLanguageFamily, numberFormatError, resolveChartData, resolveDesignRecords, resolveFontScheme, resolveTableData, resolveVariables, suggestChartNumberFix, tableCellDisplayValue, toExcelNumberFormat, unusedDatasets, variableDeclarations } from './chunk-5PDN7BN6.js';
|
|
3
|
+
export { OPFDataImportError, importData, parseTabularData } from './chunk-O263APNI.js';
|
|
4
|
+
export { DECK_FORMATS, deckFormatOf, parse, stringify } from './chunk-N4EVOFEA.js';
|
|
5
|
+
export { fromMarkdown, toMarkdown } from './chunk-BIC3SWPK.js';
|
|
6
|
+
import './chunk-TCD2FB2K.js';
|
|
7
|
+
export { OPFMarkdownError } from './chunk-IS5H5JKH.js';
|
|
8
|
+
export { diff, merge } from './chunk-M4UR3NPN.js';
|
|
9
|
+
export { OPFPatchError, OPFPatchValidationError, applyPatch } from './chunk-O3CVNJTL.js';
|
|
10
|
+
export { OPFFormatError, format } from './chunk-YT7FMQER.js';
|
|
11
|
+
export { OPFPaginationError, paginate, paginateSlide } from './chunk-O2CX5NEH.js';
|
|
12
|
+
import './chunk-ESRYBYLY.js';
|
|
13
|
+
import './chunk-PPROJP2E.js';
|
|
14
|
+
export { DEFAULT_CHART_PALETTE, DEFAULT_VALIDATION_THRESHOLDS, OPFValidationError, assertValid, assertValidCatalogRecord, findValidationRule, resolveSlideContext, validate, validateCatalogRecord, validationCategories, validationRules } from './chunk-NLNYNBTS.js';
|
|
15
|
+
export { CHART_TYPES, DEFAULT_VARIABLE_DATE_FORMAT, ENGINE_DEFAULT_CHART_TYPES, ENGINE_DEFAULT_COLOR_SCHEME, ENGINE_DEFAULT_FONT_SCHEME, ENGINE_DEFAULT_THEME, LANGUAGES, OPFVariableError, SLIDE_SCOPED_BUILTINS, SOCIAL_PLATFORMS, VARIABLE_KINDS, chartNumber, coerceVariableValue, datasetDiagnostics, formatDataNumber, formatVariableNumber, fromExcelNumberFormat, hasContentVariables, inlineChartData, inlineDatasets, inlineTableData, isDatasetRef, isTemplate, isXYChartType, listBuiltinVariables, listVariables, normalizeLanguageFamily, numberFormatError, resolveChartData, resolveDesignRecords, resolveFontScheme, resolveSlideVariables, resolveTableData, resolveVariables, suggestChartNumberFix, tableCellDisplayValue, toExcelNumberFormat, unusedDatasets, variableDeclarations } from './chunk-CW7GEAV3.js';
|
|
16
16
|
export { catalogDisplayKinds, catalogSchemaNames } from './chunk-TRDXRRQK.js';
|
|
17
|
-
import { embeddedCopy, checkCatalogsOption, catalogReferenceSites, parseReference, catalogGroupDeclared, resolveReference, dottedPath, unresolvedReference, recordReferenceSites, catalogGroupSource, registeredCatalog, catalogKinds, CATALOG_GROUP_PATTERN } from './chunk-SPFV27O5.js';
|
|
18
17
|
export { CATALOG_GROUP_PATTERN, CATALOG_REFERENCE_PATTERN, OPFCatalogsOptionError, OPFUnresolvedReferenceError, catalogGroupSource, catalogKinds, catalogRecords, catalogReferenceSites, parseReference, resolveReference, unresolvedReference } from './chunk-SPFV27O5.js';
|
|
19
|
-
export { audience, chartType, colorScheme, fontScheme, language, layout, narrative, presentation, purpose, schemaEntries, schemaNames, schemas, socialPlatform, theme, tone } from './chunk-
|
|
18
|
+
export { audience, chartType, colorScheme, fontScheme, language, layout, narrative, presentation, purpose, schemaEntries, schemaNames, schemas, socialPlatform, theme, tone } from './chunk-RA64UQKI.js';
|
|
20
19
|
export { FONT_POLICY, applyFontPolicyDecisions, fontAvailabilityDiagnostics, fontPolicyFor } from './chunk-WXSPETQ6.js';
|
|
21
|
-
|
|
22
|
-
// src/catalog-helpers.ts
|
|
23
|
-
var isRec = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24
|
-
var rec = (value) => isRec(value) ? value : {};
|
|
25
|
-
function canonical(value) {
|
|
26
|
-
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
27
|
-
if (isRec(value))
|
|
28
|
-
return `{${Object.keys(value).filter((key) => value[key] !== void 0).sort().map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`).join(",")}}`;
|
|
29
|
-
return JSON.stringify(value);
|
|
30
|
-
}
|
|
31
|
-
function sameRecord(a, b) {
|
|
32
|
-
return canonical(embeddedCopy(a)) === canonical(embeddedCopy(b));
|
|
33
|
-
}
|
|
34
|
-
function setAt(root, path, value) {
|
|
35
|
-
let node = root;
|
|
36
|
-
for (const part of path.slice(0, -1)) node = node[part];
|
|
37
|
-
node[path[path.length - 1]] = value;
|
|
38
|
-
}
|
|
39
|
-
var kindsOf = (group, kind) => {
|
|
40
|
-
if (!isRec(group[kind])) group[kind] = {};
|
|
41
|
-
return group[kind];
|
|
42
|
-
};
|
|
43
|
-
function embed(document, options = {}) {
|
|
44
|
-
const catalogs = { catalogs: checkCatalogsOption(options.catalogs, "embed") };
|
|
45
|
-
const out = structuredClone(rec(document));
|
|
46
|
-
const added = [];
|
|
47
|
-
const unresolved = [];
|
|
48
|
-
const queue = catalogReferenceSites(out);
|
|
49
|
-
const reported = /* @__PURE__ */ new Set();
|
|
50
|
-
while (queue.length) {
|
|
51
|
-
const site = queue.shift();
|
|
52
|
-
const parsed = parseReference(site.reference);
|
|
53
|
-
if (parsed?.group !== void 0 && !catalogGroupDeclared(out, parsed.group)) continue;
|
|
54
|
-
const found = resolveReference(out, site.kind, site.reference, { ...catalogs, ...site.group !== void 0 ? { group: site.group } : {} });
|
|
55
|
-
if (!found) {
|
|
56
|
-
const path = dottedPath(site.path);
|
|
57
|
-
if (!reported.has(path)) {
|
|
58
|
-
reported.add(path);
|
|
59
|
-
unresolved.push(unresolvedReference(out, site.kind, site.reference, path, catalogs));
|
|
60
|
-
}
|
|
61
|
-
continue;
|
|
62
|
-
}
|
|
63
|
-
if (found.origin === "document") continue;
|
|
64
|
-
if (!isRec(out.catalogs)) out.catalogs = {};
|
|
65
|
-
const groups = out.catalogs;
|
|
66
|
-
if (!isRec(groups[found.group])) groups[found.group] = {};
|
|
67
|
-
const group = groups[found.group];
|
|
68
|
-
if (found.group !== "custom" && typeof group.source !== "string" && found.source !== void 0) {
|
|
69
|
-
const rest = { ...group };
|
|
70
|
-
for (const key of Object.keys(group)) delete group[key];
|
|
71
|
-
Object.assign(group, { source: found.source }, rest);
|
|
72
|
-
}
|
|
73
|
-
const copy = embeddedCopy(found.record);
|
|
74
|
-
kindsOf(group, site.kind)[found.id] = copy;
|
|
75
|
-
added.push({ group: found.group, kind: site.kind, id: found.id, ...found.source !== void 0 ? { source: found.source } : {} });
|
|
76
|
-
queue.push(...recordReferenceSites(site.kind, copy, ["catalogs", found.group, site.kind, found.id], found.group));
|
|
77
|
-
}
|
|
78
|
-
return { document: out, added, unresolved };
|
|
79
|
-
}
|
|
80
|
-
function groupNameFor(source) {
|
|
81
|
-
const base = source.startsWith("pkg:") ? source.slice(4).replace(/^@/, "").split("/").slice(0, 2).join("-") : (() => {
|
|
82
|
-
try {
|
|
83
|
-
return new URL(source).hostname.replace(/^www\./, "");
|
|
84
|
-
} catch {
|
|
85
|
-
return source;
|
|
86
|
-
}
|
|
87
|
-
})();
|
|
88
|
-
const name = base.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
89
|
-
return /^[a-z]/.test(name) ? name : `catalog-${name || "source"}`;
|
|
90
|
-
}
|
|
91
|
-
function copySlides(from, to, indexes, options = {}) {
|
|
92
|
-
const catalogs = { catalogs: checkCatalogsOption(options.catalogs, "copySlides") };
|
|
93
|
-
const source = rec(from);
|
|
94
|
-
const target = structuredClone(rec(to));
|
|
95
|
-
const sourceSlides = Array.isArray(source.slides) ? source.slides : [];
|
|
96
|
-
const targetSlides = Array.isArray(target.slides) ? target.slides : [];
|
|
97
|
-
for (const index of indexes)
|
|
98
|
-
if (!Number.isInteger(index) || index < 0 || index >= sourceSlides.length) throw new RangeError(`Slide index ${String(index)} is outside the source presentation's ${sourceSlides.length} slides.`);
|
|
99
|
-
const at = options.at ?? targetSlides.length;
|
|
100
|
-
if (!Number.isInteger(at) || at < 0 || at > targetSlides.length) throw new RangeError(`Insertion index ${String(at)} is outside the target presentation's ${targetSlides.length + 1} positions.`);
|
|
101
|
-
const renamed = [];
|
|
102
|
-
const addedGroups = [];
|
|
103
|
-
const added = [];
|
|
104
|
-
const unresolved = [];
|
|
105
|
-
const hadCatalogs = isRec(target.catalogs);
|
|
106
|
-
const groups = () => {
|
|
107
|
-
if (!isRec(target.catalogs)) target.catalogs = {};
|
|
108
|
-
return target.catalogs;
|
|
109
|
-
};
|
|
110
|
-
const memo = /* @__PURE__ */ new Map();
|
|
111
|
-
const targetGroupFor = (catalogSource, sourceGroupName) => {
|
|
112
|
-
for (const [name2, value] of Object.entries(rec(target.catalogs))) if (name2 !== "custom" && isRec(value) && value.source === catalogSource) return name2;
|
|
113
|
-
if (rec(target.catalogs).default !== false && catalogGroupSource(target, "default", catalogs) === catalogSource) return "default";
|
|
114
|
-
let name = sourceGroupName === "default" || sourceGroupName === "custom" ? groupNameFor(catalogSource) : sourceGroupName;
|
|
115
|
-
for (let n = 2; catalogGroupDeclared(target, name) || name === "default" || name === "custom"; n++) name = `${sourceGroupName === "default" ? groupNameFor(catalogSource) : sourceGroupName}-${n}`;
|
|
116
|
-
groups()[name] = { source: catalogSource };
|
|
117
|
-
addedGroups.push({ name, source: catalogSource });
|
|
118
|
-
return name;
|
|
119
|
-
};
|
|
120
|
-
const bareTaken = (kind, id) => resolveReference(target, kind, id, catalogs) !== void 0;
|
|
121
|
-
const addCustom = (kind, wanted, record, renamed2 = false) => {
|
|
122
|
-
const custom = rec(rec(target.catalogs).custom);
|
|
123
|
-
const existing = rec(custom[kind]);
|
|
124
|
-
for (const [id2, value] of Object.entries(existing)) if ((!renamed2 && id2 === wanted || /^-\d+$/.test(id2.slice(wanted.length))) && id2.startsWith(wanted) && sameRecord(value, record)) return { id: id2, reused: true };
|
|
125
|
-
let n = renamed2 ? 2 : 1;
|
|
126
|
-
let id = renamed2 ? `${wanted}-2` : wanted;
|
|
127
|
-
while (Object.hasOwn(existing, id) || bareTaken(kind, id)) id = `${wanted}-${++n}`;
|
|
128
|
-
if (!isRec(groups().custom)) groups().custom = {};
|
|
129
|
-
kindsOf(groups().custom, kind)[id] = record;
|
|
130
|
-
added.push({ group: "custom", kind, id });
|
|
131
|
-
return { id, reused: false };
|
|
132
|
-
};
|
|
133
|
-
const referenceTo = (kind, group, id, holder) => {
|
|
134
|
-
const found = resolveReference(target, kind, id, { ...catalogs, ...holder !== void 0 ? { group: holder } : {} });
|
|
135
|
-
return found && found.group === group && found.id === id ? id : `${group}:${id}`;
|
|
136
|
-
};
|
|
137
|
-
const place = (kind, reference2, path, holder) => {
|
|
138
|
-
const found = resolveReference(source, kind, reference2, { ...catalogs, ...holder !== void 0 ? { group: holder } : {} });
|
|
139
|
-
if (!found) {
|
|
140
|
-
unresolved.push(unresolvedReference(source, kind, reference2, path, catalogs));
|
|
141
|
-
return void 0;
|
|
142
|
-
}
|
|
143
|
-
const key = `${kind}\0${found.group}\0${found.source ?? ""}\0${found.id}`;
|
|
144
|
-
const known = memo.get(key);
|
|
145
|
-
if (known) return known;
|
|
146
|
-
const incoming = embeddedCopy(found.record);
|
|
147
|
-
const catalogSource = found.group === "custom" ? void 0 : found.source;
|
|
148
|
-
const group = catalogSource === void 0 ? "custom" : targetGroupFor(catalogSource, found.group);
|
|
149
|
-
const inner = recordReferenceSites(kind, incoming, []).map((site) => ({ site, placed: place(site.kind, site.reference, `${path} -> ${site.path.join(".")}`, found.group) }));
|
|
150
|
-
const rewrite = (holderGroup) => {
|
|
151
|
-
const copy = structuredClone(incoming);
|
|
152
|
-
for (const { site, placed: placed2 } of inner) if (placed2) setAt(copy, site.path, referenceTo(site.kind, placed2.group, placed2.id, holderGroup));
|
|
153
|
-
return copy;
|
|
154
|
-
};
|
|
155
|
-
let placed;
|
|
156
|
-
if (group === "custom") {
|
|
157
|
-
const result = addCustom(kind, found.id, rewrite("custom"));
|
|
158
|
-
if (result.id !== found.id && !result.reused) renamed.push({ kind, from: reference2, to: result.id, reason: "custom-conflict" });
|
|
159
|
-
placed = { group: "custom", id: result.id };
|
|
160
|
-
} else {
|
|
161
|
-
const record = rewrite(group);
|
|
162
|
-
const embedded = rec(rec(rec(target.catalogs)[group])[kind]);
|
|
163
|
-
const current = Object.hasOwn(embedded, found.id) ? embedded[found.id] : registeredCatalog(catalogGroupSource(target, group, catalogs), catalogs)?.[kind]?.[found.id];
|
|
164
|
-
if (current === void 0 || sameRecord(current, record)) {
|
|
165
|
-
if (!Object.hasOwn(embedded, found.id)) {
|
|
166
|
-
if (!isRec(groups()[group])) groups()[group] = {};
|
|
167
|
-
const holder2 = groups()[group];
|
|
168
|
-
if (typeof holder2.source !== "string" && catalogSource !== void 0) {
|
|
169
|
-
const rest = { ...holder2 };
|
|
170
|
-
for (const key2 of Object.keys(holder2)) delete holder2[key2];
|
|
171
|
-
Object.assign(holder2, { source: catalogSource }, rest);
|
|
172
|
-
}
|
|
173
|
-
kindsOf(holder2, kind)[found.id] = record;
|
|
174
|
-
added.push({ group, kind, id: found.id, ...catalogSource !== void 0 ? { source: catalogSource } : {} });
|
|
175
|
-
}
|
|
176
|
-
placed = { group, id: found.id };
|
|
177
|
-
} else {
|
|
178
|
-
const { id, reused } = addCustom(kind, found.id, rewrite("custom"), true);
|
|
179
|
-
if (!reused) renamed.push({ kind, from: reference2, to: id, reason: "catalog-revision" });
|
|
180
|
-
placed = { group: "custom", id };
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
memo.set(key, placed);
|
|
184
|
-
return placed;
|
|
185
|
-
};
|
|
186
|
-
const copied = [];
|
|
187
|
-
for (const index of indexes) {
|
|
188
|
-
const slide = structuredClone(sourceSlides[index]);
|
|
189
|
-
const holder = { slides: [slide] };
|
|
190
|
-
for (const site of catalogReferenceSites(holder, { records: false })) {
|
|
191
|
-
const placed = place(site.kind, site.reference, `slides.${index}.${site.path.slice(2).join(".")}`);
|
|
192
|
-
if (placed) setAt(holder, site.path, referenceTo(site.kind, placed.group, placed.id));
|
|
193
|
-
}
|
|
194
|
-
copied.push(holder.slides[0]);
|
|
195
|
-
}
|
|
196
|
-
targetSlides.splice(at, 0, ...copied);
|
|
197
|
-
target.slides = targetSlides;
|
|
198
|
-
if (!hadCatalogs && isRec(target.catalogs) && Object.keys(target.catalogs).length === 0) delete target.catalogs;
|
|
199
|
-
return { document: target, slides: copied.map((_, offset) => at + offset), renamed, addedGroups, added, unresolved };
|
|
200
|
-
}
|
|
201
|
-
var pointerPart = (part) => part.replaceAll("~", "~0").replaceAll("/", "~1");
|
|
202
|
-
function updateFromCatalog(document, catalogs, refs) {
|
|
203
|
-
const options = { catalogs: checkCatalogsOption(catalogs, "updateFromCatalog") };
|
|
204
|
-
const groups = rec(rec(document).catalogs);
|
|
205
|
-
const wanted = refs?.map((ref) => {
|
|
206
|
-
const parsed = parseReference(ref.reference);
|
|
207
|
-
return parsed ? { kind: ref.kind, group: parsed.group ?? "default", id: parsed.id } : void 0;
|
|
208
|
-
});
|
|
209
|
-
const changes = [];
|
|
210
|
-
for (const [group, value] of Object.entries(groups)) {
|
|
211
|
-
if (group === "custom" || !isRec(value)) continue;
|
|
212
|
-
const catalogSource = catalogGroupSource(document, group, options);
|
|
213
|
-
const registered = registeredCatalog(catalogSource, options);
|
|
214
|
-
if (!registered || catalogSource === void 0) continue;
|
|
215
|
-
for (const kind of catalogKinds)
|
|
216
|
-
for (const [id, embedded] of Object.entries(rec(value[kind]))) {
|
|
217
|
-
if (wanted && !wanted.some((entry) => entry && entry.kind === kind && entry.group === group && entry.id === id)) continue;
|
|
218
|
-
const current = registered[kind]?.[id];
|
|
219
|
-
if (current === void 0 || sameRecord(embedded, current)) continue;
|
|
220
|
-
changes.push({ kind, reference: group === "default" ? id : `${group}:${id}`, group, id, source: catalogSource, embedded: rec(embedded), current: embeddedCopy(current) });
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
return {
|
|
224
|
-
changes,
|
|
225
|
-
patch: changes.map((change) => ({ op: "replace", path: `/catalogs/${pointerPart(change.group)}/${change.kind}/${pointerPart(change.id)}`, value: change.current }))
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
var OPFMoveToCustomError = class extends Error {
|
|
229
|
-
code;
|
|
230
|
-
constructor(code, message) {
|
|
231
|
-
super(message);
|
|
232
|
-
this.name = "OPFMoveToCustomError";
|
|
233
|
-
this.code = code;
|
|
234
|
-
}
|
|
235
|
-
};
|
|
236
|
-
var pointerOf = (path) => `/${path.map((part) => pointerPart(String(part))).join("/")}`;
|
|
237
|
-
function moveToCustom(document, ref, options = {}) {
|
|
238
|
-
const catalogs = { catalogs: checkCatalogsOption(options.catalogs, "moveToCustom") };
|
|
239
|
-
const parsed = parseReference(ref.reference);
|
|
240
|
-
if (!parsed || !catalogKinds.includes(ref.kind)) throw new OPFMoveToCustomError("invalid-reference", `moveToCustom: ${JSON.stringify(ref.reference)} is not a ${String(ref.kind)} reference (an id or name:id).`);
|
|
241
|
-
const { kind } = ref;
|
|
242
|
-
const fromGroup = parsed.group ?? "default";
|
|
243
|
-
if (fromGroup === "custom") throw new OPFMoveToCustomError("already-custom", `moveToCustom: ${ref.reference} already names a record of catalogs.custom.`);
|
|
244
|
-
const before = rec(document);
|
|
245
|
-
const records = rec(rec(rec(before.catalogs)[fromGroup])[kind]);
|
|
246
|
-
if (!Object.hasOwn(records, parsed.id)) throw new OPFMoveToCustomError("not-embedded", `moveToCustom: catalogs.${fromGroup}.${kind} does not embed ${JSON.stringify(parsed.id)}.`);
|
|
247
|
-
const fromId = parsed.id;
|
|
248
|
-
const record = rec(records[fromId]);
|
|
249
|
-
const sites = catalogReferenceSites(before);
|
|
250
|
-
const targets = sites.map((site) => resolveReference(before, site.kind, site.reference, { ...catalogs, ...site.group !== void 0 ? { group: site.group } : {} }));
|
|
251
|
-
const isMoved = (found) => found?.origin === "document" && found.kind === kind && found.group === fromGroup && found.id === fromId;
|
|
252
|
-
const inMoved = (site) => site.path.length >= 4 && site.path[0] === "catalogs" && site.path[1] === fromGroup && site.path[2] === kind && site.path[3] === fromId;
|
|
253
|
-
const after = structuredClone(before);
|
|
254
|
-
const groups = after.catalogs;
|
|
255
|
-
const custom = rec(groups.custom);
|
|
256
|
-
const existing = rec(custom[kind]);
|
|
257
|
-
const moved = structuredClone(record);
|
|
258
|
-
const ownSites = sites.map((site, index) => ({ site, found: targets[index] })).filter(({ site }) => inMoved(site));
|
|
259
|
-
if (options.id !== void 0 && (typeof options.id !== "string" || !CATALOG_GROUP_PATTERN.test(options.id))) throw new OPFMoveToCustomError("invalid-id", `moveToCustom: the new id ${JSON.stringify(options.id)} is not a lowercase kebab-case id.`);
|
|
260
|
-
const wanted = options.id ?? fromId;
|
|
261
|
-
let toId = wanted;
|
|
262
|
-
for (let n = 2; Object.hasOwn(existing, toId) && !sameRecord(existing[toId], moved); n++) toId = `${wanted}-${n}`;
|
|
263
|
-
const reused = Object.hasOwn(existing, toId);
|
|
264
|
-
const patch = [];
|
|
265
|
-
const fromRecords = groups[fromGroup][kind];
|
|
266
|
-
delete fromRecords[fromId];
|
|
267
|
-
patch.push({ op: "remove", path: pointerOf(["catalogs", fromGroup, kind, fromId]) });
|
|
268
|
-
if (Object.keys(fromRecords).length === 0) {
|
|
269
|
-
delete groups[fromGroup][kind];
|
|
270
|
-
patch.push({ op: "remove", path: pointerOf(["catalogs", fromGroup, kind]) });
|
|
271
|
-
}
|
|
272
|
-
if (!isRec(groups.custom)) {
|
|
273
|
-
groups.custom = {};
|
|
274
|
-
patch.push({ op: "add", path: pointerOf(["catalogs", "custom"]), value: {} });
|
|
275
|
-
}
|
|
276
|
-
if (!isRec(groups.custom[kind])) {
|
|
277
|
-
groups.custom[kind] = {};
|
|
278
|
-
patch.push({ op: "add", path: pointerOf(["catalogs", "custom", kind]), value: {} });
|
|
279
|
-
}
|
|
280
|
-
const referenceTo = (targetKind, group, id, holder) => {
|
|
281
|
-
const found = resolveReference(after, targetKind, id, { ...catalogs, ...holder !== void 0 ? { group: holder } : {} });
|
|
282
|
-
return found && found.group === group && found.id === id ? id : `${group}:${id}`;
|
|
283
|
-
};
|
|
284
|
-
if (!reused) {
|
|
285
|
-
groups.custom[kind][toId] = moved;
|
|
286
|
-
for (const { site, found } of ownSites) {
|
|
287
|
-
if (!found) continue;
|
|
288
|
-
const target = isMoved(found) ? { group: "custom", id: toId } : { group: found.group, id: found.id };
|
|
289
|
-
setAt(moved, site.path.slice(4), referenceTo(site.kind, target.group, target.id, "custom"));
|
|
290
|
-
}
|
|
291
|
-
patch.push({ op: "add", path: pointerOf(["catalogs", "custom", kind, toId]), value: structuredClone(moved) });
|
|
292
|
-
}
|
|
293
|
-
const references = [];
|
|
294
|
-
sites.forEach((site, index) => {
|
|
295
|
-
if (inMoved(site) || !isMoved(targets[index])) return;
|
|
296
|
-
const written = referenceTo(kind, "custom", toId, site.group);
|
|
297
|
-
if (written === site.reference) return;
|
|
298
|
-
setAt(after, site.path, written);
|
|
299
|
-
references.push(pointerOf(site.path));
|
|
300
|
-
patch.push({ op: "replace", path: pointerOf(site.path), value: written });
|
|
301
|
-
});
|
|
302
|
-
return {
|
|
303
|
-
document: after,
|
|
304
|
-
from: { kind, group: fromGroup, id: fromId, reference: fromGroup === "default" ? fromId : `${fromGroup}:${fromId}` },
|
|
305
|
-
to: { kind, group: "custom", id: toId, reference: toId },
|
|
306
|
-
references,
|
|
307
|
-
patch,
|
|
308
|
-
...toId !== wanted ? { renamed: { from: wanted, to: toId } } : {}
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// src/stats.ts
|
|
313
|
-
var DEFAULT_WORDS_PER_MINUTE = 130;
|
|
314
|
-
var KIND_ORDER = ["text", "items", "bullets", "quote", "metric", "code", "timeline", "chart", "table", "image", "video"];
|
|
315
|
-
var FURNITURE_FIELDS = ["logo", "image", "text", "organization", "socials", "section", "slideNumber", "date"];
|
|
316
|
-
var ZONES = ["left", "center", "right"];
|
|
317
|
-
var LOGO_VARIANTS = ["default", "light", "dark", "stacked", "stackedLight", "stackedDark", "icon", "iconLight", "iconDark", "wordmark", "wordmarkLight", "wordmarkDark"];
|
|
318
|
-
var WORD = /[\p{L}\p{N}\p{M}]+(?:['’.,-][\p{L}\p{N}\p{M}]+)*/gu;
|
|
319
|
-
var UNSPACED = /[-က-႟ក--ヿ㐀-䶿一-鿿豈-]/gu;
|
|
320
|
-
var wordCount = (text) => {
|
|
321
|
-
let extra = 0;
|
|
322
|
-
const spaced = text.replace(UNSPACED, () => {
|
|
323
|
-
extra++;
|
|
324
|
-
return " ";
|
|
325
|
-
});
|
|
326
|
-
return (spaced.match(WORD)?.length ?? 0) + extra;
|
|
327
|
-
};
|
|
328
|
-
var sorted = (values) => [...new Set(values)].sort();
|
|
329
|
-
var sortedCounts = (counts) => Object.fromEntries([...counts].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0));
|
|
330
|
-
var bump = (counts, key) => counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
331
|
-
var str = (value) => typeof value === "string" ? value : null;
|
|
332
|
-
var decimals = (value, places) => Math.round(value * 10 ** places) / 10 ** places;
|
|
333
|
-
var reference = (value) => {
|
|
334
|
-
if (typeof value === "string") return { id: value, inline: false };
|
|
335
|
-
if (isRecord(value)) return { id: str(value.id), inline: true };
|
|
336
|
-
return null;
|
|
337
|
-
};
|
|
338
|
-
var list = (value) => Array.isArray(value) ? value : value === void 0 ? [] : [value];
|
|
339
|
-
var assetForm = (src) => /^asset:/i.test(src) ? "reference" : /^data:/i.test(src) ? "embedded" : /^(https?:)?\/\//i.test(src) || /^pkg:/i.test(src) ? "remote" : "file";
|
|
340
|
-
var embeddedBytes = (src) => {
|
|
341
|
-
const comma = src.indexOf(",");
|
|
342
|
-
if (comma < 0) return 0;
|
|
343
|
-
const payload = src.slice(comma + 1);
|
|
344
|
-
if (!/;base64$/i.test(src.slice(0, comma))) return payload.length;
|
|
345
|
-
const padding = payload.endsWith("==") ? 2 : payload.endsWith("=") ? 1 : 0;
|
|
346
|
-
return Math.max(0, Math.floor(payload.length * 3 / 4) - padding);
|
|
347
|
-
};
|
|
348
|
-
var srcOf = (asset) => typeof asset === "string" ? asset : isRecord(asset) && typeof asset.src === "string" ? asset.src : void 0;
|
|
349
|
-
function slideSize(deck, catalogs) {
|
|
350
|
-
const design = isRecord(deck.design) ? deck.design : {};
|
|
351
|
-
const records = resolveDesignRecords(deck, void 0, catalogs);
|
|
352
|
-
const theme2 = records.theme;
|
|
353
|
-
const themed = typeof design.theme === "string" && !records.diagnostics.some((diagnostic) => diagnostic.kind === "themes");
|
|
354
|
-
const source = design.dimensions !== void 0 ? "design" : themed && theme2.dimensions !== void 0 ? "theme" : "default";
|
|
355
|
-
const dimensions = design.dimensions ?? theme2.dimensions;
|
|
356
|
-
let width = 40 / 3, height = 7.5;
|
|
357
|
-
try {
|
|
358
|
-
const resolved = resolveCanvasDimensions(dimensions);
|
|
359
|
-
width = resolved.width / 96;
|
|
360
|
-
height = resolved.height / 96;
|
|
361
|
-
} catch {
|
|
362
|
-
}
|
|
363
|
-
const preset = typeof dimensions === "string" ? dimensions : isRecord(dimensions) && typeof dimensions.preset === "string" && dimensions.widthInches === void 0 && dimensions.heightInches === void 0 ? dimensions.preset : null;
|
|
364
|
-
return { preset, widthInches: decimals(width, 4), heightInches: decimals(height, 4), aspectRatio: decimals(width / height, 3), source };
|
|
365
|
-
}
|
|
366
|
-
var furniture = (value) => {
|
|
367
|
-
const zones = [], fields = /* @__PURE__ */ new Set();
|
|
368
|
-
if (isRecord(value))
|
|
369
|
-
for (const zone of ZONES) {
|
|
370
|
-
const item = value[zone];
|
|
371
|
-
if (!isRecord(item)) continue;
|
|
372
|
-
const present = FURNITURE_FIELDS.filter((field) => item[field] !== void 0 && item[field] !== false);
|
|
373
|
-
if (present.length) {
|
|
374
|
-
zones.push(zone);
|
|
375
|
-
for (const field of present) fields.add(field);
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
return { configured: isRecord(value), suppressed: value === false, zones, fields: FURNITURE_FIELDS.filter((field) => fields.has(field)) };
|
|
379
|
-
};
|
|
380
|
-
function visitRuns(value, visit) {
|
|
381
|
-
if (typeof value === "string") visit({ text: value });
|
|
382
|
-
else if (typeof value === "number") visit({ text: String(value) });
|
|
383
|
-
else if (Array.isArray(value)) for (const entry of value) visitRuns(entry, visit);
|
|
384
|
-
else if (isRecord(value)) {
|
|
385
|
-
if (typeof value.text === "string") {
|
|
386
|
-
visit(value);
|
|
387
|
-
if (value.description !== void 0) visitRuns(value.description, visit);
|
|
388
|
-
} else if (Array.isArray(value.text)) {
|
|
389
|
-
visitRuns(value.text, visit);
|
|
390
|
-
if (value.description !== void 0) visitRuns(value.description, visit);
|
|
391
|
-
} else if (value.value !== void 0) visitRuns(value.value, visit);
|
|
392
|
-
else if (typeof value.name === "string") visit({ text: value.name });
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
function stats(presentation2, options = {}) {
|
|
396
|
-
const catalogs = { catalogs: checkCatalogsOption(options.catalogs, "stats") };
|
|
397
|
-
if (!isRecord(presentation2)) throw new TypeError("stats needs a presentation object.");
|
|
398
|
-
const deck = presentation2;
|
|
399
|
-
const wordsPerMinute = options.wordsPerMinute ?? DEFAULT_WORDS_PER_MINUTE;
|
|
400
|
-
if (!Number.isFinite(wordsPerMinute) || wordsPerMinute <= 0) throw new RangeError("wordsPerMinute must be a positive number.");
|
|
401
|
-
const slides = Array.isArray(deck.slides) ? deck.slides.filter(isRecord) : [];
|
|
402
|
-
const design = isRecord(deck.design) ? deck.design : {};
|
|
403
|
-
const registry = isRecord(deck.assets) ? deck.assets : {};
|
|
404
|
-
const uses = { total: 0, references: 0, embedded: 0, files: 0, remote: 0 };
|
|
405
|
-
let embeddedTotal = 0;
|
|
406
|
-
const useAsset = (asset) => {
|
|
407
|
-
const src = srcOf(asset);
|
|
408
|
-
if (src === void 0) return;
|
|
409
|
-
const form = assetForm(src);
|
|
410
|
-
uses.total++;
|
|
411
|
-
uses[form === "reference" ? "references" : form === "embedded" ? "embedded" : form === "remote" ? "remote" : "files"]++;
|
|
412
|
-
if (form === "embedded") embeddedTotal += embeddedBytes(src);
|
|
413
|
-
};
|
|
414
|
-
const registryFacts = { entries: 0, embedded: 0, files: 0, remote: 0 };
|
|
415
|
-
for (const entry of Object.values(registry)) {
|
|
416
|
-
const src = srcOf(entry);
|
|
417
|
-
if (src === void 0) continue;
|
|
418
|
-
registryFacts.entries++;
|
|
419
|
-
const form = assetForm(src);
|
|
420
|
-
if (form === "embedded") {
|
|
421
|
-
registryFacts.embedded++;
|
|
422
|
-
embeddedTotal += embeddedBytes(src);
|
|
423
|
-
} else if (form === "remote") registryFacts.remote++;
|
|
424
|
-
else if (form === "file") registryFacts.files++;
|
|
425
|
-
}
|
|
426
|
-
const altOf = (asset) => {
|
|
427
|
-
if (isRecord(asset) && typeof asset.alt === "string") return asset.alt;
|
|
428
|
-
const src = srcOf(asset);
|
|
429
|
-
if (src?.startsWith("asset:")) {
|
|
430
|
-
const entry = registry[src.slice("asset:".length)];
|
|
431
|
-
if (isRecord(entry) && typeof entry.alt === "string") return entry.alt;
|
|
432
|
-
}
|
|
433
|
-
return void 0;
|
|
434
|
-
};
|
|
435
|
-
const images = { content: { total: 0, withAlt: 0, decorative: 0, missingAlt: 0 }, logos: 0, watermarks: { deck: false, slides: 0 }, backgrounds: { deck: false, slides: 0 }, headerFooter: 0, speakerPhotos: 0, videos: 0 };
|
|
436
|
-
const contentImage = (asset) => {
|
|
437
|
-
if (srcOf(asset) === void 0) return 0;
|
|
438
|
-
useAsset(asset);
|
|
439
|
-
images.content.total++;
|
|
440
|
-
const alt = altOf(asset);
|
|
441
|
-
if (alt === void 0 || alt !== "" && alt.trim() === "") images.content.missingAlt++;
|
|
442
|
-
else if (alt === "") images.content.decorative++;
|
|
443
|
-
else images.content.withAlt++;
|
|
444
|
-
return 1;
|
|
445
|
-
};
|
|
446
|
-
const logoImages = (value) => {
|
|
447
|
-
if (srcOf(value) !== void 0) {
|
|
448
|
-
useAsset(value);
|
|
449
|
-
images.logos++;
|
|
450
|
-
return;
|
|
451
|
-
}
|
|
452
|
-
if (isRecord(value)) {
|
|
453
|
-
for (const variant of LOGO_VARIANTS) if (srcOf(value[variant]) !== void 0) {
|
|
454
|
-
useAsset(value[variant]);
|
|
455
|
-
images.logos++;
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
};
|
|
459
|
-
const watermarkOf = (value) => {
|
|
460
|
-
if (value === void 0 || value === false) return false;
|
|
461
|
-
if (srcOf(value) !== void 0) useAsset(value);
|
|
462
|
-
return srcOf(value) !== void 0;
|
|
463
|
-
};
|
|
464
|
-
const backgroundImage = (value) => {
|
|
465
|
-
const picture = imageBackground(value);
|
|
466
|
-
if (!picture) return false;
|
|
467
|
-
useAsset(picture.src);
|
|
468
|
-
return true;
|
|
469
|
-
};
|
|
470
|
-
const furnitureImages = (value) => {
|
|
471
|
-
if (!isRecord(value)) return;
|
|
472
|
-
for (const zone of ZONES) {
|
|
473
|
-
const item = value[zone];
|
|
474
|
-
if (isRecord(item) && srcOf(item.image) !== void 0) {
|
|
475
|
-
useAsset(item.image);
|
|
476
|
-
images.headerFooter++;
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
};
|
|
480
|
-
const designAssets = (value, scope) => {
|
|
481
|
-
if (!isRecord(value)) return;
|
|
482
|
-
logoImages(value.logo);
|
|
483
|
-
if (watermarkOf(value.watermark)) {
|
|
484
|
-
if (scope === "deck") images.watermarks.deck = true;
|
|
485
|
-
else images.watermarks.slides++;
|
|
486
|
-
}
|
|
487
|
-
if (backgroundImage(value.background)) {
|
|
488
|
-
if (scope === "deck") images.backgrounds.deck = true;
|
|
489
|
-
else images.backgrounds.slides++;
|
|
490
|
-
}
|
|
491
|
-
furnitureImages(value.header);
|
|
492
|
-
furnitureImages(value.footer);
|
|
493
|
-
};
|
|
494
|
-
const organizations = list(deck.organization).filter(isRecord).map((entry) => {
|
|
495
|
-
const hasLogo = srcOf(entry.logo) !== void 0;
|
|
496
|
-
if (hasLogo) {
|
|
497
|
-
useAsset(entry.logo);
|
|
498
|
-
images.logos++;
|
|
499
|
-
}
|
|
500
|
-
return { id: str(entry.id) ?? "", name: str(entry.name) ?? "", role: str(entry.role), hasLogo };
|
|
501
|
-
});
|
|
502
|
-
const speakers = list(deck.speaker).filter(isRecord).map((entry) => {
|
|
503
|
-
const hasPhoto = srcOf(entry.photo) !== void 0;
|
|
504
|
-
if (hasPhoto) {
|
|
505
|
-
useAsset(entry.photo);
|
|
506
|
-
images.speakerPhotos++;
|
|
507
|
-
}
|
|
508
|
-
return { id: str(entry.id) ?? "", name: str(entry.name) ?? "", title: str(entry.title), organizationId: str(entry.organizationId), hasPhoto };
|
|
509
|
-
});
|
|
510
|
-
designAssets(design, "deck");
|
|
511
|
-
for (const variable of Object.values(isRecord(deck.variables) ? deck.variables : {})) if (isRecord(variable) && variable.type === "image") useAsset(variable.value);
|
|
512
|
-
const narrative2 = reference(deck.narrative);
|
|
513
|
-
const deckFacts = {
|
|
514
|
-
name: str(deck.name),
|
|
515
|
-
description: typeof deck.description === "string" && deck.description !== "",
|
|
516
|
-
filename: str(deck.filename),
|
|
517
|
-
author: list(deck.author).filter((entry) => typeof entry === "string"),
|
|
518
|
-
language: reference(deck.language),
|
|
519
|
-
slideSize: slideSize(deck, catalogs),
|
|
520
|
-
template: deck.template === true,
|
|
521
|
-
tags: Array.isArray(deck.tags) ? deck.tags.filter((tag) => typeof tag === "string") : [],
|
|
522
|
-
takeaways: list(deck.takeaway).filter((entry) => typeof entry === "string").length,
|
|
523
|
-
declaredMinutes: typeof deck.duration === "number" ? deck.duration : null,
|
|
524
|
-
design: { theme: reference(design.theme), colorScheme: reference(design.colorScheme), fontScheme: reference(design.fontScheme) },
|
|
525
|
-
audience: list(deck.audience).flatMap((entry) => reference(entry) ?? []),
|
|
526
|
-
purpose: reference(deck.purpose),
|
|
527
|
-
tone: reference(deck.tone),
|
|
528
|
-
narrative: narrative2 ? { ...narrative2, beats: isRecord(deck.narrative) && Array.isArray(deck.narrative.beats) ? deck.narrative.beats.length : 0 } : null
|
|
529
|
-
};
|
|
530
|
-
const datasetRecords = isRecord(deck.datasets) ? Object.entries(deck.datasets).filter(([, value]) => isRecord(value)) : [];
|
|
531
|
-
const datasetUse = /* @__PURE__ */ new Map();
|
|
532
|
-
const payloadCounts = { text: 0, items: 0, bullets: 0, quote: 0, metric: 0, code: 0, timeline: 0, chart: 0, table: 0, image: 0, video: 0, blocks: 0, regions: 0, groups: 0, maxDepth: 0 };
|
|
533
|
-
const layouts = /* @__PURE__ */ new Map(), chartTypes = /* @__PURE__ */ new Map(), extensions = /* @__PURE__ */ new Set();
|
|
534
|
-
const chartData = { inline: 0, dataset: 0, source: 0 };
|
|
535
|
-
const tableItems = [];
|
|
536
|
-
let tableRows = 0, tableColumns = 0, datasetBackedTables = 0, chartTotal = 0, captions = 0;
|
|
537
|
-
const hidden = [], withoutNotes = [], sections = [];
|
|
538
|
-
let withTitle = 0, withBeat = 0, unsectioned = 0, withoutLayout = 0, withOwnDesign = 0, withNotes = 0, contentWords = 0, notesWords = 0;
|
|
539
|
-
const headerOverrides = { header: 0, headerSuppressed: 0, footer: 0, footerSuppressed: 0 };
|
|
540
|
-
const total = { citations: 0, footnotes: 0, links: 0, cited: /* @__PURE__ */ new Set(), families: /* @__PURE__ */ new Set() };
|
|
541
|
-
const perSlide = [];
|
|
542
|
-
const contentPerSlide = [];
|
|
543
|
-
const schemeDesigns = [void 0];
|
|
544
|
-
slides.forEach((slide, index) => {
|
|
545
|
-
const id = str(slide.id);
|
|
546
|
-
const ref = { index, id };
|
|
547
|
-
const slideDesign = isRecord(slide.design) ? slide.design : void 0;
|
|
548
|
-
const slideTally = { words: 0, citations: 0, footnotes: 0, links: 0, cited: /* @__PURE__ */ new Set(), families: /* @__PURE__ */ new Set() };
|
|
549
|
-
const kinds = /* @__PURE__ */ new Set();
|
|
550
|
-
let slideImages = 0, slideCharts = 0, slideTables = 0;
|
|
551
|
-
const count = (text) => {
|
|
552
|
-
slideTally.words += wordCount(text);
|
|
553
|
-
};
|
|
554
|
-
const run = (value) => visitRuns(value, (entry) => {
|
|
555
|
-
count(entry.text);
|
|
556
|
-
if (typeof entry.link === "string" && entry.link !== "") slideTally.links++;
|
|
557
|
-
if (entry.cite !== void 0) {
|
|
558
|
-
slideTally.citations++;
|
|
559
|
-
for (const cite of list(entry.cite)) if (typeof cite === "string") slideTally.cited.add(cite);
|
|
560
|
-
}
|
|
561
|
-
if (entry.footnote !== void 0) slideTally.footnotes++;
|
|
562
|
-
if (typeof entry.fontFamily === "string" && entry.fontFamily !== "") slideTally.families.add(entry.fontFamily);
|
|
563
|
-
});
|
|
564
|
-
const caption = (node) => {
|
|
565
|
-
if (node.caption !== void 0) {
|
|
566
|
-
captions++;
|
|
567
|
-
run(node.caption);
|
|
568
|
-
}
|
|
569
|
-
};
|
|
570
|
-
const visitNode = (node, path, depth, kind) => {
|
|
571
|
-
if (kind === "block") payloadCounts.blocks++;
|
|
572
|
-
if (kind === "region") payloadCounts.regions++;
|
|
573
|
-
if (kind !== "root" && Array.isArray(node.blocks)) payloadCounts.groups++;
|
|
574
|
-
if (depth > payloadCounts.maxDepth) payloadCounts.maxDepth = depth;
|
|
575
|
-
for (const key of KIND_ORDER) if (node[key] !== void 0) {
|
|
576
|
-
payloadCounts[key]++;
|
|
577
|
-
kinds.add(key);
|
|
578
|
-
}
|
|
579
|
-
if (isRecord(node.extensions)) for (const key of Object.keys(node.extensions)) extensions.add(key);
|
|
580
|
-
run(node.text);
|
|
581
|
-
run(node.items);
|
|
582
|
-
run(node.bullets);
|
|
583
|
-
caption(node);
|
|
584
|
-
if (node.quote !== void 0) {
|
|
585
|
-
const quote = node.quote;
|
|
586
|
-
if (isRecord(quote)) {
|
|
587
|
-
run(quote.text);
|
|
588
|
-
run(quote.attribution);
|
|
589
|
-
run(quote.source);
|
|
590
|
-
} else run(quote);
|
|
591
|
-
}
|
|
592
|
-
if (isRecord(node.metric)) {
|
|
593
|
-
run(node.metric.value);
|
|
594
|
-
run(node.metric.label);
|
|
595
|
-
run(node.metric.description);
|
|
596
|
-
run(node.metric.unit);
|
|
597
|
-
run(node.metric.delta);
|
|
598
|
-
}
|
|
599
|
-
if (node.timeline !== void 0) {
|
|
600
|
-
const timeline = node.timeline, events = Array.isArray(timeline) ? timeline : isRecord(timeline) && Array.isArray(timeline.events) ? timeline.events : [];
|
|
601
|
-
if (isRecord(timeline)) {
|
|
602
|
-
run(timeline.name);
|
|
603
|
-
run(timeline.description);
|
|
604
|
-
}
|
|
605
|
-
for (const event of events) if (isRecord(event)) {
|
|
606
|
-
run(event.when);
|
|
607
|
-
run(event.what);
|
|
608
|
-
run(event.description);
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
if (node.image !== void 0) slideImages += contentImage(node.image);
|
|
612
|
-
if (node.video !== void 0) {
|
|
613
|
-
useAsset(node.video);
|
|
614
|
-
images.videos++;
|
|
615
|
-
}
|
|
616
|
-
if (isRecord(node.chart)) {
|
|
617
|
-
chartTotal++;
|
|
618
|
-
slideCharts++;
|
|
619
|
-
bump(chartTypes, str(node.chart.type) ?? "unknown");
|
|
620
|
-
const data = node.chart.data;
|
|
621
|
-
if (isRecord(data)) {
|
|
622
|
-
if (typeof data.dataset === "string") {
|
|
623
|
-
chartData.dataset++;
|
|
624
|
-
bump(datasetUse, data.dataset);
|
|
625
|
-
} else if (Array.isArray(data.columns) || Array.isArray(data.rows)) chartData.inline++;
|
|
626
|
-
else if (typeof data.src === "string") {
|
|
627
|
-
chartData.source++;
|
|
628
|
-
useAsset(data.src);
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
if (isRecord(node.table)) {
|
|
633
|
-
slideTables++;
|
|
634
|
-
const table = node.table;
|
|
635
|
-
let rows = 0, columns = 0, dataset = null;
|
|
636
|
-
if (typeof table.dataset === "string") {
|
|
637
|
-
dataset = table.dataset;
|
|
638
|
-
datasetBackedTables++;
|
|
639
|
-
bump(datasetUse, dataset);
|
|
640
|
-
const source = isRecord(deck.datasets) && isRecord(deck.datasets[dataset]) ? deck.datasets[dataset] : void 0;
|
|
641
|
-
rows = Array.isArray(source?.rows) ? source.rows.length : 0;
|
|
642
|
-
columns = Array.isArray(table.fields) ? table.fields.length : Array.isArray(source?.columns) ? source.columns.length : 0;
|
|
643
|
-
} else {
|
|
644
|
-
const body = Array.isArray(table.rows) ? table.rows : [];
|
|
645
|
-
rows = body.length;
|
|
646
|
-
columns = Array.isArray(table.columns) ? table.columns.length : body.reduce((widest, row) => Math.max(widest, Array.isArray(row) ? row.length : 0), 0);
|
|
647
|
-
run(table.columns);
|
|
648
|
-
for (const row of body) run(row);
|
|
649
|
-
}
|
|
650
|
-
tableRows += rows;
|
|
651
|
-
tableColumns += columns;
|
|
652
|
-
tableItems.push({ slide: index, path: `${path}/table`, rows, columns, dataset });
|
|
653
|
-
}
|
|
654
|
-
};
|
|
655
|
-
run(slide.title);
|
|
656
|
-
run(slide.subtitle);
|
|
657
|
-
run(slide.tag);
|
|
658
|
-
const slidePath = `/slides/${index}`;
|
|
659
|
-
visitNode(slide, slidePath, 0, "root");
|
|
660
|
-
visitContentPayloads(slide, slidePath, (node, path) => {
|
|
661
|
-
const relative = path.slice(slidePath.length + 1);
|
|
662
|
-
visitNode(node, path, (relative.match(/(^|\/)blocks\//g) ?? []).length, /(^|\/)blocks\/\d+$/.test(relative) ? "block" : "region");
|
|
663
|
-
});
|
|
664
|
-
const notes = typeof slide.notes === "string" ? slide.notes : "";
|
|
665
|
-
const noteWords = wordCount(notes);
|
|
666
|
-
const hasNotes = notes.trim() !== "";
|
|
667
|
-
if (hasNotes) withNotes++;
|
|
668
|
-
else withoutNotes.push(ref);
|
|
669
|
-
notesWords += noteWords;
|
|
670
|
-
contentWords += slideTally.words;
|
|
671
|
-
contentPerSlide.push(slideTally.words);
|
|
672
|
-
total.citations += slideTally.citations;
|
|
673
|
-
total.footnotes += slideTally.footnotes;
|
|
674
|
-
total.links += slideTally.links;
|
|
675
|
-
for (const cite of slideTally.cited) total.cited.add(cite);
|
|
676
|
-
for (const family of slideTally.families) total.families.add(family);
|
|
677
|
-
const title = typeof slide.title === "string" && slide.title.trim() !== "" ? slide.title : null;
|
|
678
|
-
if (title) withTitle++;
|
|
679
|
-
if (slide.beat !== void 0) withBeat++;
|
|
680
|
-
if (slide.hidden === true) hidden.push(ref);
|
|
681
|
-
const layout2 = str(slide.layout);
|
|
682
|
-
if (layout2) bump(layouts, layout2);
|
|
683
|
-
else withoutLayout++;
|
|
684
|
-
const section = str(slide.section);
|
|
685
|
-
if (section !== null && section !== "") {
|
|
686
|
-
const last = sections.at(-1);
|
|
687
|
-
if (last && last.name === section && last.firstSlide + last.slides === index) last.slides++;
|
|
688
|
-
else sections.push({ name: section, slides: 1, firstSlide: index });
|
|
689
|
-
} else unsectioned++;
|
|
690
|
-
if (slideDesign) {
|
|
691
|
-
withOwnDesign++;
|
|
692
|
-
designAssets(slideDesign, "slide");
|
|
693
|
-
for (const kind of ["header", "footer"]) {
|
|
694
|
-
if (slideDesign[kind] === false) headerOverrides[`${kind}Suppressed`]++;
|
|
695
|
-
else if (isRecord(slideDesign[kind])) headerOverrides[kind]++;
|
|
696
|
-
}
|
|
697
|
-
if (slideDesign.fontScheme !== void 0 || slideDesign.theme !== void 0 && design.fontScheme === void 0) schemeDesigns.push(index);
|
|
698
|
-
}
|
|
699
|
-
if (options.perSlide)
|
|
700
|
-
perSlide.push({
|
|
701
|
-
index,
|
|
702
|
-
id,
|
|
703
|
-
title,
|
|
704
|
-
layout: layout2,
|
|
705
|
-
section: section === "" ? null : section,
|
|
706
|
-
hidden: slide.hidden === true,
|
|
707
|
-
payloads: KIND_ORDER.filter((kind) => kinds.has(kind)),
|
|
708
|
-
words: { content: slideTally.words, notes: noteWords },
|
|
709
|
-
hasNotes,
|
|
710
|
-
speakingSeconds: Math.round(noteWords / wordsPerMinute * 60),
|
|
711
|
-
images: slideImages,
|
|
712
|
-
charts: slideCharts,
|
|
713
|
-
tables: slideTables,
|
|
714
|
-
citations: slideTally.citations
|
|
715
|
-
});
|
|
716
|
-
});
|
|
717
|
-
if (isRecord(deck.extensions)) for (const key of Object.keys(deck.extensions)) extensions.add(key);
|
|
718
|
-
const datasetItems = datasetRecords.map(([id, value]) => ({
|
|
719
|
-
id,
|
|
720
|
-
title: str(value.title),
|
|
721
|
-
columns: Array.isArray(value.columns) ? value.columns.length : 0,
|
|
722
|
-
rows: Array.isArray(value.rows) ? value.rows.length : 0,
|
|
723
|
-
source: isRecord(value.source) ? str(value.source.src) : null,
|
|
724
|
-
referencedBy: datasetUse.get(id) ?? 0
|
|
725
|
-
}));
|
|
726
|
-
const references = Array.isArray(deck.references) ? deck.references.filter(isRecord) : [];
|
|
727
|
-
const referenceIds = references.map((entry) => str(entry.id)).filter((entry) => entry !== null);
|
|
728
|
-
const cited = referenceIds.filter((entry) => total.cited.has(entry));
|
|
729
|
-
const variables = listVariables(deck, isRecord(options.values) ? options.values : {});
|
|
730
|
-
const byKind = /* @__PURE__ */ new Map();
|
|
731
|
-
for (const variable of variables) bump(byKind, variable.kind);
|
|
732
|
-
const variableFacts = {
|
|
733
|
-
declared: variables.length,
|
|
734
|
-
byKind: sortedCounts(byKind),
|
|
735
|
-
required: variables.filter((variable) => variable.required).length,
|
|
736
|
-
optional: variables.filter((variable) => !variable.required).length,
|
|
737
|
-
filled: variables.filter((variable) => variable.filled).length,
|
|
738
|
-
unfilled: variables.filter((variable) => !variable.filled).map((variable) => variable.id),
|
|
739
|
-
unfilledRequired: variables.filter((variable) => !variable.filled && variable.required).map((variable) => variable.id),
|
|
740
|
-
unused: variables.filter((variable) => variable.uses.length === 0).map((variable) => variable.id)
|
|
741
|
-
};
|
|
742
|
-
const families = new Set(total.families), schemeIds = /* @__PURE__ */ new Set(), unresolved = /* @__PURE__ */ new Set();
|
|
743
|
-
const addScheme = (slideIndex) => {
|
|
744
|
-
const resolved = resolveDesignRecords(deck, slideIndex, catalogs);
|
|
745
|
-
for (const diagnostic of resolved.diagnostics) if (diagnostic.kind === "fontSchemes") unresolved.add(diagnostic.reference);
|
|
746
|
-
if (resolved.fontSchemeReference !== void 0) schemeIds.add(resolved.fontSchemeReference);
|
|
747
|
-
const scheme = resolved.fontScheme;
|
|
748
|
-
const named = resolveFontFamilies(scheme);
|
|
749
|
-
families.add(named.heading);
|
|
750
|
-
families.add(named.body);
|
|
751
|
-
if (scheme.code !== void 0) families.add(named.code);
|
|
752
|
-
if (named.accent) families.add(named.accent);
|
|
753
|
-
};
|
|
754
|
-
for (const entry of schemeDesigns) addScheme(entry);
|
|
755
|
-
const catalogGroups = {};
|
|
756
|
-
if (isRecord(deck.catalogs))
|
|
757
|
-
for (const group of Object.keys(deck.catalogs).sort()) {
|
|
758
|
-
const entry = deck.catalogs[group];
|
|
759
|
-
if (!isRecord(entry)) continue;
|
|
760
|
-
const records = {};
|
|
761
|
-
for (const kind of catalogKinds) if (isRecord(entry[kind])) records[kind] = Object.keys(entry[kind]).length;
|
|
762
|
-
catalogGroups[group] = { source: str(entry.source), records };
|
|
763
|
-
}
|
|
764
|
-
const colorVariables = variables.filter((variable) => variable.kind === "color").map((variable) => ({ id: variable.id, value: typeof variable.value === "string" ? variable.value : null, uses: variable.uses.length }));
|
|
765
|
-
const contentMean = slides.length ? decimals(contentWords / slides.length, 1) : 0;
|
|
766
|
-
const result = {
|
|
767
|
-
deck: deckFacts,
|
|
768
|
-
people: { organizations, speakers },
|
|
769
|
-
slides: {
|
|
770
|
-
total: slides.length,
|
|
771
|
-
hidden,
|
|
772
|
-
withTitle,
|
|
773
|
-
withoutTitle: slides.length - withTitle,
|
|
774
|
-
withBeat,
|
|
775
|
-
sections,
|
|
776
|
-
unsectioned,
|
|
777
|
-
layouts: sortedCounts(layouts),
|
|
778
|
-
withoutLayout,
|
|
779
|
-
withOwnDesign
|
|
780
|
-
},
|
|
781
|
-
payloads: payloadCounts,
|
|
782
|
-
words: {
|
|
783
|
-
content: contentWords,
|
|
784
|
-
notes: notesWords,
|
|
785
|
-
total: contentWords + notesWords,
|
|
786
|
-
perSlide: { min: contentPerSlide.length ? Math.min(...contentPerSlide) : 0, max: contentPerSlide.length ? Math.max(...contentPerSlide) : 0, mean: contentMean }
|
|
787
|
-
},
|
|
788
|
-
notes: { withNotes, withoutNotes },
|
|
789
|
-
speakingTime: { basis: "estimate", wordsPerMinute, notesWords, minutes: decimals(notesWords / wordsPerMinute, 1), declaredMinutes: deckFacts.declaredMinutes },
|
|
790
|
-
images,
|
|
791
|
-
charts: { total: chartTotal, byType: sortedCounts(chartTypes), data: chartData },
|
|
792
|
-
tables: { total: tableItems.length, datasetBacked: datasetBackedTables, rows: tableRows, columns: tableColumns, items: tableItems },
|
|
793
|
-
datasets: { count: datasetItems.length, withSource: datasetItems.filter((item) => item.source !== null).length, items: datasetItems },
|
|
794
|
-
citations: { references: references.length, cited, citations: total.citations, footnotes: total.footnotes, captions, links: total.links },
|
|
795
|
-
variables: variableFacts,
|
|
796
|
-
assets: { registry: registryFacts, uses, embeddedBytes: embeddedTotal },
|
|
797
|
-
headerFooter: {
|
|
798
|
-
header: furniture(design.header),
|
|
799
|
-
footer: furniture(design.footer),
|
|
800
|
-
slides: { headerOverrides: headerOverrides.header, headerSuppressed: headerOverrides.headerSuppressed, footerOverrides: headerOverrides.footer, footerSuppressed: headerOverrides.footerSuppressed }
|
|
801
|
-
},
|
|
802
|
-
fonts: { families: sorted(families), schemeIds: sorted(schemeIds), unresolvedSchemeIds: sorted(unresolved), runOverrides: sorted(total.families) },
|
|
803
|
-
colors: { variables: colorVariables },
|
|
804
|
-
extensions: sorted(extensions),
|
|
805
|
-
catalogs: catalogGroups
|
|
806
|
-
};
|
|
807
|
-
if (options.perSlide) result.perSlide = perSlide;
|
|
808
|
-
return result;
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
export { OPFMoveToCustomError, copySlides, embed, moveToCustom, sameRecord, stats, updateFromCatalog };
|