doxum 0.1.6 → 0.1.7
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 +38 -13
- package/dist/{contract-I99DUMbN.d.ts → contract-DNZ4D53r.d.ts} +87 -76
- package/dist/{contract-uYJTmT8o.d.cts → contract-j3SLGAwh.d.cts} +87 -76
- package/dist/index.cjs +221 -349
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +209 -327
- package/dist/index.js.map +1 -1
- package/dist/{integration-xupBIKjU.js → integration-B56u1l9V.js} +2 -2
- package/dist/integration-B56u1l9V.js.map +1 -0
- package/dist/{integration-Bs3pOk65.cjs → integration-CZwCwFBS.cjs} +2 -2
- package/dist/integration-CZwCwFBS.cjs.map +1 -0
- package/dist/integration.cjs +10 -2
- package/dist/integration.d.cts +3 -3
- package/dist/integration.d.ts +3 -3
- package/dist/integration.js +3 -3
- package/dist/local-sync.cjs +56 -17
- package/dist/local-sync.cjs.map +1 -1
- package/dist/local-sync.d.cts +2 -2
- package/dist/local-sync.d.ts +2 -2
- package/dist/local-sync.js +56 -17
- package/dist/local-sync.js.map +1 -1
- package/dist/react.cjs +27 -19
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +27 -19
- package/dist/react.js.map +1 -1
- package/dist/{runtime-CRijXjYp.cjs → runtime-0mOFbe_H.cjs} +899 -451
- package/dist/runtime-0mOFbe_H.cjs.map +1 -0
- package/dist/{runtime-CUcvhFNP.d.ts → runtime-B22tuj9A.d.cts} +18 -20
- package/dist/{runtime-C_vKHmhy.d.cts → runtime-BFmhzPpZ.d.ts} +18 -20
- package/dist/{runtime-BJRXF0gq.js → runtime-DF1q9Gje.js} +823 -429
- package/dist/runtime-DF1q9Gje.js.map +1 -0
- package/package.json +1 -1
- package/skills/doxum-runtime/SKILL.md +2 -1
- package/skills/doxum-runtime/references/guide.en.md +18 -18
- package/skills/doxum-runtime/references/guide.zh-CN.md +12 -17
- package/skills/doxum-runtime/references/invariants.en.md +1 -1
- package/skills/doxum-runtime/references/invariants.zh-CN.md +1 -1
- package/skills/doxum-runtime/references/patterns.en.md +9 -20
- package/skills/doxum-runtime/references/patterns.zh-CN.md +5 -18
- package/dist/integration-Bs3pOk65.cjs.map +0 -1
- package/dist/integration-xupBIKjU.js.map +0 -1
- package/dist/runtime-BJRXF0gq.js.map +0 -1
- package/dist/runtime-CRijXjYp.cjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as
|
|
1
|
+
import { A as id, B as set$1, C as restore, D as DocumentReentrancyError, E as DocumentDisposedError, F as locate, G as object, H as field, I as overlaps, J as table, K as optional, L as read, N as contains$1, O as address$1, P as debugKey, R as resolveAddress, S as keys, T as validPositions, U as list, V as dict, W as map, X as variant, Y as tree, a as bindDocumentReadable, b as at$1, c as notify, d as subscribeTargets, f as accessOf, h as commandFootprint, i as ProjectionError, j as impact_target_exports, k as belongs, l as shareNotification, m as readWith, o as createNotification, p as bindRuntimeAccess, q as schema, r as ProjectionDisposedError, s as disposeNotification, t as createProjectionRuntime, u as subscribeRoot, v as documentReader, w as valid, x as index, y as afterRemove, z as resolveLocated } from "./runtime-DF1q9Gje.js";
|
|
2
2
|
import { a as isStablePayload, c as snapshotPayload, i as isRecord, l as transferPayload, n as deepEqual, o as ownPayload, r as isPlainObject, s as sameStructuralValue, t as cloneValue, u as profile } from "./ownership-CduRygE7.js";
|
|
3
3
|
import { n as bindRuntimeDriver, r as disposeRuntimeDriver, t as assertRuntimeWritable } from "./driver-CbzfW5MR.js";
|
|
4
4
|
//#region core/src/impact.ts
|
|
@@ -38,9 +38,9 @@ const createImpact = (input) => {
|
|
|
38
38
|
profile.impact.affects();
|
|
39
39
|
if (kind === "reset") return true;
|
|
40
40
|
if (!belongs(value, input.schema)) return false;
|
|
41
|
-
if (pathsAffect(address$
|
|
41
|
+
if (pathsAffect(address$1(value))) return true;
|
|
42
42
|
if (value.kind === "collection") {
|
|
43
|
-
const collection = findCollection(address$
|
|
43
|
+
const collection = findCollection(address$1(value));
|
|
44
44
|
if (!collection) return false;
|
|
45
45
|
const id$1 = id(value);
|
|
46
46
|
if (id$1 !== void 0) return collection.added.has(id$1) || collection.removed.has(id$1) || collection.updated.has(id$1);
|
|
@@ -54,7 +54,7 @@ const createImpact = (input) => {
|
|
|
54
54
|
const cached = collectionCache?.find((entry) => entry.address.length === selector.address.length && entry.address.every((segment, index) => segment === selector.address[index]))?.value;
|
|
55
55
|
if (cached) return cached;
|
|
56
56
|
const exact = findCollection(selector.address);
|
|
57
|
-
if (somePath(selector.address, (changed) => contains(changed, selector.address) && changed.length < selector.address.length)) {
|
|
57
|
+
if (somePath(selector.address, (changed) => contains$1(changed, selector.address) && changed.length < selector.address.length)) {
|
|
58
58
|
const reset = { kind: "reset" };
|
|
59
59
|
(collectionCache ??= []).push({
|
|
60
60
|
address: selector.address,
|
|
@@ -88,78 +88,170 @@ const createImpact = (input) => {
|
|
|
88
88
|
//#endregion
|
|
89
89
|
//#region core/src/history.ts
|
|
90
90
|
const createHistory = (input) => {
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
let undos = [];
|
|
92
|
+
let redos = [];
|
|
93
93
|
const listeners = /* @__PURE__ */ new Set();
|
|
94
94
|
let state = Object.freeze({
|
|
95
95
|
undoDepth: 0,
|
|
96
96
|
redoDepth: 0
|
|
97
97
|
});
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
let revision = 0;
|
|
99
|
+
let pending = false;
|
|
100
|
+
let disposed = false;
|
|
101
|
+
let group;
|
|
102
|
+
const unchanged = () => ({
|
|
103
|
+
status: "unchanged",
|
|
104
|
+
revision: input.revision()
|
|
105
|
+
});
|
|
106
|
+
const publish = () => {
|
|
107
|
+
if (state.undoDepth === undos.length && state.redoDepth === redos.length) return;
|
|
108
|
+
state = Object.freeze({
|
|
100
109
|
undoDepth: undos.length,
|
|
101
110
|
redoDepth: redos.length
|
|
102
111
|
});
|
|
103
|
-
|
|
112
|
+
revision++;
|
|
113
|
+
pending = true;
|
|
104
114
|
};
|
|
105
|
-
const
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
|
|
115
|
+
const flush = () => {
|
|
116
|
+
if (!pending) return [];
|
|
117
|
+
pending = false;
|
|
118
|
+
const errors = [];
|
|
119
|
+
for (const listener of [...listeners]) {
|
|
120
|
+
if (!listeners.has(listener)) continue;
|
|
121
|
+
try {
|
|
122
|
+
listener();
|
|
123
|
+
} catch (error) {
|
|
124
|
+
errors.push({
|
|
125
|
+
phase: "listener",
|
|
126
|
+
error
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return errors;
|
|
109
131
|
};
|
|
110
132
|
const clear = () => {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
133
|
+
group = void 0;
|
|
134
|
+
undos.length = redos.length = 0;
|
|
135
|
+
publish();
|
|
136
|
+
};
|
|
137
|
+
const travel = (direction) => {
|
|
138
|
+
input.assertIdle();
|
|
139
|
+
const from = direction === "redo" ? redos : undos;
|
|
140
|
+
const to = direction === "redo" ? undos : redos;
|
|
141
|
+
const previousUndos = undos;
|
|
142
|
+
const previousRedos = redos;
|
|
143
|
+
const entry = direction === "cancel" ? from.at(-1) : from.pop();
|
|
144
|
+
if (!entry) return unchanged();
|
|
145
|
+
if (direction === "cancel") {
|
|
146
|
+
if (!group || group.entry !== entry) throw new Error("History group no longer owns its entry.");
|
|
147
|
+
undos = group.undos;
|
|
148
|
+
redos = group.redos;
|
|
149
|
+
} else to.push(entry);
|
|
150
|
+
let committed = false;
|
|
151
|
+
try {
|
|
152
|
+
const operations = direction === "redo" ? entry.batches.flatMap((batch) => batch.operations) : entry.batches.slice().reverse().flatMap((batch) => batch.inverse);
|
|
153
|
+
const result = input.apply(operations);
|
|
154
|
+
committed = result.status !== "rejected";
|
|
155
|
+
if (committed && direction === "cancel") group = void 0;
|
|
156
|
+
if (result.status === "unchanged") {
|
|
157
|
+
publish();
|
|
158
|
+
const errors = input.notify(flush);
|
|
159
|
+
if (errors.length) throw new AggregateError(errors.map((entry) => entry.error), "History listeners failed.");
|
|
160
|
+
}
|
|
161
|
+
return result;
|
|
162
|
+
} finally {
|
|
163
|
+
if (!committed) if (direction === "cancel") {
|
|
164
|
+
undos = previousUndos;
|
|
165
|
+
redos = previousRedos;
|
|
166
|
+
} else {
|
|
167
|
+
to.pop();
|
|
168
|
+
from.push(entry);
|
|
169
|
+
}
|
|
115
170
|
}
|
|
116
171
|
};
|
|
117
172
|
return {
|
|
118
173
|
api: {
|
|
119
|
-
current,
|
|
174
|
+
current: () => state,
|
|
175
|
+
revision: () => revision,
|
|
120
176
|
subscribe: (listener) => {
|
|
177
|
+
if (disposed) throw new DocumentDisposedError();
|
|
121
178
|
listeners.add(listener);
|
|
122
|
-
return () =>
|
|
179
|
+
return () => {
|
|
180
|
+
listeners.delete(listener);
|
|
181
|
+
};
|
|
123
182
|
},
|
|
124
183
|
undo: () => {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
revision: input.revision()
|
|
129
|
-
};
|
|
130
|
-
const result = input.apply(entry.inverse);
|
|
131
|
-
if (result.status === "committed") {
|
|
132
|
-
redos.push(entry);
|
|
133
|
-
emit();
|
|
134
|
-
} else undos.push(entry);
|
|
135
|
-
return result;
|
|
184
|
+
input.assertIdle();
|
|
185
|
+
group = void 0;
|
|
186
|
+
return travel("undo");
|
|
136
187
|
},
|
|
137
188
|
redo: () => {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
revision: input.revision()
|
|
142
|
-
};
|
|
143
|
-
const result = input.apply(entry.operations);
|
|
144
|
-
if (result.status === "committed") {
|
|
145
|
-
undos.push(entry);
|
|
146
|
-
emit();
|
|
147
|
-
} else redos.push(entry);
|
|
148
|
-
return result;
|
|
189
|
+
input.assertIdle();
|
|
190
|
+
group = void 0;
|
|
191
|
+
return travel("redo");
|
|
149
192
|
},
|
|
150
|
-
clear
|
|
193
|
+
clear: () => {
|
|
194
|
+
input.assertIdle();
|
|
195
|
+
clear();
|
|
196
|
+
const errors = input.notify(flush);
|
|
197
|
+
if (errors.length) throw new AggregateError(errors.map((entry) => entry.error), "History listeners failed.");
|
|
198
|
+
},
|
|
199
|
+
group: () => {
|
|
200
|
+
input.assertIdle();
|
|
201
|
+
if (group) throw new Error("A history group is already active.");
|
|
202
|
+
if (input.capacity <= 0) throw new Error("History is disabled.");
|
|
203
|
+
const scope = {
|
|
204
|
+
undos: undos.slice(),
|
|
205
|
+
redos: redos.slice()
|
|
206
|
+
};
|
|
207
|
+
group = scope;
|
|
208
|
+
return Object.freeze({
|
|
209
|
+
end: () => {
|
|
210
|
+
input.assertIdle();
|
|
211
|
+
if (group === scope) group = void 0;
|
|
212
|
+
},
|
|
213
|
+
cancel: () => {
|
|
214
|
+
input.assertIdle();
|
|
215
|
+
if (group !== scope) return unchanged();
|
|
216
|
+
if (!scope.entry) {
|
|
217
|
+
group = void 0;
|
|
218
|
+
return unchanged();
|
|
219
|
+
}
|
|
220
|
+
const result = travel("cancel");
|
|
221
|
+
if (result.status !== "rejected") group = void 0;
|
|
222
|
+
return result;
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
}
|
|
151
226
|
},
|
|
152
227
|
record: (operations, inverse) => {
|
|
153
228
|
if (input.capacity <= 0) return;
|
|
154
|
-
|
|
229
|
+
const batch = {
|
|
155
230
|
operations,
|
|
156
231
|
inverse
|
|
157
|
-
}
|
|
158
|
-
if (
|
|
232
|
+
};
|
|
233
|
+
if (group?.entry) group.entry.batches.push(batch);
|
|
234
|
+
else {
|
|
235
|
+
const entry = { batches: [batch] };
|
|
236
|
+
undos.push(entry);
|
|
237
|
+
if (group) group.entry = entry;
|
|
238
|
+
if (undos.length > input.capacity) undos.shift();
|
|
239
|
+
}
|
|
159
240
|
redos.length = 0;
|
|
160
|
-
|
|
241
|
+
publish();
|
|
242
|
+
},
|
|
243
|
+
publish,
|
|
244
|
+
flush,
|
|
245
|
+
endGroup: () => {
|
|
246
|
+
group = void 0;
|
|
161
247
|
},
|
|
162
|
-
invalidate: clear
|
|
248
|
+
invalidate: clear,
|
|
249
|
+
dispose: () => {
|
|
250
|
+
disposed = true;
|
|
251
|
+
listeners.clear();
|
|
252
|
+
clear();
|
|
253
|
+
pending = false;
|
|
254
|
+
}
|
|
163
255
|
};
|
|
164
256
|
};
|
|
165
257
|
//#endregion
|
|
@@ -179,7 +271,7 @@ const writerFor = (node, inputAddress, sink) => {
|
|
|
179
271
|
at: address
|
|
180
272
|
}) : void 0
|
|
181
273
|
};
|
|
182
|
-
if (node.kind === "dict"
|
|
274
|
+
if (node.kind === "dict") return {
|
|
183
275
|
set: (key, value) => emit(sink, {
|
|
184
276
|
type: "dict.set",
|
|
185
277
|
at: address,
|
|
@@ -232,20 +324,20 @@ const writerFor = (node, inputAddress, sink) => {
|
|
|
232
324
|
}) } : {}
|
|
233
325
|
};
|
|
234
326
|
if (node.kind === "tree") return {
|
|
235
|
-
insert: (treeNodeId, value,
|
|
327
|
+
insert: (treeNodeId, value, position) => emit(sink, {
|
|
236
328
|
type: "tree.insert",
|
|
237
329
|
at: address,
|
|
238
330
|
treeNodeId,
|
|
239
331
|
value,
|
|
240
|
-
parentId,
|
|
241
|
-
index
|
|
332
|
+
parentId: position?.parentId,
|
|
333
|
+
index: position?.index
|
|
242
334
|
}),
|
|
243
|
-
move: (treeNodeId,
|
|
335
|
+
move: (treeNodeId, position) => emit(sink, {
|
|
244
336
|
type: "tree.move",
|
|
245
337
|
at: address,
|
|
246
338
|
treeNodeId,
|
|
247
|
-
parentId,
|
|
248
|
-
index
|
|
339
|
+
parentId: position?.parentId,
|
|
340
|
+
index: position?.index
|
|
249
341
|
}),
|
|
250
342
|
remove: (treeNodeId) => emit(sink, {
|
|
251
343
|
type: "tree.remove",
|
|
@@ -329,7 +421,6 @@ const writerFor = (node, inputAddress, sink) => {
|
|
|
329
421
|
})
|
|
330
422
|
};
|
|
331
423
|
}
|
|
332
|
-
if (node.kind === "single") return writerFor(node.value, address, sink);
|
|
333
424
|
if (node.kind === "variant") return {
|
|
334
425
|
replace: (value) => emit(sink, {
|
|
335
426
|
type: "variant.replace",
|
|
@@ -355,69 +446,15 @@ const documentWriter = (schema, sink) => writerFor(schemaRoot(schema), [], sink)
|
|
|
355
446
|
//#endregion
|
|
356
447
|
//#region core/src/mutation/issue.ts
|
|
357
448
|
const ownAddress$1 = (address) => Object.freeze(address.slice());
|
|
358
|
-
const at
|
|
449
|
+
const at = (address, code, message, operation) => Object.freeze({
|
|
359
450
|
source: "mutation",
|
|
360
451
|
code,
|
|
361
452
|
address: ownAddress$1(address),
|
|
362
453
|
message,
|
|
363
454
|
...operation === void 0 ? {} : { operation }
|
|
364
455
|
});
|
|
365
|
-
const from = (operation, code, message) => at
|
|
366
|
-
const input = (code, message) => at
|
|
367
|
-
//#endregion
|
|
368
|
-
//#region core/src/mutation/anchor.ts
|
|
369
|
-
const length = (keys) => keys.length;
|
|
370
|
-
const keyAt = (keys, index) => Array.isArray(keys) ? keys[index] : keys.at(index);
|
|
371
|
-
const keyIndex = (keys, key) => Array.isArray(keys) ? keys.indexOf(key) : keys.index(key);
|
|
372
|
-
const keys = (values, keyOf) => ({
|
|
373
|
-
length: values.length,
|
|
374
|
-
at: (index) => index >= 0 && index < values.length ? keyOf(values[index]) : void 0,
|
|
375
|
-
index: (key) => {
|
|
376
|
-
for (let index = 0; index < values.length; index += 1) if (keyOf(values[index]) === key) return index;
|
|
377
|
-
return -1;
|
|
378
|
-
}
|
|
379
|
-
});
|
|
380
|
-
const index = (keys, anchor) => {
|
|
381
|
-
if (!anchor) return length(keys);
|
|
382
|
-
if ("at" in anchor) return anchor.at === "start" ? 0 : length(keys);
|
|
383
|
-
if ("before" in anchor) return keyIndex(keys, anchor.before);
|
|
384
|
-
return keyIndex(keys, anchor.after) + 1;
|
|
385
|
-
};
|
|
386
|
-
const at = (keys, position) => position <= 0 ? { at: "start" } : { after: keyAt(keys, position - 1) };
|
|
387
|
-
const valid = (keys, anchor) => {
|
|
388
|
-
if (!anchor) return true;
|
|
389
|
-
if (typeof anchor !== "object" || anchor === null) return false;
|
|
390
|
-
if (Number("at" in anchor) + Number("before" in anchor) + Number("after" in anchor) !== 1) return false;
|
|
391
|
-
if ("at" in anchor) return anchor.at === "start" || anchor.at === "end";
|
|
392
|
-
return keyIndex(keys, "before" in anchor ? anchor.before : anchor.after) >= 0;
|
|
393
|
-
};
|
|
394
|
-
const afterRemove = (keys, removedIndex, anchor) => {
|
|
395
|
-
const position = index(keys, anchor);
|
|
396
|
-
return position > removedIndex ? position - 1 : position;
|
|
397
|
-
};
|
|
398
|
-
const validPositions = (length, positions) => {
|
|
399
|
-
let previous = -1;
|
|
400
|
-
for (let index = 0; index < positions.length; index += 1) {
|
|
401
|
-
const position = positions[index];
|
|
402
|
-
if (!Number.isInteger(position) || position < 0 || position <= previous || position > length + index) return false;
|
|
403
|
-
previous = position;
|
|
404
|
-
}
|
|
405
|
-
return true;
|
|
406
|
-
};
|
|
407
|
-
const restore = (keys, inserted, positions) => {
|
|
408
|
-
const currentLength = keys.length;
|
|
409
|
-
if (inserted.length !== positions.length || !validPositions(currentLength, positions)) throw new Error("Ordered restore positions are invalid.");
|
|
410
|
-
let readIndex = currentLength - 1;
|
|
411
|
-
let insertedIndex = inserted.length - 1;
|
|
412
|
-
keys.length = currentLength + inserted.length;
|
|
413
|
-
for (let writeIndex = keys.length - 1; writeIndex >= 0; writeIndex -= 1) if (insertedIndex >= 0 && positions[insertedIndex] === writeIndex) {
|
|
414
|
-
keys[writeIndex] = inserted[insertedIndex];
|
|
415
|
-
insertedIndex -= 1;
|
|
416
|
-
} else {
|
|
417
|
-
keys[writeIndex] = keys[readIndex];
|
|
418
|
-
readIndex -= 1;
|
|
419
|
-
}
|
|
420
|
-
};
|
|
456
|
+
const from = (operation, code, message) => at(operation.at, code, message, operation.type);
|
|
457
|
+
const input = (code, message) => at([], code, message);
|
|
421
458
|
//#endregion
|
|
422
459
|
//#region core/src/mutation/execute-entity.ts
|
|
423
460
|
const resolveEntityCollection = (node, value) => {
|
|
@@ -542,7 +579,7 @@ const executeEntity = (target, operation, copyPayload) => {
|
|
|
542
579
|
type: "entity.move",
|
|
543
580
|
at: operation.at,
|
|
544
581
|
id: operation.id,
|
|
545
|
-
anchor: at(ids, position)
|
|
582
|
+
anchor: at$1(ids, position)
|
|
546
583
|
};
|
|
547
584
|
ids.splice(position, 1);
|
|
548
585
|
ids.splice(nextIndex, 0, operation.id);
|
|
@@ -617,7 +654,7 @@ const executeList = (target, operation, copyPayload) => {
|
|
|
617
654
|
at: operation.at,
|
|
618
655
|
key: operation.key,
|
|
619
656
|
value: cloneValue(list[position], "inverse"),
|
|
620
|
-
anchor: at(orderedKeys, position)
|
|
657
|
+
anchor: at$1(orderedKeys, position)
|
|
621
658
|
};
|
|
622
659
|
list.splice(position, 1);
|
|
623
660
|
return {
|
|
@@ -633,7 +670,7 @@ const executeList = (target, operation, copyPayload) => {
|
|
|
633
670
|
type: "list.move",
|
|
634
671
|
at: operation.at,
|
|
635
672
|
key: operation.key,
|
|
636
|
-
anchor: at(orderedKeys, position)
|
|
673
|
+
anchor: at$1(orderedKeys, position)
|
|
637
674
|
};
|
|
638
675
|
const [entry] = list.splice(position, 1);
|
|
639
676
|
list.splice(nextIndex, 0, entry);
|
|
@@ -816,7 +853,7 @@ const changeChanged = (change, value) => {
|
|
|
816
853
|
return false;
|
|
817
854
|
};
|
|
818
855
|
const is = (value) => isRecord(value) && isRecord(value.nodes);
|
|
819
|
-
const contains
|
|
856
|
+
const contains = (tree, id) => has$1(tree.nodes, id);
|
|
820
857
|
const validate = (value) => {
|
|
821
858
|
if (!is(value)) return false;
|
|
822
859
|
const ids = Object.keys(value.nodes);
|
|
@@ -858,7 +895,6 @@ const documentTreeError = (node, value, address) => {
|
|
|
858
895
|
}
|
|
859
896
|
return;
|
|
860
897
|
}
|
|
861
|
-
if (node.kind === "single") return documentTreeError(node.value, value, address);
|
|
862
898
|
if (node.kind === "variant") {
|
|
863
899
|
if (!isRecord(value) || typeof value[node.tag] !== "string") return void 0;
|
|
864
900
|
const variant = node.variants[value[node.tag]];
|
|
@@ -897,7 +933,7 @@ const replace = (current, operation) => {
|
|
|
897
933
|
};
|
|
898
934
|
};
|
|
899
935
|
const insert = (tree, operation, value) => {
|
|
900
|
-
if (contains
|
|
936
|
+
if (contains(tree, operation.treeNodeId)) return rejected$2("duplicate-tree-node", `Tree node '${operation.treeNodeId}' already exists.`);
|
|
901
937
|
if (!validIndex(operation.index)) return rejected$2("invalid-tree-index", "Tree index is invalid.");
|
|
902
938
|
if (tree.rootId === void 0) {
|
|
903
939
|
if (operation.parentId !== void 0) return rejected$2("missing-tree-parent", `Tree parent '${operation.parentId}' does not exist.`);
|
|
@@ -1022,9 +1058,8 @@ const move = (tree, operation) => {
|
|
|
1022
1058
|
if (!currentParent || parentId === void 0) return rejected$2("invalid-tree", "Tree parent links are inconsistent.");
|
|
1023
1059
|
const originalIndex = childIndex(currentParent, operation.treeNodeId);
|
|
1024
1060
|
if (originalIndex < 0) return rejected$2("invalid-tree", "Tree parent links are inconsistent.");
|
|
1025
|
-
let nextIndex = Math.min(operation.index ?? nextParent.children.length, nextParent.children.length);
|
|
1026
1061
|
currentParent.children.splice(originalIndex, 1);
|
|
1027
|
-
|
|
1062
|
+
const nextIndex = Math.min(operation.index ?? nextParent.children.length, nextParent.children.length);
|
|
1028
1063
|
if (parentId === operation.parentId && nextIndex === originalIndex) {
|
|
1029
1064
|
currentParent.children.splice(originalIndex, 0, operation.treeNodeId);
|
|
1030
1065
|
return { status: "unchanged" };
|
|
@@ -1128,6 +1163,16 @@ const executeValue = (target, operation, copyPayload) => {
|
|
|
1128
1163
|
}
|
|
1129
1164
|
if (operation.type === "variant.replace") {
|
|
1130
1165
|
if (sameStructuralValue(target.value, operation.value)) return { status: "unchanged" };
|
|
1166
|
+
if (target.value === void 0 && target.node.optional) {
|
|
1167
|
+
target.parent[target.key] = own(operation.value);
|
|
1168
|
+
return {
|
|
1169
|
+
status: "changed",
|
|
1170
|
+
inverse: [{
|
|
1171
|
+
type: "value.clear",
|
|
1172
|
+
at: operation.at
|
|
1173
|
+
}]
|
|
1174
|
+
};
|
|
1175
|
+
}
|
|
1131
1176
|
const inverse = {
|
|
1132
1177
|
type: "variant.replace",
|
|
1133
1178
|
at: operation.at,
|
|
@@ -1206,7 +1251,7 @@ const executeClear = (target, operation) => {
|
|
|
1206
1251
|
issue: from(operation, "required-field", "Only optional values can be cleared.")
|
|
1207
1252
|
};
|
|
1208
1253
|
if (!hasOwn$1(target.parent, target.key)) return { status: "unchanged" };
|
|
1209
|
-
if (target.node.kind !== "field" && target.node.kind !== "variant" && target.node.kind !== "dict" && target.node.kind !== "
|
|
1254
|
+
if (target.node.kind !== "field" && target.node.kind !== "variant" && target.node.kind !== "dict" && target.node.kind !== "list" && target.node.kind !== "tree") return {
|
|
1210
1255
|
status: "rejected",
|
|
1211
1256
|
issue: from(operation, "invalid-operation", "This optional value has no clear operation.")
|
|
1212
1257
|
};
|
|
@@ -1222,8 +1267,7 @@ const executeClear = (target, operation) => {
|
|
|
1222
1267
|
at: operation.at,
|
|
1223
1268
|
value: cloneValue(target.value, "inverse")
|
|
1224
1269
|
};
|
|
1225
|
-
case "dict":
|
|
1226
|
-
case "record": return {
|
|
1270
|
+
case "dict": return {
|
|
1227
1271
|
type: "dict.replace",
|
|
1228
1272
|
at: operation.at,
|
|
1229
1273
|
value: cloneValue(target.value, "inverse")
|
|
@@ -1262,7 +1306,7 @@ const execute = (root, operation, target, copyPayload) => {
|
|
|
1262
1306
|
if (operation.type === "value.clear") return !target ? invalidTarget(operation) : executeClear(target, operation);
|
|
1263
1307
|
if (operation.type === "field.set" || operation.type === "field.clear") return !target || target.node.kind !== "field" ? invalidTarget(operation) : executeValue(target, operation, copyPayload);
|
|
1264
1308
|
if (operation.type === "variant.replace") return !target || target.node.kind !== "variant" ? invalidTarget(operation) : executeValue(target, operation, copyPayload);
|
|
1265
|
-
if (operation.type === "dict.set" || operation.type === "dict.delete" || operation.type === "dict.replace") return !target || target.node.kind !== "dict"
|
|
1309
|
+
if (operation.type === "dict.set" || operation.type === "dict.delete" || operation.type === "dict.replace") return !target || target.node.kind !== "dict" ? invalidTarget(operation) : executeValue(target, operation, copyPayload);
|
|
1266
1310
|
if (operation.type === "entity.create" || operation.type === "entity.remove" || operation.type === "entity.move") return !target || target.node.kind !== "table" && target.node.kind !== "map" ? invalidTarget(operation) : executeEntity(target, operation, copyPayload);
|
|
1267
1311
|
if (operation.type === "list.insert" || operation.type === "list.move" || operation.type === "list.remove" || operation.type === "list.replace") return !target || target.node.kind !== "list" ? invalidTarget(operation) : executeList(target, operation, copyPayload);
|
|
1268
1312
|
if (operation.type === "tree.insert" || operation.type === "tree.move" || operation.type === "tree.remove" || operation.type === "tree.set" || operation.type === "tree.replace") return !target || target.node.kind !== "tree" ? invalidTarget(operation) : executeTree(root, target, operation, copyPayload);
|
|
@@ -1275,7 +1319,7 @@ const execute = (root, operation, target, copyPayload) => {
|
|
|
1275
1319
|
//#region core/src/mutation/journal.ts
|
|
1276
1320
|
const indexNode = () => ({ children: /* @__PURE__ */ new Map() });
|
|
1277
1321
|
const hasOwn = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
1278
|
-
const sameAddress
|
|
1322
|
+
const sameAddress = (left, right) => {
|
|
1279
1323
|
if (left.length !== right.length) return false;
|
|
1280
1324
|
for (let index = 0; index < left.length; index += 1) if (left[index] !== right[index]) return false;
|
|
1281
1325
|
return true;
|
|
@@ -1374,7 +1418,7 @@ const restoreEntity = (value, subject) => {
|
|
|
1374
1418
|
};
|
|
1375
1419
|
const restoreRootSubject = (value, subject) => {
|
|
1376
1420
|
if (subject.kind === "value") return subject.before.status === "present" ? subject.before.value : void 0;
|
|
1377
|
-
if (subject.kind === "variant") return subject.before;
|
|
1421
|
+
if (subject.kind === "variant") return subject.before.status === "present" ? subject.before.value : void 0;
|
|
1378
1422
|
if (subject.kind === "dict") {
|
|
1379
1423
|
if (isRecord(value)) restoreDict(value, subject.state);
|
|
1380
1424
|
return value;
|
|
@@ -1390,14 +1434,14 @@ const restoreRootSubject = (value, subject) => {
|
|
|
1390
1434
|
return restoreChange(value, subject.state);
|
|
1391
1435
|
};
|
|
1392
1436
|
const restoreSubject = (value, prefix, subject) => {
|
|
1393
|
-
if (sameAddress
|
|
1437
|
+
if (sameAddress(prefix, subject.address)) return restoreRootSubject(value, subject);
|
|
1394
1438
|
const address = subject.address.slice(prefix.length);
|
|
1395
1439
|
if (subject.kind === "value") {
|
|
1396
1440
|
writePresence(value, address, subject.before);
|
|
1397
1441
|
return value;
|
|
1398
1442
|
}
|
|
1399
1443
|
if (subject.kind === "variant") {
|
|
1400
|
-
|
|
1444
|
+
writePresence(value, address, subject.before);
|
|
1401
1445
|
return value;
|
|
1402
1446
|
}
|
|
1403
1447
|
const current = read(value, address);
|
|
@@ -1498,7 +1542,11 @@ const analyzeEntity = (root, subject) => {
|
|
|
1498
1542
|
};
|
|
1499
1543
|
const subjectChanged = (root, subject) => {
|
|
1500
1544
|
if (subject.kind === "value") return valueChanged(root, subject);
|
|
1501
|
-
if (subject.kind === "variant")
|
|
1545
|
+
if (subject.kind === "variant") {
|
|
1546
|
+
const target = locate(root, subject.address);
|
|
1547
|
+
const exists = !!target && hasOwn(target.parent, target.key);
|
|
1548
|
+
return subject.before.status === "absent" ? exists : !exists || !sameStructuralValue(subject.before.value, target?.value);
|
|
1549
|
+
}
|
|
1502
1550
|
if (subject.kind === "dict") return dictChanged(root, subject);
|
|
1503
1551
|
if (subject.kind === "list") return listChanged(root, subject);
|
|
1504
1552
|
return changeChanged(subject.state, read(root, subject.address));
|
|
@@ -1617,7 +1665,7 @@ const createChangeJournal = (root) => {
|
|
|
1617
1665
|
const candidates = buckets.get(addressHash) ?? [];
|
|
1618
1666
|
for (const subject of candidates) {
|
|
1619
1667
|
profile.journal.comparison();
|
|
1620
|
-
if (subject.kind === kind && sameAddress
|
|
1668
|
+
if (subject.kind === kind && sameAddress(subject.address, address)) return subject;
|
|
1621
1669
|
}
|
|
1622
1670
|
}
|
|
1623
1671
|
const ownerOf = (address) => {
|
|
@@ -1660,11 +1708,11 @@ const createChangeJournal = (root) => {
|
|
|
1660
1708
|
const recordVariant = (resolved, operation, inverse) => {
|
|
1661
1709
|
if (find("variant", operation.at, resolved.addressHash)) return;
|
|
1662
1710
|
const first = inverse[0];
|
|
1663
|
-
if (first?.type !== "variant.replace") return inverseMismatch(operation);
|
|
1711
|
+
if (first?.type !== "variant.replace" && first?.type !== "value.clear") return inverseMismatch(operation);
|
|
1664
1712
|
add({
|
|
1665
1713
|
...base(resolved, operation),
|
|
1666
1714
|
kind: "variant",
|
|
1667
|
-
before: absorb(first.value, operation.at)
|
|
1715
|
+
before: first.type === "value.clear" ? absent : present(absorb(first.value, operation.at))
|
|
1668
1716
|
});
|
|
1669
1717
|
};
|
|
1670
1718
|
const recordDict = (resolved, operation, inverse) => {
|
|
@@ -1828,6 +1876,10 @@ const createChangeJournal = (root) => {
|
|
|
1828
1876
|
record: (resolved, operation, inverse) => {
|
|
1829
1877
|
profile.batch.journalRecord();
|
|
1830
1878
|
if (ownerOf(operation.at)) return;
|
|
1879
|
+
if (operation.type === "value.clear" && resolved.node.kind === "variant") {
|
|
1880
|
+
recordVariant(resolved, operation, inverse);
|
|
1881
|
+
return;
|
|
1882
|
+
}
|
|
1831
1883
|
if (operation.type === "field.set" || operation.type === "field.clear" || operation.type === "value.clear") {
|
|
1832
1884
|
recordValue(resolved, operation, inverse);
|
|
1833
1885
|
return;
|
|
@@ -1869,7 +1921,7 @@ const createChangeJournal = (root) => {
|
|
|
1869
1921
|
const changeAt = (address, addressHash) => {
|
|
1870
1922
|
const candidates = collectionBuckets.get(addressHash) ?? [];
|
|
1871
1923
|
collectionBuckets.set(addressHash, candidates);
|
|
1872
|
-
let change = candidates.find((entry) => sameAddress
|
|
1924
|
+
let change = candidates.find((entry) => sameAddress(entry.address, address));
|
|
1873
1925
|
if (!change) {
|
|
1874
1926
|
change = {
|
|
1875
1927
|
address,
|
|
@@ -1913,7 +1965,7 @@ const createChangeJournal = (root) => {
|
|
|
1913
1965
|
const has = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
1914
1966
|
const stringArray = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
1915
1967
|
const positions = (value) => Array.isArray(value) && value.every((entry) => Number.isInteger(entry) && entry >= 0);
|
|
1916
|
-
const address
|
|
1968
|
+
const address = (value) => stringArray(value);
|
|
1917
1969
|
const anchor = (value) => {
|
|
1918
1970
|
if (!isRecord(value)) return false;
|
|
1919
1971
|
if (Number(has(value, "at")) + Number(has(value, "before")) + Number(has(value, "after")) !== 1) return false;
|
|
@@ -1934,7 +1986,7 @@ const rejected = (code, message) => ({
|
|
|
1934
1986
|
});
|
|
1935
1987
|
const decode = (input) => {
|
|
1936
1988
|
if (!isRecord(input)) return rejected("invalid-operation", "Operation must be an object.");
|
|
1937
|
-
if (!address
|
|
1989
|
+
if (!address(input.at)) return rejected("invalid-address", "Operation address is malformed.");
|
|
1938
1990
|
if (typeof input.type !== "string") return rejected("invalid-operation", "Operation type must be a string.");
|
|
1939
1991
|
switch (input.type) {
|
|
1940
1992
|
case "field.set":
|
|
@@ -2110,192 +2162,6 @@ const mutateOperations = (root, schema, operations, options = {}) => {
|
|
|
2110
2162
|
return session.finish();
|
|
2111
2163
|
};
|
|
2112
2164
|
//#endregion
|
|
2113
|
-
//#region core/src/mutation/footprint.ts
|
|
2114
|
-
const sameAddress = (left, right) => left.length === right.length && left.every((segment, index) => segment === right[index]);
|
|
2115
|
-
const containsAddress = (parent, child) => parent.length <= child.length && parent.every((segment, index) => segment === child[index]);
|
|
2116
|
-
const address = (value) => Array.isArray(value) && value.every((segment) => typeof segment === "string") ? Object.freeze(value.slice()) : void 0;
|
|
2117
|
-
const targetKey = (target) => {
|
|
2118
|
-
const at = target.at.join("\0");
|
|
2119
|
-
if (target.kind === "dictionary-key" || target.kind === "list-item") return `${target.kind}:${at}:${target.key}`;
|
|
2120
|
-
if (target.kind === "entity" || target.kind === "tree-node") return `${target.kind}:${at}:${target.id}`;
|
|
2121
|
-
return `${target.kind}:${at}`;
|
|
2122
|
-
};
|
|
2123
|
-
const freezeTarget = (target) => Object.freeze({
|
|
2124
|
-
...target,
|
|
2125
|
-
at: Object.freeze(target.at.slice())
|
|
2126
|
-
});
|
|
2127
|
-
const add = (targets, target) => {
|
|
2128
|
-
const stable = freezeTarget(target);
|
|
2129
|
-
targets.set(targetKey(stable), stable);
|
|
2130
|
-
};
|
|
2131
|
-
const commandFootprint = (operations) => {
|
|
2132
|
-
const targets = /* @__PURE__ */ new Map();
|
|
2133
|
-
for (const operation of operations) switch (operation.type) {
|
|
2134
|
-
case "field.set":
|
|
2135
|
-
case "field.clear":
|
|
2136
|
-
case "value.clear":
|
|
2137
|
-
case "variant.replace":
|
|
2138
|
-
add(targets, {
|
|
2139
|
-
kind: "value",
|
|
2140
|
-
at: operation.at
|
|
2141
|
-
});
|
|
2142
|
-
break;
|
|
2143
|
-
case "dict.replace":
|
|
2144
|
-
add(targets, {
|
|
2145
|
-
kind: "dictionary",
|
|
2146
|
-
at: operation.at
|
|
2147
|
-
});
|
|
2148
|
-
break;
|
|
2149
|
-
case "dict.set":
|
|
2150
|
-
case "dict.delete":
|
|
2151
|
-
add(targets, {
|
|
2152
|
-
kind: "dictionary-key",
|
|
2153
|
-
at: operation.at,
|
|
2154
|
-
key: operation.key
|
|
2155
|
-
});
|
|
2156
|
-
break;
|
|
2157
|
-
case "entity.create":
|
|
2158
|
-
add(targets, {
|
|
2159
|
-
kind: "collection",
|
|
2160
|
-
at: operation.at
|
|
2161
|
-
});
|
|
2162
|
-
for (const entry of operation.entries) add(targets, {
|
|
2163
|
-
kind: "entity",
|
|
2164
|
-
at: operation.at,
|
|
2165
|
-
id: entry.id
|
|
2166
|
-
});
|
|
2167
|
-
break;
|
|
2168
|
-
case "entity.remove":
|
|
2169
|
-
add(targets, {
|
|
2170
|
-
kind: "collection",
|
|
2171
|
-
at: operation.at
|
|
2172
|
-
});
|
|
2173
|
-
for (const id of operation.ids) add(targets, {
|
|
2174
|
-
kind: "entity",
|
|
2175
|
-
at: operation.at,
|
|
2176
|
-
id
|
|
2177
|
-
});
|
|
2178
|
-
break;
|
|
2179
|
-
case "entity.move":
|
|
2180
|
-
add(targets, {
|
|
2181
|
-
kind: "collection",
|
|
2182
|
-
at: operation.at
|
|
2183
|
-
});
|
|
2184
|
-
add(targets, {
|
|
2185
|
-
kind: "entity",
|
|
2186
|
-
at: operation.at,
|
|
2187
|
-
id: operation.id
|
|
2188
|
-
});
|
|
2189
|
-
break;
|
|
2190
|
-
case "list.insert":
|
|
2191
|
-
case "list.move":
|
|
2192
|
-
case "list.remove":
|
|
2193
|
-
add(targets, {
|
|
2194
|
-
kind: "list",
|
|
2195
|
-
at: operation.at
|
|
2196
|
-
});
|
|
2197
|
-
add(targets, {
|
|
2198
|
-
kind: "list-item",
|
|
2199
|
-
at: operation.at,
|
|
2200
|
-
key: operation.key
|
|
2201
|
-
});
|
|
2202
|
-
break;
|
|
2203
|
-
case "list.replace":
|
|
2204
|
-
add(targets, {
|
|
2205
|
-
kind: "list",
|
|
2206
|
-
at: operation.at
|
|
2207
|
-
});
|
|
2208
|
-
for (const key of operation.keys) add(targets, {
|
|
2209
|
-
kind: "list-item",
|
|
2210
|
-
at: operation.at,
|
|
2211
|
-
key
|
|
2212
|
-
});
|
|
2213
|
-
break;
|
|
2214
|
-
case "tree.insert":
|
|
2215
|
-
case "tree.move":
|
|
2216
|
-
case "tree.remove":
|
|
2217
|
-
case "tree.set":
|
|
2218
|
-
add(targets, {
|
|
2219
|
-
kind: "tree",
|
|
2220
|
-
at: operation.at
|
|
2221
|
-
});
|
|
2222
|
-
add(targets, {
|
|
2223
|
-
kind: "tree-node",
|
|
2224
|
-
at: operation.at,
|
|
2225
|
-
id: operation.treeNodeId
|
|
2226
|
-
});
|
|
2227
|
-
break;
|
|
2228
|
-
case "tree.replace":
|
|
2229
|
-
add(targets, {
|
|
2230
|
-
kind: "tree",
|
|
2231
|
-
at: operation.at
|
|
2232
|
-
});
|
|
2233
|
-
break;
|
|
2234
|
-
}
|
|
2235
|
-
return Object.freeze(Array.from(targets.values()));
|
|
2236
|
-
};
|
|
2237
|
-
const overlapsValueAndEntity = (value, entity) => containsAddress([...entity.at, entity.id], value.at) || containsAddress(value.at, [...entity.at, entity.id]);
|
|
2238
|
-
const targetsOverlap = (left, right) => {
|
|
2239
|
-
if (left.kind === "value" && right.kind === "value") return containsAddress(left.at, right.at) || containsAddress(right.at, left.at);
|
|
2240
|
-
if (left.kind === "value" && right.kind === "entity") return overlapsValueAndEntity(left, right);
|
|
2241
|
-
if (left.kind === "entity" && right.kind === "value") return overlapsValueAndEntity(right, left);
|
|
2242
|
-
if (left.kind === "dictionary" && right.kind === "dictionary") return sameAddress(left.at, right.at);
|
|
2243
|
-
if (left.kind === "dictionary" && right.kind === "dictionary-key") return sameAddress(left.at, right.at);
|
|
2244
|
-
if (left.kind === "dictionary-key" && right.kind === "dictionary") return sameAddress(left.at, right.at);
|
|
2245
|
-
if (left.kind === "dictionary-key" && right.kind === "dictionary-key") return sameAddress(left.at, right.at) && left.key === right.key;
|
|
2246
|
-
if (left.kind === "collection" && right.kind === "collection") return sameAddress(left.at, right.at);
|
|
2247
|
-
if (left.kind === "collection" && right.kind === "entity") return sameAddress(left.at, right.at);
|
|
2248
|
-
if (left.kind === "entity" && right.kind === "collection") return sameAddress(left.at, right.at);
|
|
2249
|
-
if (left.kind === "entity" && right.kind === "entity") return sameAddress(left.at, right.at) && left.id === right.id;
|
|
2250
|
-
if (left.kind === "list" && (right.kind === "list" || right.kind === "list-item")) return sameAddress(left.at, right.at);
|
|
2251
|
-
if (right.kind === "list" && left.kind === "list-item") return sameAddress(left.at, right.at);
|
|
2252
|
-
if (left.kind === "list-item" && right.kind === "list-item") return sameAddress(left.at, right.at) && left.key === right.key;
|
|
2253
|
-
if (left.kind === "tree" && (right.kind === "tree" || right.kind === "tree-node")) return sameAddress(left.at, right.at);
|
|
2254
|
-
if (right.kind === "tree" && left.kind === "tree-node") return sameAddress(left.at, right.at);
|
|
2255
|
-
if (left.kind === "tree-node" && right.kind === "tree-node") return sameAddress(left.at, right.at) && left.id === right.id;
|
|
2256
|
-
return false;
|
|
2257
|
-
};
|
|
2258
|
-
const footprintsOverlap = (left, right) => left.some((leftTarget) => right.some((rightTarget) => targetsOverlap(leftTarget, rightTarget)));
|
|
2259
|
-
const decodedTarget = (value) => {
|
|
2260
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
2261
|
-
const record = value;
|
|
2262
|
-
const at = address(record.at);
|
|
2263
|
-
if (!at || typeof record.kind !== "string") return void 0;
|
|
2264
|
-
switch (record.kind) {
|
|
2265
|
-
case "value":
|
|
2266
|
-
case "dictionary":
|
|
2267
|
-
case "collection":
|
|
2268
|
-
case "list":
|
|
2269
|
-
case "tree": return freezeTarget({
|
|
2270
|
-
kind: record.kind,
|
|
2271
|
-
at
|
|
2272
|
-
});
|
|
2273
|
-
case "dictionary-key":
|
|
2274
|
-
case "list-item": return typeof record.key === "string" ? freezeTarget({
|
|
2275
|
-
kind: record.kind,
|
|
2276
|
-
at,
|
|
2277
|
-
key: record.key
|
|
2278
|
-
}) : void 0;
|
|
2279
|
-
case "entity":
|
|
2280
|
-
case "tree-node": return typeof record.id === "string" ? freezeTarget({
|
|
2281
|
-
kind: record.kind,
|
|
2282
|
-
at,
|
|
2283
|
-
id: record.id
|
|
2284
|
-
}) : void 0;
|
|
2285
|
-
default: return;
|
|
2286
|
-
}
|
|
2287
|
-
};
|
|
2288
|
-
const decodeCommandFootprint = (value) => {
|
|
2289
|
-
if (!Array.isArray(value)) return void 0;
|
|
2290
|
-
const targets = /* @__PURE__ */ new Map();
|
|
2291
|
-
for (const entry of value) {
|
|
2292
|
-
const target = decodedTarget(entry);
|
|
2293
|
-
if (!target) return void 0;
|
|
2294
|
-
targets.set(targetKey(target), target);
|
|
2295
|
-
}
|
|
2296
|
-
return Object.freeze(Array.from(targets.values()));
|
|
2297
|
-
};
|
|
2298
|
-
//#endregion
|
|
2299
2165
|
//#region core/src/runtime.ts
|
|
2300
2166
|
var RejectedUpdate = class extends Error {
|
|
2301
2167
|
issues;
|
|
@@ -2307,6 +2173,7 @@ var RejectedUpdate = class extends Error {
|
|
|
2307
2173
|
const EMPTY = Object.freeze([]);
|
|
2308
2174
|
const publishDiagnostic = (value) => Object.freeze({
|
|
2309
2175
|
...value,
|
|
2176
|
+
source: "application",
|
|
2310
2177
|
...value.address === void 0 ? {} : { address: Object.freeze(value.address.slice()) }
|
|
2311
2178
|
});
|
|
2312
2179
|
const createDocument = (input) => {
|
|
@@ -2367,7 +2234,19 @@ const createDocument = (input) => {
|
|
|
2367
2234
|
const history = createHistory({
|
|
2368
2235
|
capacity: input.history === false ? 0 : Math.max(0, input.history?.capacity ?? 100),
|
|
2369
2236
|
revision: () => revision,
|
|
2370
|
-
apply: (operations) => applyBatch(operations, "history", false)
|
|
2237
|
+
apply: (operations) => applyBatch(operations, "history", false),
|
|
2238
|
+
assertIdle: () => {
|
|
2239
|
+
if (state.disposed) throw new DocumentDisposedError();
|
|
2240
|
+
if (busy || accessOf(runtime).projectionLocks) throw new DocumentReentrancyError();
|
|
2241
|
+
},
|
|
2242
|
+
notify: (run) => {
|
|
2243
|
+
busy = true;
|
|
2244
|
+
try {
|
|
2245
|
+
return run();
|
|
2246
|
+
} finally {
|
|
2247
|
+
busy = false;
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2371
2250
|
});
|
|
2372
2251
|
const publish = (batch, source, kind, recordHistory) => {
|
|
2373
2252
|
revision += 1;
|
|
@@ -2381,10 +2260,12 @@ const createDocument = (input) => {
|
|
|
2381
2260
|
});
|
|
2382
2261
|
if (kind === "replace" || source === "remote") history.invalidate();
|
|
2383
2262
|
else if (recordHistory && (source === "local" || source === "system")) history.record(batch.operations, batch.inverse);
|
|
2263
|
+
else if (source === "history") history.publish();
|
|
2264
|
+
else history.endGroup();
|
|
2384
2265
|
busy = true;
|
|
2385
2266
|
let observerErrors;
|
|
2386
2267
|
try {
|
|
2387
|
-
observerErrors = notify(notification, commit);
|
|
2268
|
+
observerErrors = notify(notification, commit, history.flush);
|
|
2388
2269
|
} finally {
|
|
2389
2270
|
busy = false;
|
|
2390
2271
|
}
|
|
@@ -2416,7 +2297,7 @@ const createDocument = (input) => {
|
|
|
2416
2297
|
address: {
|
|
2417
2298
|
resolve: (address) => resolveAddress(input.schema, address, state.document),
|
|
2418
2299
|
read: (address) => read(state.document, address),
|
|
2419
|
-
contains,
|
|
2300
|
+
contains: contains$1,
|
|
2420
2301
|
overlaps,
|
|
2421
2302
|
debugKey
|
|
2422
2303
|
},
|
|
@@ -2527,7 +2408,7 @@ const createDocument = (input) => {
|
|
|
2527
2408
|
const invalidTree = invalidDocument(input.schema, document);
|
|
2528
2409
|
if (invalidTree) return {
|
|
2529
2410
|
status: "rejected",
|
|
2530
|
-
issues: [at
|
|
2411
|
+
issues: [at(invalidTree, "invalid-tree", "Document replacement contains an invalid tree.")],
|
|
2531
2412
|
revision
|
|
2532
2413
|
};
|
|
2533
2414
|
if (deepEqual(state.document, document)) return {
|
|
@@ -2562,7 +2443,7 @@ const createDocument = (input) => {
|
|
|
2562
2443
|
try {
|
|
2563
2444
|
disposeNotification(notification);
|
|
2564
2445
|
} finally {
|
|
2565
|
-
history.
|
|
2446
|
+
history.dispose();
|
|
2566
2447
|
disposeRuntimeDriver(runtime);
|
|
2567
2448
|
}
|
|
2568
2449
|
}
|
|
@@ -2570,6 +2451,7 @@ const createDocument = (input) => {
|
|
|
2570
2451
|
bindRuntimeAccess(runtime, state);
|
|
2571
2452
|
bindRuntimeDriver(runtime);
|
|
2572
2453
|
notification = createNotification(runtime);
|
|
2454
|
+
bindDocumentReadable(history.api, runtime);
|
|
2573
2455
|
return runtime;
|
|
2574
2456
|
};
|
|
2575
2457
|
//#endregion
|
|
@@ -2588,6 +2470,6 @@ const asReadable = (runtime) => {
|
|
|
2588
2470
|
//#region core/src/projection/select.ts
|
|
2589
2471
|
const select = (runtime, selector) => readWith(runtime, selector);
|
|
2590
2472
|
//#endregion
|
|
2591
|
-
export { DocumentDisposedError, DocumentReentrancyError, ProjectionDisposedError, ProjectionError, asReadable,
|
|
2473
|
+
export { DocumentDisposedError, DocumentReentrancyError, ProjectionDisposedError, ProjectionError, asReadable, createDocument, createProjectionRuntime, dict, field, list, map, object, optional, schema, select, table, impact_target_exports as target, tree, variant };
|
|
2592
2474
|
|
|
2593
2475
|
//# sourceMappingURL=index.js.map
|