@pixerate/editor 0.154.0 → 0.155.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/dist/animation-editor/index.cjs +2 -3
- package/dist/animation-editor/index.js +1 -2
- package/dist/canvas/index.cjs +15 -16
- package/dist/canvas/index.js +2 -3
- package/dist/chart/index.cjs +2 -3
- package/dist/chart/index.js +1 -2
- package/dist/chunk-M4MIZPQI.cjs +393 -0
- package/dist/chunk-NHLYK3AX.js +393 -0
- package/dist/{chunk-XFDQEAOS.cjs → chunk-RQCMSEM5.cjs} +2 -2
- package/dist/{chunk-BCY22GBH.js → chunk-SDHZG5TF.js} +1 -1
- package/dist/{chunk-HVX35M2I.cjs → chunk-WI7QJA7A.cjs} +2 -2
- package/dist/{chunk-4J4MC3F5.js → chunk-YXOW456B.js} +1 -1
- package/dist/diagram/index.cjs +2 -3
- package/dist/diagram/index.js +1 -2
- package/dist/image-editor/controller.d.cts +8 -0
- package/dist/image-editor/controller.d.ts +8 -0
- package/dist/image-editor/editorDocument.d.cts +16 -0
- package/dist/image-editor/editorDocument.d.ts +16 -0
- package/dist/image-editor/index.cjs +102 -52
- package/dist/image-editor/index.d.cts +1 -0
- package/dist/image-editor/index.d.ts +1 -0
- package/dist/image-editor/index.js +51 -1
- package/dist/index.cjs +4 -5
- package/dist/index.js +2 -3
- package/dist/paint-editor/controller.d.cts +8 -0
- package/dist/paint-editor/controller.d.ts +8 -0
- package/dist/paint-editor/editorDocument.d.cts +17 -0
- package/dist/paint-editor/editorDocument.d.ts +17 -0
- package/dist/paint-editor/index.cjs +74 -18
- package/dist/paint-editor/index.d.cts +1 -0
- package/dist/paint-editor/index.d.ts +1 -0
- package/dist/paint-editor/index.js +58 -2
- package/dist/parameters/index.cjs +2 -3
- package/dist/parameters/index.js +1 -2
- package/dist/persistence/assets.d.cts +51 -0
- package/dist/persistence/assets.d.ts +51 -0
- package/dist/persistence/editorDocument.d.cts +12 -0
- package/dist/persistence/editorDocument.d.ts +12 -0
- package/dist/persistence/index.cjs +32 -8
- package/dist/persistence/index.d.cts +1 -0
- package/dist/persistence/index.d.ts +1 -0
- package/dist/persistence/index.js +34 -10
- package/dist/spreadsheet/index.cjs +3 -4
- package/dist/spreadsheet/index.js +2 -3
- package/dist/tokens/index.cjs +3 -4
- package/dist/tokens/index.js +2 -3
- package/dist/vector/index.cjs +2 -3
- package/dist/vector/index.js +1 -2
- package/dist/video-editor/index.cjs +2 -3
- package/dist/video-editor/index.js +1 -2
- package/package.json +1 -1
- package/skills/pixerate-image-editor/SKILL.md +16 -24
- package/skills/pixerate-image-editor/references/smart-objects.md +28 -0
- package/skills/pixerate-paint-editor/SKILL.md +17 -5
- package/dist/chunk-5H2C3QSF.cjs +0 -134
- package/dist/chunk-GNV54DLO.js +0 -134
- package/dist/chunk-L5OWG2NA.cjs +0 -135
- package/dist/chunk-WHKNYFM2.js +0 -135
|
@@ -61,8 +61,7 @@ var _chunkALNIFK5Gcjs = require('../chunk-ALNIFK5G.cjs');
|
|
|
61
61
|
require('../chunk-UWEQ55MY.cjs');
|
|
62
62
|
|
|
63
63
|
|
|
64
|
-
var
|
|
65
|
-
require('../chunk-L5OWG2NA.cjs');
|
|
64
|
+
var _chunkM4MIZPQIcjs = require('../chunk-M4MIZPQI.cjs');
|
|
66
65
|
require('../chunk-2BSBFBOA.cjs');
|
|
67
66
|
|
|
68
67
|
|
|
@@ -5938,7 +5937,7 @@ function createAnimationEffectsToolProvider(controller, options = {}) {
|
|
|
5938
5937
|
|
|
5939
5938
|
// src/animation-editor/editorDocument.ts
|
|
5940
5939
|
function createAnimationEditorDocument(controller) {
|
|
5941
|
-
return
|
|
5940
|
+
return _chunkM4MIZPQIcjs.defineEditorDocument.call(void 0, {
|
|
5942
5941
|
kind: "animation",
|
|
5943
5942
|
get: () => controller.getScene(),
|
|
5944
5943
|
load: (document, { history }) => {
|
package/dist/canvas/index.cjs
CHANGED
|
@@ -60,7 +60,7 @@ var _chunkZVNAMTFOcjs = require('../chunk-ZVNAMTFO.cjs');
|
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
|
|
63
|
-
var
|
|
63
|
+
var _chunkWI7QJA7Acjs = require('../chunk-WI7QJA7A.cjs');
|
|
64
64
|
|
|
65
65
|
|
|
66
66
|
|
|
@@ -215,8 +215,7 @@ require('../chunk-WOFXZ3XU.cjs');
|
|
|
215
215
|
var _chunkYQGCPL5Xcjs = require('../chunk-YQGCPL5X.cjs');
|
|
216
216
|
|
|
217
217
|
|
|
218
|
-
var
|
|
219
|
-
require('../chunk-L5OWG2NA.cjs');
|
|
218
|
+
var _chunkM4MIZPQIcjs = require('../chunk-M4MIZPQI.cjs');
|
|
220
219
|
require('../chunk-2BSBFBOA.cjs');
|
|
221
220
|
|
|
222
221
|
|
|
@@ -4050,7 +4049,7 @@ function getTokenPropertyScope(property, node) {
|
|
|
4050
4049
|
}
|
|
4051
4050
|
function getTokensForProperty(state, property, node) {
|
|
4052
4051
|
const scope = getTokenPropertyScope(property, node);
|
|
4053
|
-
return state.variables.filter((v) => v.type === property.type &&
|
|
4052
|
+
return state.variables.filter((v) => v.type === property.type && _chunkWI7QJA7Acjs.isTokenInScope.call(void 0, v, scope));
|
|
4054
4053
|
}
|
|
4055
4054
|
function lookupOf(nodes) {
|
|
4056
4055
|
return new Map(nodes.map((n3) => [n3.id, n3]));
|
|
@@ -4058,7 +4057,7 @@ function lookupOf(nodes) {
|
|
|
4058
4057
|
function validModes(state, modes, into) {
|
|
4059
4058
|
for (const [collectionId, modeId] of Object.entries(modes)) {
|
|
4060
4059
|
if (state) {
|
|
4061
|
-
const collection =
|
|
4060
|
+
const collection = _chunkWI7QJA7Acjs.getTokenCollection.call(void 0, state, collectionId);
|
|
4062
4061
|
if (!collection || !collection.modes.some((m) => m.id === modeId)) continue;
|
|
4063
4062
|
}
|
|
4064
4063
|
into[collectionId] = modeId;
|
|
@@ -4113,7 +4112,7 @@ function applyBindings(node, state, modes, options, only) {
|
|
|
4113
4112
|
if (only && !only.has(variableId)) continue;
|
|
4114
4113
|
const property = getCanvasTokenProperty(key, options);
|
|
4115
4114
|
if (!property || !property.appliesTo(next)) continue;
|
|
4116
|
-
const resolved =
|
|
4115
|
+
const resolved = _chunkWI7QJA7Acjs.resolveToken.call(void 0, state, variableId, modes);
|
|
4117
4116
|
if (!resolved.ok || resolved.type !== property.type) continue;
|
|
4118
4117
|
next = property.write(next, resolved.value);
|
|
4119
4118
|
}
|
|
@@ -4136,7 +4135,7 @@ function inspectNodeTokens(node, nodes, state, options = {}) {
|
|
|
4136
4135
|
for (const [key, variableId] of Object.entries(getNodeTokenBindings(node))) {
|
|
4137
4136
|
const property = getCanvasTokenProperty(key, options);
|
|
4138
4137
|
if (!property) continue;
|
|
4139
|
-
out.push({ property, variableId, variable:
|
|
4138
|
+
out.push({ property, variableId, variable: _chunkWI7QJA7Acjs.getTokenVariable.call(void 0, state, variableId), resolution: _chunkWI7QJA7Acjs.resolveToken.call(void 0, state, variableId, modes) });
|
|
4140
4139
|
}
|
|
4141
4140
|
return out;
|
|
4142
4141
|
}
|
|
@@ -4148,12 +4147,12 @@ function setDataRecord(node, key, record) {
|
|
|
4148
4147
|
}
|
|
4149
4148
|
function bindCanvasToken(nodes, ids, propertyKey, variableId, state, options = {}) {
|
|
4150
4149
|
const property = getCanvasTokenProperty(propertyKey, options);
|
|
4151
|
-
if (!property) throw new (0,
|
|
4150
|
+
if (!property) throw new (0, _chunkWI7QJA7Acjs.TokenError)("not-found", `No bindable property \`${propertyKey}\``);
|
|
4152
4151
|
if (variableId !== null) {
|
|
4153
|
-
const variable =
|
|
4154
|
-
if (!variable) throw new (0,
|
|
4152
|
+
const variable = _chunkWI7QJA7Acjs.getTokenVariable.call(void 0, state, variableId);
|
|
4153
|
+
if (!variable) throw new (0, _chunkWI7QJA7Acjs.TokenError)("not-found", `No variable \`${variableId}\``);
|
|
4155
4154
|
if (variable.type !== property.type) {
|
|
4156
|
-
throw new (0,
|
|
4155
|
+
throw new (0, _chunkWI7QJA7Acjs.TokenError)("type-mismatch", `${property.label} takes a ${property.type} variable; \`${variable.name}\` is a ${variable.type}`);
|
|
4157
4156
|
}
|
|
4158
4157
|
}
|
|
4159
4158
|
const targets = new Set(ids);
|
|
@@ -4175,9 +4174,9 @@ function bindCanvasToken(nodes, ids, propertyKey, variableId, state, options = {
|
|
|
4175
4174
|
}
|
|
4176
4175
|
function setCanvasTokenMode(nodes, ids, collectionId, modeId, state, options = {}) {
|
|
4177
4176
|
if (modeId !== null) {
|
|
4178
|
-
const collection =
|
|
4179
|
-
if (!collection) throw new (0,
|
|
4180
|
-
if (!collection.modes.some((m) => m.id === modeId)) throw new (0,
|
|
4177
|
+
const collection = _chunkWI7QJA7Acjs.getTokenCollection.call(void 0, state, collectionId);
|
|
4178
|
+
if (!collection) throw new (0, _chunkWI7QJA7Acjs.TokenError)("not-found", `No collection \`${collectionId}\``);
|
|
4179
|
+
if (!collection.modes.some((m) => m.id === modeId)) throw new (0, _chunkWI7QJA7Acjs.TokenError)("not-found", `No mode \`${modeId}\` in \`${collection.name}\``);
|
|
4181
4180
|
}
|
|
4182
4181
|
const targets = new Set(ids);
|
|
4183
4182
|
let changed = false;
|
|
@@ -4198,7 +4197,7 @@ function setCanvasTokenMode(nodes, ids, collectionId, modeId, state, options = {
|
|
|
4198
4197
|
}
|
|
4199
4198
|
function detachTokenBindings(nodes, state, variableIds, options = {}) {
|
|
4200
4199
|
const only = variableIds ? new Set(variableIds) : null;
|
|
4201
|
-
const isDetached = (id) => only ? only.has(id) : !
|
|
4200
|
+
const isDetached = (id) => only ? only.has(id) : !_chunkWI7QJA7Acjs.getTokenVariable.call(void 0, state, id);
|
|
4202
4201
|
const { modesOf } = modesResolver(nodes, state, options);
|
|
4203
4202
|
let changed = false;
|
|
4204
4203
|
const out = nodes.map((node) => {
|
|
@@ -11744,7 +11743,7 @@ function createCanvasEditorDocument(options) {
|
|
|
11744
11743
|
options.setEdges(doc.edges.map((e) => ({ ...e })));
|
|
11745
11744
|
if (scenes2) scenes2.load(_nullishCoalesce(doc.scenes, () => ( [])));
|
|
11746
11745
|
};
|
|
11747
|
-
return
|
|
11746
|
+
return _chunkM4MIZPQIcjs.defineEditorDocument.call(void 0, {
|
|
11748
11747
|
kind: "canvas",
|
|
11749
11748
|
get: snapshot,
|
|
11750
11749
|
load: (document2, { history: mode }) => {
|
package/dist/canvas/index.js
CHANGED
|
@@ -60,7 +60,7 @@ import {
|
|
|
60
60
|
getTokenVariable,
|
|
61
61
|
isTokenInScope,
|
|
62
62
|
resolveToken
|
|
63
|
-
} from "../chunk-
|
|
63
|
+
} from "../chunk-SDHZG5TF.js";
|
|
64
64
|
import {
|
|
65
65
|
DEFAULT_NODE_HEIGHT,
|
|
66
66
|
DEFAULT_NODE_WIDTH,
|
|
@@ -215,8 +215,7 @@ import {
|
|
|
215
215
|
} from "../chunk-ODBT55Q7.js";
|
|
216
216
|
import {
|
|
217
217
|
defineEditorDocument
|
|
218
|
-
} from "../chunk-
|
|
219
|
-
import "../chunk-WHKNYFM2.js";
|
|
218
|
+
} from "../chunk-NHLYK3AX.js";
|
|
220
219
|
import "../chunk-HF5QZS7Z.js";
|
|
221
220
|
import {
|
|
222
221
|
ANIMATION_TIME_EPSILON,
|
package/dist/chart/index.cjs
CHANGED
|
@@ -155,8 +155,7 @@ var _chunkSWTUM32Hcjs = require('../chunk-SWTUM32H.cjs');
|
|
|
155
155
|
var _chunkALNIFK5Gcjs = require('../chunk-ALNIFK5G.cjs');
|
|
156
156
|
|
|
157
157
|
|
|
158
|
-
var
|
|
159
|
-
require('../chunk-L5OWG2NA.cjs');
|
|
158
|
+
var _chunkM4MIZPQIcjs = require('../chunk-M4MIZPQI.cjs');
|
|
160
159
|
require('../chunk-2BSBFBOA.cjs');
|
|
161
160
|
require('../chunk-FJ2MSI43.cjs');
|
|
162
161
|
require('../chunk-UKCJ43YL.cjs');
|
|
@@ -2191,7 +2190,7 @@ function createOfficeChartToolProvider(options = {}) {
|
|
|
2191
2190
|
|
|
2192
2191
|
// src/chart/editorDocument.ts
|
|
2193
2192
|
function createChartEditorDocument(controller) {
|
|
2194
|
-
return
|
|
2193
|
+
return _chunkM4MIZPQIcjs.defineEditorDocument.call(void 0, {
|
|
2195
2194
|
kind: "chart",
|
|
2196
2195
|
get: () => controller.toJSON(),
|
|
2197
2196
|
load: (document, { history }) => {
|
package/dist/chart/index.js
CHANGED
|
@@ -155,8 +155,7 @@ import {
|
|
|
155
155
|
} from "../chunk-CIQIM2IP.js";
|
|
156
156
|
import {
|
|
157
157
|
defineEditorDocument
|
|
158
|
-
} from "../chunk-
|
|
159
|
-
import "../chunk-WHKNYFM2.js";
|
|
158
|
+
} from "../chunk-NHLYK3AX.js";
|
|
160
159
|
import "../chunk-HF5QZS7Z.js";
|
|
161
160
|
import "../chunk-RNSANXPT.js";
|
|
162
161
|
import "../chunk-AA34BA7G.js";
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
var _chunk2BSBFBOAcjs = require('./chunk-2BSBFBOA.cjs');
|
|
5
|
+
|
|
6
|
+
// src/persistence/assets.ts
|
|
7
|
+
var EDITOR_ASSET_PREFIX = "pixerate-asset:";
|
|
8
|
+
var REF = /pixerate-asset:[0-9a-z]+-[0-9a-z]+(?:~[0-9]+)?/g;
|
|
9
|
+
var BASE64 = /^[A-Za-z0-9+/=\r\n]+$/;
|
|
10
|
+
function isInlineAsset(value) {
|
|
11
|
+
if (value.startsWith("data:")) return value.length >= 512;
|
|
12
|
+
return value.length >= 4096 && BASE64.test(value);
|
|
13
|
+
}
|
|
14
|
+
function hash53(text) {
|
|
15
|
+
let h1 = 3735928559;
|
|
16
|
+
let h2 = 1103547991;
|
|
17
|
+
for (let i = 0; i < text.length; i++) {
|
|
18
|
+
const c = text.charCodeAt(i);
|
|
19
|
+
h1 = Math.imul(h1 ^ c, 2654435761);
|
|
20
|
+
h2 = Math.imul(h2 ^ c, 1597334677);
|
|
21
|
+
}
|
|
22
|
+
h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507) ^ Math.imul(h2 ^ h2 >>> 13, 3266489909);
|
|
23
|
+
h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507) ^ Math.imul(h1 ^ h1 >>> 13, 3266489909);
|
|
24
|
+
return 4294967296 * (2097151 & h2) + (h1 >>> 0);
|
|
25
|
+
}
|
|
26
|
+
function createEditorAssetRegistry() {
|
|
27
|
+
const byRef = /* @__PURE__ */ new Map();
|
|
28
|
+
const byData = /* @__PURE__ */ new Map();
|
|
29
|
+
return {
|
|
30
|
+
put(data) {
|
|
31
|
+
const known = byData.get(data);
|
|
32
|
+
if (known) return known;
|
|
33
|
+
const base = `${EDITOR_ASSET_PREFIX}${data.length.toString(36)}-${hash53(data).toString(36)}`;
|
|
34
|
+
let ref = base;
|
|
35
|
+
for (let n = 1; byRef.has(ref) && byRef.get(ref) !== data; n++) ref = `${base}~${n}`;
|
|
36
|
+
byRef.set(ref, data);
|
|
37
|
+
byData.set(data, ref);
|
|
38
|
+
return ref;
|
|
39
|
+
},
|
|
40
|
+
get: (ref) => byRef.get(ref),
|
|
41
|
+
has: (ref) => byRef.has(ref),
|
|
42
|
+
set(ref, data) {
|
|
43
|
+
byRef.set(ref, data);
|
|
44
|
+
byData.set(data, ref);
|
|
45
|
+
},
|
|
46
|
+
get size() {
|
|
47
|
+
return byRef.size;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function externalizeAssets(value, registry) {
|
|
52
|
+
const walk = (v) => {
|
|
53
|
+
if (typeof v === "string") return isInlineAsset(v) ? registry.put(v) : v;
|
|
54
|
+
if (Array.isArray(v)) return v.map(walk);
|
|
55
|
+
if (v && typeof v === "object") {
|
|
56
|
+
const out = {};
|
|
57
|
+
for (const [k, x] of Object.entries(v)) out[k] = walk(x);
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
return v;
|
|
61
|
+
};
|
|
62
|
+
return walk(value);
|
|
63
|
+
}
|
|
64
|
+
function collectAssetRefs(value) {
|
|
65
|
+
const text = typeof value === "string" ? value : _nullishCoalesce(JSON.stringify(value), () => ( ""));
|
|
66
|
+
return [...new Set(_nullishCoalesce(text.match(REF), () => ( [])))];
|
|
67
|
+
}
|
|
68
|
+
function internalizeAssets(value, registry) {
|
|
69
|
+
const missing = collectAssetRefs(value).filter((ref) => !registry.has(ref));
|
|
70
|
+
if (missing.length) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
`The document refers to ${missing.length} asset${missing.length === 1 ? "" : "s"} that ${missing.length === 1 ? "is" : "are"} not loaded (${missing.slice(0, 3).join(", ")}${missing.length > 3 ? ", \u2026" : ""}). Pass a document from get_*_document in this session, or open it from storage so its assets are read first.`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
const walk = (v) => {
|
|
76
|
+
if (typeof v === "string") return v.startsWith(EDITOR_ASSET_PREFIX) && registry.has(v) ? registry.get(v) : v;
|
|
77
|
+
if (Array.isArray(v)) return v.map(walk);
|
|
78
|
+
if (v && typeof v === "object") {
|
|
79
|
+
const out = {};
|
|
80
|
+
for (const [k, x] of Object.entries(v)) out[k] = walk(x);
|
|
81
|
+
return out;
|
|
82
|
+
}
|
|
83
|
+
return v;
|
|
84
|
+
};
|
|
85
|
+
return walk(value);
|
|
86
|
+
}
|
|
87
|
+
var persisted = /* @__PURE__ */ new WeakMap();
|
|
88
|
+
var assetKey = (ref, options) => `${_nullishCoalesce(options.prefix, () => ( "pixerate.assets:"))}${ref.slice(EDITOR_ASSET_PREFIX.length)}`;
|
|
89
|
+
async function persistEditorAssets(storage, registry, document, options = {}) {
|
|
90
|
+
const written = _nullishCoalesce(persisted.get(storage), () => ( /* @__PURE__ */ new Set()));
|
|
91
|
+
persisted.set(storage, written);
|
|
92
|
+
for (const ref of collectAssetRefs(document)) {
|
|
93
|
+
const key = assetKey(ref, options);
|
|
94
|
+
if (written.has(key)) continue;
|
|
95
|
+
const data = registry.get(ref);
|
|
96
|
+
if (data === void 0) continue;
|
|
97
|
+
await storage.set(key, data);
|
|
98
|
+
written.add(key);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async function preloadEditorAssets(storage, registry, document, options = {}) {
|
|
102
|
+
const missing = [];
|
|
103
|
+
for (const ref of collectAssetRefs(document)) {
|
|
104
|
+
if (registry.has(ref)) continue;
|
|
105
|
+
const data = await storage.get(assetKey(ref, options));
|
|
106
|
+
if (data === null) missing.push(ref);
|
|
107
|
+
else registry.set(ref, data);
|
|
108
|
+
}
|
|
109
|
+
return missing;
|
|
110
|
+
}
|
|
111
|
+
function withEditorAssets(storage, registry, options = {}) {
|
|
112
|
+
return {
|
|
113
|
+
kind: storage.kind,
|
|
114
|
+
get available() {
|
|
115
|
+
return storage.available;
|
|
116
|
+
},
|
|
117
|
+
async get(key) {
|
|
118
|
+
const value = await storage.get(key);
|
|
119
|
+
if (value !== null && value.includes(EDITOR_ASSET_PREFIX)) await preloadEditorAssets(storage, registry, value, options);
|
|
120
|
+
return value;
|
|
121
|
+
},
|
|
122
|
+
async set(key, value) {
|
|
123
|
+
if (value.includes(EDITOR_ASSET_PREFIX)) await persistEditorAssets(storage, registry, value, options);
|
|
124
|
+
await storage.set(key, value);
|
|
125
|
+
},
|
|
126
|
+
remove: (key) => storage.remove(key)
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/persistence/migrate.ts
|
|
131
|
+
function hasLoadProblems(report) {
|
|
132
|
+
return report.problems.length > 0 || report.readOnly !== null;
|
|
133
|
+
}
|
|
134
|
+
function createLoadReport(partial = {}) {
|
|
135
|
+
return {
|
|
136
|
+
migratedFrom: null,
|
|
137
|
+
version: null,
|
|
138
|
+
problems: [],
|
|
139
|
+
readOnly: null,
|
|
140
|
+
unknownKeys: [],
|
|
141
|
+
...partial
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
var isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
145
|
+
var deepClone = (value) => typeof structuredClone === "function" ? structuredClone(value) : JSON.parse(JSON.stringify(value));
|
|
146
|
+
function toObject(json) {
|
|
147
|
+
let value = json;
|
|
148
|
+
if (typeof json === "string") {
|
|
149
|
+
try {
|
|
150
|
+
value = JSON.parse(json);
|
|
151
|
+
} catch (e) {
|
|
152
|
+
return void 0;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return isObject(value) ? _chunk2BSBFBOAcjs.stripPrototypeKeys.call(void 0, deepClone(value)) : void 0;
|
|
156
|
+
}
|
|
157
|
+
function migrateDocument(json, options) {
|
|
158
|
+
const versionKey = _nullishCoalesce(options.versionKey, () => ( "version"));
|
|
159
|
+
const target = options.currentVersion;
|
|
160
|
+
const original = toObject(json);
|
|
161
|
+
if (!original) {
|
|
162
|
+
return {
|
|
163
|
+
doc: { [versionKey]: target },
|
|
164
|
+
report: createLoadReport({
|
|
165
|
+
readOnly: { kind: "invalid", message: "document is not a JSON object" }
|
|
166
|
+
})
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
const raw = original[versionKey];
|
|
170
|
+
const found = typeof raw === "number" && Number.isInteger(raw) && raw >= 0 ? raw : null;
|
|
171
|
+
const from = _nullishCoalesce(_nullishCoalesce(found, () => ( options.missingVersion)), () => ( target));
|
|
172
|
+
const report = createLoadReport({ version: found });
|
|
173
|
+
if (from > target) {
|
|
174
|
+
report.readOnly = {
|
|
175
|
+
kind: "newerVersion",
|
|
176
|
+
version: from,
|
|
177
|
+
supported: target,
|
|
178
|
+
message: `document has version ${from}, newer than the supported ${target}`
|
|
179
|
+
};
|
|
180
|
+
return { doc: original, report };
|
|
181
|
+
}
|
|
182
|
+
if (from === target) {
|
|
183
|
+
original[versionKey] = target;
|
|
184
|
+
return { doc: original, report };
|
|
185
|
+
}
|
|
186
|
+
let doc = deepClone(original);
|
|
187
|
+
for (let step = from; step < target; step++) {
|
|
188
|
+
const fn = _optionalChain([options, 'access', _ => _.steps, 'optionalAccess', _2 => _2[step]]);
|
|
189
|
+
if (!fn) {
|
|
190
|
+
report.readOnly = {
|
|
191
|
+
kind: "migrationFailed",
|
|
192
|
+
from: step,
|
|
193
|
+
message: `no migration step from version ${step}`
|
|
194
|
+
};
|
|
195
|
+
return { doc: original, report };
|
|
196
|
+
}
|
|
197
|
+
try {
|
|
198
|
+
doc = _nullishCoalesce(fn(doc), () => ( doc));
|
|
199
|
+
} catch (error) {
|
|
200
|
+
report.readOnly = {
|
|
201
|
+
kind: "migrationFailed",
|
|
202
|
+
from: step,
|
|
203
|
+
message: `migration from version ${step} failed: ${error instanceof Error ? error.message : String(error)}`
|
|
204
|
+
};
|
|
205
|
+
return { doc: original, report };
|
|
206
|
+
}
|
|
207
|
+
doc[versionKey] = step + 1;
|
|
208
|
+
}
|
|
209
|
+
report.migratedFrom = from;
|
|
210
|
+
return { doc, report };
|
|
211
|
+
}
|
|
212
|
+
function loadSections(doc, sections, options = {}) {
|
|
213
|
+
const source = isObject(doc) ? doc : {};
|
|
214
|
+
const ignore = new Set(_nullishCoalesce(options.ignore, () => ( ["version"])));
|
|
215
|
+
const value = {};
|
|
216
|
+
const problems = [];
|
|
217
|
+
for (const key of Object.keys(sections)) {
|
|
218
|
+
const spec = sections[key];
|
|
219
|
+
const fallback = () => typeof spec.defaults === "function" ? spec.defaults() : spec.defaults;
|
|
220
|
+
if (!Object.prototype.hasOwnProperty.call(source, key)) {
|
|
221
|
+
value[key] = fallback();
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
try {
|
|
225
|
+
const parsed = spec.parse(source[key]);
|
|
226
|
+
if (parsed === void 0) throw new Error("invalid value");
|
|
227
|
+
value[key] = parsed;
|
|
228
|
+
} catch (error) {
|
|
229
|
+
problems.push({
|
|
230
|
+
section: key,
|
|
231
|
+
message: error instanceof Error ? error.message : String(error)
|
|
232
|
+
});
|
|
233
|
+
value[key] = fallback();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
const unknown = {};
|
|
237
|
+
for (const key of Object.keys(source)) {
|
|
238
|
+
if (!(key in sections) && !ignore.has(key) && !_chunk2BSBFBOAcjs.isUnsafeJsonKey.call(void 0, key)) unknown[key] = source[key];
|
|
239
|
+
}
|
|
240
|
+
return { value, problems, unknown };
|
|
241
|
+
}
|
|
242
|
+
function loadDocument(json, sections, options) {
|
|
243
|
+
const { doc, report } = migrateDocument(json, options);
|
|
244
|
+
const ignore = _nullishCoalesce(options.ignore, () => ( [_nullishCoalesce(options.versionKey, () => ( "version"))]));
|
|
245
|
+
const result = loadSections(_optionalChain([report, 'access', _3 => _3.readOnly, 'optionalAccess', _4 => _4.kind]) === "invalid" ? {} : doc, sections, {
|
|
246
|
+
ignore
|
|
247
|
+
});
|
|
248
|
+
report.problems = result.problems;
|
|
249
|
+
report.unknownKeys = Object.keys(result.unknown);
|
|
250
|
+
return { ...result, report };
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// src/persistence/editorDocument.ts
|
|
254
|
+
var EditorDocumentLoadError = class extends Error {
|
|
255
|
+
/** The `LoadReport` when the input was a file that could not be migrated. */
|
|
256
|
+
|
|
257
|
+
constructor(message, report) {
|
|
258
|
+
super(message);
|
|
259
|
+
this.name = "EditorDocumentLoadError";
|
|
260
|
+
this.report = report;
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
var EDITOR_DOCUMENT_FORMAT = "pixerate.editor-document";
|
|
264
|
+
var KIND = /^[a-z][a-z0-9_]*$/;
|
|
265
|
+
function isEditorDocumentFile(value) {
|
|
266
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
267
|
+
const v = value;
|
|
268
|
+
return v.format === EDITOR_DOCUMENT_FORMAT && typeof v.kind === "string" && typeof v.formatVersion === "number" && "document" in v;
|
|
269
|
+
}
|
|
270
|
+
function toEditorDocumentFile(doc, name) {
|
|
271
|
+
return {
|
|
272
|
+
format: EDITOR_DOCUMENT_FORMAT,
|
|
273
|
+
kind: doc.kind,
|
|
274
|
+
formatVersion: doc.formatVersion,
|
|
275
|
+
...name ? { name } : {},
|
|
276
|
+
document: doc.getDocument()
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
function serializeEditorDocument(doc, options = {}) {
|
|
280
|
+
return JSON.stringify(toEditorDocumentFile(doc, options.name), null, options.space);
|
|
281
|
+
}
|
|
282
|
+
function parseEditorDocument(text, options = {}) {
|
|
283
|
+
let value;
|
|
284
|
+
try {
|
|
285
|
+
value = _chunk2BSBFBOAcjs.stripPrototypeKeys.call(void 0, JSON.parse(text));
|
|
286
|
+
} catch (error) {
|
|
287
|
+
throw new EditorDocumentLoadError(`The file is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
288
|
+
}
|
|
289
|
+
if (!isEditorDocumentFile(value)) {
|
|
290
|
+
throw new EditorDocumentLoadError(`The file is not a saved editor document (expected "format": "${EDITOR_DOCUMENT_FORMAT}").`);
|
|
291
|
+
}
|
|
292
|
+
if (options.kind && value.kind !== options.kind) {
|
|
293
|
+
throw new EditorDocumentLoadError(`The file is a ${value.kind} document, not a ${options.kind} document.`);
|
|
294
|
+
}
|
|
295
|
+
return value;
|
|
296
|
+
}
|
|
297
|
+
function defineEditorDocument(spec) {
|
|
298
|
+
if (!KIND.test(spec.kind)) throw new Error(`Editor document kind "${spec.kind}" must match ${KIND}.`);
|
|
299
|
+
const formatVersion = _nullishCoalesce(spec.formatVersion, () => ( 1));
|
|
300
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
301
|
+
let revision = 0;
|
|
302
|
+
let unsubscribe = null;
|
|
303
|
+
let connected = false;
|
|
304
|
+
const connect = () => {
|
|
305
|
+
if (unsubscribe) return;
|
|
306
|
+
if (connected) revision++;
|
|
307
|
+
connected = true;
|
|
308
|
+
unsubscribe = spec.subscribe(() => {
|
|
309
|
+
revision++;
|
|
310
|
+
listeners.forEach((listener) => {
|
|
311
|
+
try {
|
|
312
|
+
listener();
|
|
313
|
+
} catch (error) {
|
|
314
|
+
console.error(`[${spec.kind} document] Error in change listener:`, error);
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
};
|
|
319
|
+
connect();
|
|
320
|
+
const unwrap = (input) => {
|
|
321
|
+
if (!isEditorDocumentFile(input)) return { document: input, report: createLoadReport({ version: formatVersion }) };
|
|
322
|
+
if (input.kind !== spec.kind) throw new EditorDocumentLoadError(`This is a ${input.kind} document; it cannot be opened in the ${spec.kind} editor.`);
|
|
323
|
+
const steps = Object.fromEntries(
|
|
324
|
+
Object.entries(_nullishCoalesce(spec.migrations, () => ( {}))).map(([v, step]) => [v, (w) => ({ ...w, document: step(w.document) })])
|
|
325
|
+
);
|
|
326
|
+
const { doc, report } = migrateDocument(
|
|
327
|
+
{ formatVersion: input.formatVersion, document: input.document },
|
|
328
|
+
{ currentVersion: formatVersion, versionKey: "formatVersion", steps }
|
|
329
|
+
);
|
|
330
|
+
if (report.readOnly) throw new EditorDocumentLoadError(`Cannot open the ${spec.kind} document: ${report.readOnly.message}.`, report);
|
|
331
|
+
return { document: doc.document, report };
|
|
332
|
+
};
|
|
333
|
+
return {
|
|
334
|
+
kind: spec.kind,
|
|
335
|
+
formatVersion,
|
|
336
|
+
recordsLoads: spec.recordsLoads !== false,
|
|
337
|
+
getDocument: () => spec.assets ? externalizeAssets(spec.get(), spec.assets) : spec.get(),
|
|
338
|
+
loadDocument(input, options = {}) {
|
|
339
|
+
const { document, report } = unwrap(input);
|
|
340
|
+
if (document === void 0 || document === null) throw new EditorDocumentLoadError(`No ${spec.kind} document was given.`);
|
|
341
|
+
try {
|
|
342
|
+
const result = spec.load(spec.assets ? internalizeAssets(document, spec.assets) : document, { history: _nullishCoalesce(options.history, () => ( "reset")) });
|
|
343
|
+
if (_optionalChain([result, 'optionalAccess', _5 => _5.problems, 'optionalAccess', _6 => _6.length])) report.problems.push(...result.problems);
|
|
344
|
+
} catch (error) {
|
|
345
|
+
if (error instanceof EditorDocumentLoadError) throw error;
|
|
346
|
+
throw new EditorDocumentLoadError(error instanceof Error ? error.message : String(error));
|
|
347
|
+
}
|
|
348
|
+
return report;
|
|
349
|
+
},
|
|
350
|
+
revision: () => {
|
|
351
|
+
connect();
|
|
352
|
+
return revision;
|
|
353
|
+
},
|
|
354
|
+
subscribe(listener) {
|
|
355
|
+
connect();
|
|
356
|
+
listeners.add(listener);
|
|
357
|
+
return () => {
|
|
358
|
+
listeners.delete(listener);
|
|
359
|
+
};
|
|
360
|
+
},
|
|
361
|
+
history: spec.history,
|
|
362
|
+
...spec.assets ? { assets: spec.assets } : {},
|
|
363
|
+
readOnly: () => _nullishCoalesce(_optionalChain([spec, 'access', _7 => _7.readOnly, 'optionalCall', _8 => _8()]), () => ( false)),
|
|
364
|
+
destroy() {
|
|
365
|
+
_optionalChain([unsubscribe, 'optionalCall', _9 => _9()]);
|
|
366
|
+
unsubscribe = null;
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
exports.EDITOR_ASSET_PREFIX = EDITOR_ASSET_PREFIX; exports.isInlineAsset = isInlineAsset; exports.createEditorAssetRegistry = createEditorAssetRegistry; exports.externalizeAssets = externalizeAssets; exports.collectAssetRefs = collectAssetRefs; exports.internalizeAssets = internalizeAssets; exports.persistEditorAssets = persistEditorAssets; exports.preloadEditorAssets = preloadEditorAssets; exports.withEditorAssets = withEditorAssets; exports.hasLoadProblems = hasLoadProblems; exports.createLoadReport = createLoadReport; exports.migrateDocument = migrateDocument; exports.loadSections = loadSections; exports.loadDocument = loadDocument; exports.EditorDocumentLoadError = EditorDocumentLoadError; exports.EDITOR_DOCUMENT_FORMAT = EDITOR_DOCUMENT_FORMAT; exports.isEditorDocumentFile = isEditorDocumentFile; exports.toEditorDocumentFile = toEditorDocumentFile; exports.serializeEditorDocument = serializeEditorDocument; exports.parseEditorDocument = parseEditorDocument; exports.defineEditorDocument = defineEditorDocument;
|