@openpresentation/opf 0.11.3 → 0.12.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 -0
- package/dist/audit.d.ts +156 -0
- package/dist/audit.js +7 -0
- package/dist/{catalogs-CUClB3nl.d.ts → catalogs-u6TEeMcz.d.ts} +1 -1
- package/dist/catalogs.d.ts +2 -2
- package/dist/catalogs.js +2 -1
- package/dist/{chunk-UDPSGTZI.js → chunk-32DIB5BN.js} +12 -9
- package/dist/chunk-4FWCY4ZV.js +198 -0
- package/dist/chunk-6TSDIPSH.js +3624 -0
- package/dist/chunk-FYLJVF7X.js +18448 -0
- package/dist/{chunk-HJL64ETN.js → chunk-GJKJL4YY.js} +14 -0
- package/dist/chunk-JENJZR3F.js +1690 -0
- package/dist/{chunk-57NWIYX3.js → chunk-JVTN3HPP.js} +18 -4
- package/dist/{chunk-JTXCMVVP.js → chunk-RVN5C2FX.js} +754 -39
- package/dist/chunk-S5W34SIJ.js +1 -0
- package/dist/chunk-S667QI3M.js +261 -0
- package/dist/chunk-UQKJWHSS.js +1332 -0
- package/dist/{chunk-RXNFDGPC.js → chunk-WXSPETQ6.js} +311 -40
- package/dist/composition-DWbCiMwF.d.ts +1523 -0
- package/dist/composition.d.ts +1 -1
- package/dist/composition.js +2 -1
- package/dist/convert.d.ts +261 -0
- package/dist/convert.js +1107 -0
- package/dist/diff.d.ts +145 -0
- package/dist/diff.js +604 -0
- package/dist/docs.js +69 -15
- package/dist/examples.d.ts +1 -1
- package/dist/font-policy.d.ts +15 -0
- package/dist/font-policy.js +1 -1
- package/dist/format.d.ts +20 -0
- package/dist/format.js +83 -0
- package/dist/index.d.ts +173 -24
- package/dist/index.js +926 -262
- package/dist/lint.d.ts +4 -4
- package/dist/lint.js +6 -5
- package/dist/markdown.d.ts +74 -0
- package/dist/markdown.js +1941 -0
- package/dist/pagination.d.ts +1 -1
- package/dist/pagination.js +6 -5
- package/dist/patch.d.ts +99 -0
- package/dist/patch.js +6 -0
- package/dist/{presentation-Cn6vTOCP.d.ts → presentation-DRx4hpNZ.d.ts} +479 -32
- package/dist/repo-readme.js +1 -1
- package/dist/{schemas-X_NniU4A.d.ts → schemas-BSjlG8-R.d.ts} +28 -0
- package/dist/schemas.d.ts +1 -1
- package/dist/schemas.js +1 -1
- package/dist/spec/reference/font-policy.json +311 -40
- package/dist/spec/reference/font-policy.schema.json +40 -0
- package/dist/spec/reference/symbol-font-encodings.json +18354 -0
- package/dist/spec/reference/symbol-font-encodings.schema.json +156 -0
- package/dist/spec/schemas/opf.schema.json +608 -35
- package/dist/spec-files.d.ts +1 -1
- package/dist/spec-files.js +1 -1
- package/dist/symbol-font-encodings.d.ts +128 -0
- package/dist/symbol-font-encodings.js +1 -0
- package/dist/types.d.ts +4 -4
- package/dist/validator-bu396ffT.d.ts +172 -0
- package/dist/validator.d.ts +4 -36
- package/dist/validator.js +5 -4
- package/package.json +31 -2
- package/dist/chunk-BVLWFMDX.js +0 -1812
- package/dist/chunk-JCXHSTSM.js +0 -1366
- package/dist/composition-DzLwY-Mi.d.ts +0 -887
- /package/dist/{chunk-AEUSVEUY.js → chunk-3ZGSWEHK.js} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { validatePresentation } from './chunk-UQKJWHSS.js';
|
|
2
|
+
|
|
3
|
+
// src/patch.ts
|
|
4
|
+
var PatchError = class extends Error {
|
|
5
|
+
code;
|
|
6
|
+
/** The JSON Pointer the failing operation addressed, when known. */
|
|
7
|
+
path;
|
|
8
|
+
/** The index of the failing operation within the patch, when known. */
|
|
9
|
+
index;
|
|
10
|
+
/** The failing operation, when known. */
|
|
11
|
+
operation;
|
|
12
|
+
constructor(code, message, details = {}) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = "PatchError";
|
|
15
|
+
this.code = code;
|
|
16
|
+
if (details.path !== void 0) this.path = details.path;
|
|
17
|
+
if (details.index !== void 0) this.index = details.index;
|
|
18
|
+
if (details.operation !== void 0) this.operation = details.operation;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
var PatchValidationError = class extends PatchError {
|
|
22
|
+
validation;
|
|
23
|
+
constructor(validation) {
|
|
24
|
+
super("patch-invalid-document", "The patched document is not a valid OPF presentation.");
|
|
25
|
+
this.name = "PatchValidationError";
|
|
26
|
+
this.validation = validation;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
var own = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
30
|
+
var isObject = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
31
|
+
var clone = (value) => structuredClone(value);
|
|
32
|
+
function jsonEqual(a, b) {
|
|
33
|
+
if (a === b) return true;
|
|
34
|
+
if (!a || !b || typeof a !== "object" || typeof b !== "object") return false;
|
|
35
|
+
if (Array.isArray(a) !== Array.isArray(b)) return false;
|
|
36
|
+
if (Array.isArray(a)) {
|
|
37
|
+
const other = b;
|
|
38
|
+
return a.length === other.length && a.every((item, i) => jsonEqual(item, other[i]));
|
|
39
|
+
}
|
|
40
|
+
const left = a, right = b;
|
|
41
|
+
const keys = Object.keys(left);
|
|
42
|
+
return keys.length === Object.keys(right).length && keys.every((key) => own(right, key) && jsonEqual(left[key], right[key]));
|
|
43
|
+
}
|
|
44
|
+
function escapePointerToken(token) {
|
|
45
|
+
return String(token).replaceAll("~", "~0").replaceAll("/", "~1");
|
|
46
|
+
}
|
|
47
|
+
function unescapePointerToken(token) {
|
|
48
|
+
return token.replaceAll("~1", "/").replaceAll("~0", "~");
|
|
49
|
+
}
|
|
50
|
+
function parsePointer(pointer) {
|
|
51
|
+
if (typeof pointer !== "string" || pointer !== "" && !pointer.startsWith("/") || /~(?![01])/u.test(pointer)) {
|
|
52
|
+
throw new PatchError("invalid-json-pointer", "Expected a JSON Pointer (empty string or /path with ~0 and ~1 escapes).", { path: typeof pointer === "string" ? pointer : void 0 });
|
|
53
|
+
}
|
|
54
|
+
return pointer === "" ? [] : pointer.slice(1).split("/").map(unescapePointerToken);
|
|
55
|
+
}
|
|
56
|
+
function formatPointer(tokens) {
|
|
57
|
+
return tokens.length ? `/${tokens.map(escapePointerToken).join("/")}` : "";
|
|
58
|
+
}
|
|
59
|
+
function pointerFromPath(path) {
|
|
60
|
+
if (Array.isArray(path)) return formatPointer(path);
|
|
61
|
+
if (typeof path !== "string") throw new PatchError("invalid-json-pointer", "A path must be a string or an array of segments.");
|
|
62
|
+
if (path === "") return "";
|
|
63
|
+
if (path.startsWith("/")) {
|
|
64
|
+
parsePointer(path);
|
|
65
|
+
return path;
|
|
66
|
+
}
|
|
67
|
+
return formatPointer(path.split(".").filter(Boolean));
|
|
68
|
+
}
|
|
69
|
+
function splitPointer(pointer) {
|
|
70
|
+
const tokens = parsePointer(pointer);
|
|
71
|
+
if (!tokens.length) throw new PatchError("invalid-json-pointer", "The root pointer has no parent.", { path: pointer });
|
|
72
|
+
return { parent: formatPointer(tokens.slice(0, -1)), token: tokens[tokens.length - 1] };
|
|
73
|
+
}
|
|
74
|
+
function readPointer(document, pointer) {
|
|
75
|
+
const tokens = typeof pointer === "string" ? parsePointer(pointer) : pointer;
|
|
76
|
+
let value = document;
|
|
77
|
+
for (const token of tokens) {
|
|
78
|
+
if (Array.isArray(value)) {
|
|
79
|
+
if (!/^(0|[1-9][0-9]*)$/.test(token)) return { found: false };
|
|
80
|
+
const at = Number(token);
|
|
81
|
+
if (!Number.isSafeInteger(at) || at >= value.length) return { found: false };
|
|
82
|
+
value = value[at];
|
|
83
|
+
} else if (value && typeof value === "object" && own(value, token)) value = value[token];
|
|
84
|
+
else return { found: false };
|
|
85
|
+
}
|
|
86
|
+
return { found: true, value };
|
|
87
|
+
}
|
|
88
|
+
function getAtPointer(document, pointer) {
|
|
89
|
+
const result = readPointer(document, pointer);
|
|
90
|
+
if (!result.found) {
|
|
91
|
+
const shown = typeof pointer === "string" ? pointer : formatPointer(pointer);
|
|
92
|
+
throw new PatchError("patch-path-missing", `Patch path does not exist: ${shown || "/"}`, { path: shown });
|
|
93
|
+
}
|
|
94
|
+
return result.value;
|
|
95
|
+
}
|
|
96
|
+
var hasPointer = (document, pointer) => readPointer(document, pointer).found;
|
|
97
|
+
function arrayIndex(token, length, allowEnd, path) {
|
|
98
|
+
if (allowEnd && token === "-") return length;
|
|
99
|
+
if (!/^(0|[1-9][0-9]*)$/.test(token)) throw new PatchError("invalid-array-index", `Invalid array index: ${token}`, { path });
|
|
100
|
+
const at = Number(token);
|
|
101
|
+
if (!Number.isSafeInteger(at) || at > length || !allowEnd && at >= length) throw new PatchError("invalid-array-index", `Array index out of bounds: ${token}`, { path });
|
|
102
|
+
return at;
|
|
103
|
+
}
|
|
104
|
+
function normalizePatch(patch) {
|
|
105
|
+
if (!Array.isArray(patch)) throw new PatchError("invalid-patch", "A JSON Patch must be an array of operations.");
|
|
106
|
+
return patch.map((operation, index) => normalizeOperation(operation, index));
|
|
107
|
+
}
|
|
108
|
+
function normalizeOperation(operation, index) {
|
|
109
|
+
const fail = (code, message, path) => new PatchError(code, index === void 0 ? message : `Operation ${index}: ${message}`, { index, operation, path });
|
|
110
|
+
if (!isObject(operation)) throw fail("invalid-patch-operation", "Expected an operation object.");
|
|
111
|
+
const op = operation.op;
|
|
112
|
+
if (typeof op !== "string" || !["add", "remove", "replace", "move", "copy", "test"].includes(op)) {
|
|
113
|
+
throw fail("unsupported-patch-operation", `Unknown operation: ${String(op)}`);
|
|
114
|
+
}
|
|
115
|
+
if (typeof operation.path !== "string") throw fail("invalid-patch-operation", "An operation needs a string path.");
|
|
116
|
+
try {
|
|
117
|
+
parsePointer(operation.path);
|
|
118
|
+
} catch (error) {
|
|
119
|
+
throw fail("invalid-json-pointer", error.message, operation.path);
|
|
120
|
+
}
|
|
121
|
+
if (op === "move" || op === "copy") {
|
|
122
|
+
if (typeof operation.from !== "string") throw fail("invalid-patch-operation", `${op} requires a string from.`, operation.path);
|
|
123
|
+
try {
|
|
124
|
+
parsePointer(operation.from);
|
|
125
|
+
} catch (error) {
|
|
126
|
+
throw fail("invalid-json-pointer", error.message, operation.from);
|
|
127
|
+
}
|
|
128
|
+
return { op, from: operation.from, path: operation.path };
|
|
129
|
+
}
|
|
130
|
+
if (op === "remove") return { op, path: operation.path };
|
|
131
|
+
if (!own(operation, "value")) throw fail("invalid-patch-operation", `${op} requires value.`, operation.path);
|
|
132
|
+
return { op, path: operation.path, value: clone(operation.value) };
|
|
133
|
+
}
|
|
134
|
+
function parentOf(document, tokens, path) {
|
|
135
|
+
const key = tokens[tokens.length - 1];
|
|
136
|
+
const found = readPointer(document, tokens.slice(0, -1));
|
|
137
|
+
if (!found.found || !found.value || typeof found.value !== "object") {
|
|
138
|
+
throw new PatchError("patch-parent-missing", `Patch parent does not exist for ${path}.`, { path });
|
|
139
|
+
}
|
|
140
|
+
return { parent: found.value, key };
|
|
141
|
+
}
|
|
142
|
+
var NONE = /* @__PURE__ */ Symbol("none");
|
|
143
|
+
function addAt(document, path, value) {
|
|
144
|
+
const tokens = parsePointer(path);
|
|
145
|
+
if (!tokens.length) return { document: clone(value), inverse: { op: "replace", path: "", value: clone(document) } };
|
|
146
|
+
const { parent, key } = parentOf(document, tokens, path);
|
|
147
|
+
if (Array.isArray(parent)) {
|
|
148
|
+
const at = arrayIndex(key, parent.length, true, path);
|
|
149
|
+
parent.splice(at, 0, clone(value));
|
|
150
|
+
return { document, inverse: { op: "remove", path: formatPointer([...tokens.slice(0, -1), at]) } };
|
|
151
|
+
}
|
|
152
|
+
const record = parent;
|
|
153
|
+
const previous = own(record, key) ? record[key] : NONE;
|
|
154
|
+
Object.defineProperty(record, key, { value: clone(value), enumerable: true, configurable: true, writable: true });
|
|
155
|
+
return { document, inverse: previous === NONE ? { op: "remove", path } : { op: "replace", path, value: clone(previous) } };
|
|
156
|
+
}
|
|
157
|
+
function replaceAt(document, path, value) {
|
|
158
|
+
const tokens = parsePointer(path);
|
|
159
|
+
if (!tokens.length) return { document: clone(value), inverse: { op: "replace", path: "", value: clone(document) } };
|
|
160
|
+
const { parent, key } = parentOf(document, tokens, path);
|
|
161
|
+
let previous;
|
|
162
|
+
if (Array.isArray(parent)) {
|
|
163
|
+
const at = arrayIndex(key, parent.length, false, path);
|
|
164
|
+
previous = parent[at];
|
|
165
|
+
parent[at] = clone(value);
|
|
166
|
+
} else {
|
|
167
|
+
const record = parent;
|
|
168
|
+
if (!own(record, key)) throw new PatchError("patch-path-missing", `Patch path does not exist: ${path}.`, { path });
|
|
169
|
+
previous = record[key];
|
|
170
|
+
Object.defineProperty(record, key, { value: clone(value), enumerable: true, configurable: true, writable: true });
|
|
171
|
+
}
|
|
172
|
+
return { document, inverse: { op: "replace", path, value: clone(previous) } };
|
|
173
|
+
}
|
|
174
|
+
function removeAt(document, path) {
|
|
175
|
+
const tokens = parsePointer(path);
|
|
176
|
+
if (!tokens.length) throw new PatchError("patch-root-remove", "The document root cannot be removed.", { path });
|
|
177
|
+
const { parent, key } = parentOf(document, tokens, path);
|
|
178
|
+
let previous;
|
|
179
|
+
if (Array.isArray(parent)) {
|
|
180
|
+
const at = arrayIndex(key, parent.length, false, path);
|
|
181
|
+
previous = parent[at];
|
|
182
|
+
parent.splice(at, 1);
|
|
183
|
+
return { document, inverse: { op: "add", path: formatPointer([...tokens.slice(0, -1), at]), value: clone(previous) } };
|
|
184
|
+
}
|
|
185
|
+
const record = parent;
|
|
186
|
+
if (!own(record, key)) throw new PatchError("patch-path-missing", `Patch path does not exist: ${path}.`, { path });
|
|
187
|
+
previous = record[key];
|
|
188
|
+
delete record[key];
|
|
189
|
+
return { document, inverse: { op: "add", path, value: clone(previous) } };
|
|
190
|
+
}
|
|
191
|
+
function applyOne(document, operation) {
|
|
192
|
+
switch (operation.op) {
|
|
193
|
+
case "add": {
|
|
194
|
+
const r = addAt(document, operation.path, operation.value);
|
|
195
|
+
return { document: r.document, inverse: [r.inverse] };
|
|
196
|
+
}
|
|
197
|
+
case "replace": {
|
|
198
|
+
const r = replaceAt(document, operation.path, operation.value);
|
|
199
|
+
return { document: r.document, inverse: [r.inverse] };
|
|
200
|
+
}
|
|
201
|
+
case "remove": {
|
|
202
|
+
const r = removeAt(document, operation.path);
|
|
203
|
+
return { document: r.document, inverse: [r.inverse] };
|
|
204
|
+
}
|
|
205
|
+
case "test": {
|
|
206
|
+
const found = readPointer(document, operation.path);
|
|
207
|
+
if (!found.found || !jsonEqual(found.value, operation.value)) throw new PatchError("patch-test-failed", `Test failed at ${operation.path || "/"}: the value changed.`, { path: operation.path });
|
|
208
|
+
return { document, inverse: [] };
|
|
209
|
+
}
|
|
210
|
+
case "copy": {
|
|
211
|
+
const value = clone(getAtPointer(document, operation.from));
|
|
212
|
+
const r = addAt(document, operation.path, value);
|
|
213
|
+
return { document: r.document, inverse: [r.inverse] };
|
|
214
|
+
}
|
|
215
|
+
case "move": {
|
|
216
|
+
const from = parsePointer(operation.from), to = parsePointer(operation.path);
|
|
217
|
+
const value = clone(getAtPointer(document, from));
|
|
218
|
+
if (from.length === to.length && from.every((token, i) => token === to[i])) return { document, inverse: [] };
|
|
219
|
+
if (to.length > from.length && from.every((token, i) => to[i] === token)) {
|
|
220
|
+
throw new PatchError("patch-invalid-move", "Cannot move a value into its descendant.", { path: operation.path });
|
|
221
|
+
}
|
|
222
|
+
const removed = removeAt(document, operation.from);
|
|
223
|
+
const added = addAt(removed.document, operation.path, value);
|
|
224
|
+
return { document: added.document, inverse: [added.inverse, removed.inverse] };
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
function applyPatchWithInverse(document, patch, options = {}) {
|
|
229
|
+
const operations = normalizePatch(patch);
|
|
230
|
+
let working = clone(document);
|
|
231
|
+
const inverse = [];
|
|
232
|
+
for (const [index, operation] of operations.entries()) {
|
|
233
|
+
try {
|
|
234
|
+
const step = applyOne(working, operation);
|
|
235
|
+
working = step.document;
|
|
236
|
+
inverse.unshift(...step.inverse);
|
|
237
|
+
} catch (error) {
|
|
238
|
+
if (error instanceof PatchError && error.index === void 0) {
|
|
239
|
+
const wrapped = new PatchError(error.code, `Operation ${index}: ${error.message}`, { path: error.path, index, operation });
|
|
240
|
+
throw wrapped;
|
|
241
|
+
}
|
|
242
|
+
throw error;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
const result = { document: working, inverse, patch: operations };
|
|
246
|
+
if (options.validate) {
|
|
247
|
+
const validator = typeof options.validate === "function" ? options.validate : (value) => validatePresentation(value);
|
|
248
|
+
const validation = validator(working);
|
|
249
|
+
if (!validation.valid || options.strict && Array.isArray(validation.warnings) && validation.warnings.length) throw new PatchValidationError(validation);
|
|
250
|
+
result.validation = validation;
|
|
251
|
+
}
|
|
252
|
+
return result;
|
|
253
|
+
}
|
|
254
|
+
function applyPatch(document, patch, options = {}) {
|
|
255
|
+
return applyPatchWithInverse(document, patch, options).document;
|
|
256
|
+
}
|
|
257
|
+
function invertPatch(document, patch) {
|
|
258
|
+
return applyPatchWithInverse(document, patch).inverse;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export { PatchError, PatchValidationError, applyPatch, applyPatchWithInverse, escapePointerToken, formatPointer, getAtPointer, hasPointer, invertPatch, jsonEqual, normalizePatch, parsePointer, pointerFromPath, readPointer, splitPointer, unescapePointerToken };
|