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
|
@@ -14,10 +14,19 @@ const require_ownership = require("./ownership-CY0nPXGF.cjs");
|
|
|
14
14
|
//#region core/src/schema.ts
|
|
15
15
|
const node = (value) => Object.freeze(value);
|
|
16
16
|
const field = () => node({ kind: "field" });
|
|
17
|
-
const optional = (value) =>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
const optional = (value) => {
|
|
18
|
+
if (![
|
|
19
|
+
"field",
|
|
20
|
+
"variant",
|
|
21
|
+
"dict",
|
|
22
|
+
"list",
|
|
23
|
+
"tree"
|
|
24
|
+
].includes(value.kind)) throw new TypeError("Only field, variant, dict, list and tree nodes support optional presence.");
|
|
25
|
+
return node({
|
|
26
|
+
...value,
|
|
27
|
+
optional: true
|
|
28
|
+
});
|
|
29
|
+
};
|
|
21
30
|
const object = (shape) => node({
|
|
22
31
|
kind: "object",
|
|
23
32
|
shape
|
|
@@ -27,10 +36,6 @@ const variant = (tag, variants) => node({
|
|
|
27
36
|
tag,
|
|
28
37
|
variants
|
|
29
38
|
});
|
|
30
|
-
const single = (value) => node({
|
|
31
|
-
kind: "single",
|
|
32
|
-
value
|
|
33
|
-
});
|
|
34
39
|
const table = (value) => node({
|
|
35
40
|
kind: "table",
|
|
36
41
|
value
|
|
@@ -39,26 +44,55 @@ const map = (value) => node({
|
|
|
39
44
|
kind: "map",
|
|
40
45
|
value
|
|
41
46
|
});
|
|
42
|
-
const record = () => node({ kind: "record" });
|
|
43
47
|
const dict = () => node({ kind: "dict" });
|
|
44
48
|
const list = (config) => ({
|
|
45
49
|
kind: "list",
|
|
46
50
|
keyOf: config.keyOf
|
|
47
51
|
});
|
|
48
52
|
const tree = () => node({ kind: "tree" });
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
const paths = /* @__PURE__ */ new WeakMap();
|
|
54
|
+
const collectionSchemas = /* @__PURE__ */ new WeakMap();
|
|
55
|
+
const collectionSchema = (selector) => {
|
|
56
|
+
const node = collectionSchemas.get(selector);
|
|
57
|
+
if (!node) throw new TypeError("Expected a schema-owned collection selector.");
|
|
58
|
+
return node;
|
|
59
|
+
};
|
|
60
|
+
const pathProxy = (nodes, address, owner) => {
|
|
61
|
+
const proxy = new Proxy({}, { get: (_target, property) => {
|
|
62
|
+
if (typeof property !== "string") return void 0;
|
|
63
|
+
if (nodes.every((node) => node.kind === "table" || node.kind === "map") && property === "item") return (id) => {
|
|
64
|
+
if (typeof id !== "string") throw new TypeError("Collection keys must be strings.");
|
|
65
|
+
return pathProxy(nodes.map((node) => node.value), [...address, id], owner);
|
|
66
|
+
};
|
|
67
|
+
const children = nodes.flatMap((node) => {
|
|
68
|
+
if (node.kind === "object") return node.shape[property] ? [node.shape[property]] : [];
|
|
69
|
+
if (node.kind !== "variant") return [];
|
|
70
|
+
if (property === node.tag) return [field()];
|
|
71
|
+
return Object.values(node.variants).flatMap((branch) => branch.shape[property] ? [branch.shape[property]] : []);
|
|
72
|
+
});
|
|
73
|
+
if (!children.length) throw new TypeError(`Invalid schema path segment: ${property}`);
|
|
74
|
+
return pathProxy(children, [...address, property], owner);
|
|
75
|
+
} });
|
|
76
|
+
paths.set(proxy, {
|
|
77
|
+
nodes,
|
|
78
|
+
address,
|
|
79
|
+
owner
|
|
80
|
+
});
|
|
81
|
+
return proxy;
|
|
82
|
+
};
|
|
55
83
|
const select = (owner, kind, pick) => {
|
|
56
|
-
const
|
|
57
|
-
|
|
84
|
+
const scope = {};
|
|
85
|
+
const value = pick(pathProxy([object(owner.shape)], [], scope));
|
|
86
|
+
const selected = typeof value === "object" && value !== null ? paths.get(value) : void 0;
|
|
87
|
+
if (!selected || selected.owner !== scope) throw new TypeError("Selector must return a path from its callback.");
|
|
88
|
+
if (kind === "collection" && !selected.nodes.every((node) => node.kind === "table" || node.kind === "map")) throw new TypeError("Collection selectors require a table or map path.");
|
|
89
|
+
const result = Object.freeze({
|
|
58
90
|
kind,
|
|
59
91
|
schema: owner,
|
|
60
|
-
address: Object.freeze([...selected.address
|
|
92
|
+
address: Object.freeze([...selected.address])
|
|
61
93
|
});
|
|
94
|
+
if (kind === "collection") collectionSchemas.set(result, selected.nodes[0]);
|
|
95
|
+
return result;
|
|
62
96
|
};
|
|
63
97
|
const schema = (shape) => {
|
|
64
98
|
const result = {
|
|
@@ -90,11 +124,6 @@ const hashText = (value, seed) => {
|
|
|
90
124
|
};
|
|
91
125
|
const appendAddressHash = (hash, segment) => hashText(segment, hashText("/", hash));
|
|
92
126
|
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
93
|
-
const unwrap = (node) => {
|
|
94
|
-
let current = node;
|
|
95
|
-
while (current?.kind === "single") current = current.value;
|
|
96
|
-
return current;
|
|
97
|
-
};
|
|
98
127
|
const variantNode = (node, value) => {
|
|
99
128
|
const tag = isRecord(value) && typeof value[node.tag] === "string" ? value[node.tag] : void 0;
|
|
100
129
|
return node.variants[String(tag ?? Object.keys(node.variants)[0] ?? "")];
|
|
@@ -104,12 +133,12 @@ const schemaRoot$1 = (schema) => ({
|
|
|
104
133
|
shape: schema.shape
|
|
105
134
|
});
|
|
106
135
|
const step = (nodeInput, value, segment) => {
|
|
107
|
-
let node =
|
|
136
|
+
let node = nodeInput;
|
|
108
137
|
if (!node) return {
|
|
109
138
|
node: void 0,
|
|
110
139
|
dynamic: false
|
|
111
140
|
};
|
|
112
|
-
if (node.kind === "variant") node =
|
|
141
|
+
if (node.kind === "variant") node = variantNode(node, value);
|
|
113
142
|
if (!node) return {
|
|
114
143
|
node: void 0,
|
|
115
144
|
dynamic: false
|
|
@@ -122,7 +151,7 @@ const step = (nodeInput, value, segment) => {
|
|
|
122
151
|
node: node.value,
|
|
123
152
|
dynamic: true
|
|
124
153
|
};
|
|
125
|
-
if (node.kind === "
|
|
154
|
+
if (node.kind === "dict" || node.kind === "list" || node.kind === "tree") return {
|
|
126
155
|
node,
|
|
127
156
|
dynamic: true
|
|
128
157
|
};
|
|
@@ -173,7 +202,7 @@ const nodeAt = (schema, address, document) => {
|
|
|
173
202
|
value = readSegment(value, segment);
|
|
174
203
|
if (!node) return void 0;
|
|
175
204
|
}
|
|
176
|
-
return
|
|
205
|
+
return node;
|
|
177
206
|
};
|
|
178
207
|
const readSegment = (value, segment) => {
|
|
179
208
|
if (!isRecord(value) && !Array.isArray(value)) return void 0;
|
|
@@ -287,25 +316,93 @@ const debugKey = (address) => {
|
|
|
287
316
|
//#endregion
|
|
288
317
|
//#region core/src/impact-target.ts
|
|
289
318
|
var impact_target_exports = /* @__PURE__ */ __exportAll({
|
|
290
|
-
address: () => address,
|
|
319
|
+
address: () => address$1,
|
|
291
320
|
belongs: () => belongs,
|
|
292
321
|
bucket: () => bucket,
|
|
293
322
|
id: () => id,
|
|
294
323
|
same: () => same
|
|
295
324
|
});
|
|
296
|
-
const address = (target) => "at" in target ? target.at : target.address;
|
|
325
|
+
const address$1 = (target) => "at" in target ? target.at : target.address;
|
|
297
326
|
const id = (target) => target.kind === "collection" && "id" in target ? target.id : void 0;
|
|
298
327
|
const belongs = (target, schema) => !("schema" in target) || target.schema === schema;
|
|
299
328
|
const same = (left, right) => {
|
|
300
329
|
if (left.kind !== right.kind) return false;
|
|
301
330
|
if ("schema" in left && "schema" in right && left.schema !== right.schema) return false;
|
|
302
|
-
const leftAddress = address(left);
|
|
303
|
-
const rightAddress = address(right);
|
|
331
|
+
const leftAddress = address$1(left);
|
|
332
|
+
const rightAddress = address$1(right);
|
|
304
333
|
if (leftAddress.length !== rightAddress.length) return false;
|
|
305
334
|
for (let index = 0; index < leftAddress.length; index += 1) if (leftAddress[index] !== rightAddress[index]) return false;
|
|
306
335
|
return left.kind !== "collection" || id(left) === id(right);
|
|
307
336
|
};
|
|
308
|
-
const bucket = (target) => address(target)[0];
|
|
337
|
+
const bucket = (target) => address$1(target)[0];
|
|
338
|
+
//#endregion
|
|
339
|
+
//#region core/src/runtime/contract.ts
|
|
340
|
+
var DocumentReentrancyError = class extends Error {
|
|
341
|
+
constructor() {
|
|
342
|
+
super("Document writes cannot be re-entered during an update or notification.");
|
|
343
|
+
this.name = "DocumentReentrancyError";
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
var DocumentDisposedError = class extends Error {
|
|
347
|
+
constructor() {
|
|
348
|
+
super("Doxum runtime has been disposed.");
|
|
349
|
+
this.name = "DocumentDisposedError";
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
//#endregion
|
|
353
|
+
//#region core/src/mutation/anchor.ts
|
|
354
|
+
const length = (keys) => keys.length;
|
|
355
|
+
const keyAt = (keys, index) => Array.isArray(keys) ? keys[index] : keys.at(index);
|
|
356
|
+
const keyIndex = (keys, key) => Array.isArray(keys) ? keys.indexOf(key) : keys.index(key);
|
|
357
|
+
const keys = (values, keyOf) => ({
|
|
358
|
+
length: values.length,
|
|
359
|
+
at: (index) => index >= 0 && index < values.length ? keyOf(values[index]) : void 0,
|
|
360
|
+
index: (key) => {
|
|
361
|
+
for (let index = 0; index < values.length; index += 1) if (keyOf(values[index]) === key) return index;
|
|
362
|
+
return -1;
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
const index = (keys, anchor) => {
|
|
366
|
+
if (!anchor) return length(keys);
|
|
367
|
+
if ("at" in anchor) return anchor.at === "start" ? 0 : length(keys);
|
|
368
|
+
if ("before" in anchor) return keyIndex(keys, anchor.before);
|
|
369
|
+
return keyIndex(keys, anchor.after) + 1;
|
|
370
|
+
};
|
|
371
|
+
const at = (keys, position) => position <= 0 ? { at: "start" } : { after: keyAt(keys, position - 1) };
|
|
372
|
+
const valid = (keys, anchor) => {
|
|
373
|
+
if (!anchor) return true;
|
|
374
|
+
if (typeof anchor !== "object" || anchor === null) return false;
|
|
375
|
+
if (Number("at" in anchor) + Number("before" in anchor) + Number("after" in anchor) !== 1) return false;
|
|
376
|
+
if ("at" in anchor) return anchor.at === "start" || anchor.at === "end";
|
|
377
|
+
return keyIndex(keys, "before" in anchor ? anchor.before : anchor.after) >= 0;
|
|
378
|
+
};
|
|
379
|
+
const afterRemove = (keys, removedIndex, anchor) => {
|
|
380
|
+
const position = index(keys, anchor);
|
|
381
|
+
return position > removedIndex ? position - 1 : position;
|
|
382
|
+
};
|
|
383
|
+
const validPositions = (length, positions) => {
|
|
384
|
+
let previous = -1;
|
|
385
|
+
for (let index = 0; index < positions.length; index += 1) {
|
|
386
|
+
const position = positions[index];
|
|
387
|
+
if (!Number.isInteger(position) || position < 0 || position <= previous || position > length + index) return false;
|
|
388
|
+
previous = position;
|
|
389
|
+
}
|
|
390
|
+
return true;
|
|
391
|
+
};
|
|
392
|
+
const restore = (keys, inserted, positions) => {
|
|
393
|
+
const currentLength = keys.length;
|
|
394
|
+
if (inserted.length !== positions.length || !validPositions(currentLength, positions)) throw new Error("Ordered restore positions are invalid.");
|
|
395
|
+
let readIndex = currentLength - 1;
|
|
396
|
+
let insertedIndex = inserted.length - 1;
|
|
397
|
+
keys.length = currentLength + inserted.length;
|
|
398
|
+
for (let writeIndex = keys.length - 1; writeIndex >= 0; writeIndex -= 1) if (insertedIndex >= 0 && positions[insertedIndex] === writeIndex) {
|
|
399
|
+
keys[writeIndex] = inserted[insertedIndex];
|
|
400
|
+
insertedIndex -= 1;
|
|
401
|
+
} else {
|
|
402
|
+
keys[writeIndex] = keys[readIndex];
|
|
403
|
+
readIndex -= 1;
|
|
404
|
+
}
|
|
405
|
+
};
|
|
309
406
|
//#endregion
|
|
310
407
|
//#region core/src/access/reader.ts
|
|
311
408
|
const schemaRoot = (schema) => object(schema.shape);
|
|
@@ -336,12 +433,40 @@ const readerFor = (node, context, address = []) => {
|
|
|
336
433
|
collectValue(context, address);
|
|
337
434
|
return readAt(context, address);
|
|
338
435
|
} };
|
|
339
|
-
if (node.kind === "dict"
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
436
|
+
if (node.kind === "dict") return {
|
|
437
|
+
get: (key) => {
|
|
438
|
+
collectValue(context, address);
|
|
439
|
+
const value = readAt(context, address);
|
|
440
|
+
return require_ownership.cloneValue(require_ownership.isRecord(value) && Object.prototype.hasOwnProperty.call(value, key) ? value[key] : void 0, "reader");
|
|
441
|
+
},
|
|
442
|
+
has: (key) => {
|
|
443
|
+
collectValue(context, address);
|
|
444
|
+
const value = readAt(context, address);
|
|
445
|
+
return require_ownership.isRecord(value) && Object.prototype.hasOwnProperty.call(value, key);
|
|
446
|
+
},
|
|
447
|
+
keys: () => {
|
|
448
|
+
collectValue(context, address);
|
|
449
|
+
const value = readAt(context, address);
|
|
450
|
+
return require_ownership.isRecord(value) ? Object.keys(value) : [];
|
|
451
|
+
},
|
|
452
|
+
values: () => {
|
|
453
|
+
collectValue(context, address);
|
|
454
|
+
require_ownership.profile.reader.structuralSnapshot();
|
|
455
|
+
return require_ownership.cloneValue(readAt(context, address) ?? {}, "reader");
|
|
456
|
+
}
|
|
457
|
+
};
|
|
344
458
|
if (node.kind === "list") return {
|
|
459
|
+
get: (key) => {
|
|
460
|
+
collectValue(context, address);
|
|
461
|
+
const value = readAt(context, address);
|
|
462
|
+
if (!Array.isArray(value)) return void 0;
|
|
463
|
+
return require_ownership.cloneValue(value[keys(value, node.keyOf).index(key)], "reader");
|
|
464
|
+
},
|
|
465
|
+
has: (key) => {
|
|
466
|
+
collectValue(context, address);
|
|
467
|
+
const value = readAt(context, address);
|
|
468
|
+
return Array.isArray(value) && keys(value, node.keyOf).index(key) >= 0;
|
|
469
|
+
},
|
|
345
470
|
values: () => {
|
|
346
471
|
collectValue(context, address);
|
|
347
472
|
const value = readAt(context, address);
|
|
@@ -419,14 +544,10 @@ const readerFor = (node, context, address = []) => {
|
|
|
419
544
|
}
|
|
420
545
|
};
|
|
421
546
|
}
|
|
422
|
-
if (node.kind === "
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
const tag = require_ownership.isRecord(value) && typeof value[node.tag] === "string" ? String(value[node.tag]) : void 0;
|
|
427
|
-
const child = (tag ? node.variants[tag] : void 0)?.shape[property];
|
|
428
|
-
return child ? readerFor(child, context, [...address, property]) : void 0;
|
|
429
|
-
} });
|
|
547
|
+
if (node.kind === "variant") return { get: () => {
|
|
548
|
+
collectValue(context, address);
|
|
549
|
+
return require_ownership.cloneValue(readAt(context, address), "reader");
|
|
550
|
+
} };
|
|
430
551
|
let children;
|
|
431
552
|
return new Proxy({}, { get: (_target, property) => {
|
|
432
553
|
if (typeof property === "symbol") return void 0;
|
|
@@ -448,19 +569,191 @@ const documentReader = (schema, root, active, dependencies) => {
|
|
|
448
569
|
});
|
|
449
570
|
};
|
|
450
571
|
//#endregion
|
|
451
|
-
//#region core/src/
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
572
|
+
//#region core/src/mutation/footprint.ts
|
|
573
|
+
const sameAddress = (left, right) => left.length === right.length && left.every((segment, index) => segment === right[index]);
|
|
574
|
+
const containsAddress = (parent, child) => parent.length <= child.length && parent.every((segment, index) => segment === child[index]);
|
|
575
|
+
const address = (value) => Array.isArray(value) && value.every((segment) => typeof segment === "string") ? Object.freeze(value.slice()) : void 0;
|
|
576
|
+
const targetKey = (target) => {
|
|
577
|
+
const at = target.at.join("\0");
|
|
578
|
+
if (target.kind === "dictionary-key" || target.kind === "list-item") return `${target.kind}:${at}:${target.key}`;
|
|
579
|
+
if (target.kind === "entity" || target.kind === "tree-node") return `${target.kind}:${at}:${target.id}`;
|
|
580
|
+
return `${target.kind}:${at}`;
|
|
581
|
+
};
|
|
582
|
+
const freezeTarget = (target) => Object.freeze({
|
|
583
|
+
...target,
|
|
584
|
+
at: Object.freeze(target.at.slice())
|
|
585
|
+
});
|
|
586
|
+
const add = (targets, target) => {
|
|
587
|
+
const stable = freezeTarget(target);
|
|
588
|
+
targets.set(targetKey(stable), stable);
|
|
589
|
+
};
|
|
590
|
+
const commandFootprint = (operations) => {
|
|
591
|
+
const targets = /* @__PURE__ */ new Map();
|
|
592
|
+
for (const operation of operations) switch (operation.type) {
|
|
593
|
+
case "field.set":
|
|
594
|
+
case "field.clear":
|
|
595
|
+
case "value.clear":
|
|
596
|
+
case "variant.replace":
|
|
597
|
+
add(targets, {
|
|
598
|
+
kind: "value",
|
|
599
|
+
at: operation.at
|
|
600
|
+
});
|
|
601
|
+
break;
|
|
602
|
+
case "dict.replace":
|
|
603
|
+
add(targets, {
|
|
604
|
+
kind: "dictionary",
|
|
605
|
+
at: operation.at
|
|
606
|
+
});
|
|
607
|
+
break;
|
|
608
|
+
case "dict.set":
|
|
609
|
+
case "dict.delete":
|
|
610
|
+
add(targets, {
|
|
611
|
+
kind: "dictionary-key",
|
|
612
|
+
at: operation.at,
|
|
613
|
+
key: operation.key
|
|
614
|
+
});
|
|
615
|
+
break;
|
|
616
|
+
case "entity.create":
|
|
617
|
+
add(targets, {
|
|
618
|
+
kind: "collection",
|
|
619
|
+
at: operation.at
|
|
620
|
+
});
|
|
621
|
+
for (const entry of operation.entries) add(targets, {
|
|
622
|
+
kind: "entity",
|
|
623
|
+
at: operation.at,
|
|
624
|
+
id: entry.id
|
|
625
|
+
});
|
|
626
|
+
break;
|
|
627
|
+
case "entity.remove":
|
|
628
|
+
add(targets, {
|
|
629
|
+
kind: "collection",
|
|
630
|
+
at: operation.at
|
|
631
|
+
});
|
|
632
|
+
for (const id of operation.ids) add(targets, {
|
|
633
|
+
kind: "entity",
|
|
634
|
+
at: operation.at,
|
|
635
|
+
id
|
|
636
|
+
});
|
|
637
|
+
break;
|
|
638
|
+
case "entity.move":
|
|
639
|
+
add(targets, {
|
|
640
|
+
kind: "collection",
|
|
641
|
+
at: operation.at
|
|
642
|
+
});
|
|
643
|
+
add(targets, {
|
|
644
|
+
kind: "entity",
|
|
645
|
+
at: operation.at,
|
|
646
|
+
id: operation.id
|
|
647
|
+
});
|
|
648
|
+
break;
|
|
649
|
+
case "list.insert":
|
|
650
|
+
case "list.move":
|
|
651
|
+
case "list.remove":
|
|
652
|
+
add(targets, {
|
|
653
|
+
kind: "list",
|
|
654
|
+
at: operation.at
|
|
655
|
+
});
|
|
656
|
+
add(targets, {
|
|
657
|
+
kind: "list-item",
|
|
658
|
+
at: operation.at,
|
|
659
|
+
key: operation.key
|
|
660
|
+
});
|
|
661
|
+
break;
|
|
662
|
+
case "list.replace":
|
|
663
|
+
add(targets, {
|
|
664
|
+
kind: "list",
|
|
665
|
+
at: operation.at
|
|
666
|
+
});
|
|
667
|
+
for (const key of operation.keys) add(targets, {
|
|
668
|
+
kind: "list-item",
|
|
669
|
+
at: operation.at,
|
|
670
|
+
key
|
|
671
|
+
});
|
|
672
|
+
break;
|
|
673
|
+
case "tree.insert":
|
|
674
|
+
case "tree.move":
|
|
675
|
+
case "tree.remove":
|
|
676
|
+
case "tree.set":
|
|
677
|
+
add(targets, {
|
|
678
|
+
kind: "tree",
|
|
679
|
+
at: operation.at
|
|
680
|
+
});
|
|
681
|
+
add(targets, {
|
|
682
|
+
kind: "tree-node",
|
|
683
|
+
at: operation.at,
|
|
684
|
+
id: operation.treeNodeId
|
|
685
|
+
});
|
|
686
|
+
break;
|
|
687
|
+
case "tree.replace":
|
|
688
|
+
add(targets, {
|
|
689
|
+
kind: "tree",
|
|
690
|
+
at: operation.at
|
|
691
|
+
});
|
|
692
|
+
break;
|
|
456
693
|
}
|
|
694
|
+
return Object.freeze(Array.from(targets.values()));
|
|
457
695
|
};
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
696
|
+
const overlapsValueAndEntity = (value, entity) => containsAddress([...entity.at, entity.id], value.at) || containsAddress(value.at, [...entity.at, entity.id]);
|
|
697
|
+
const targetsOverlap = (left, right) => {
|
|
698
|
+
if (left.kind === "value" && right.kind === "value") return containsAddress(left.at, right.at) || containsAddress(right.at, left.at);
|
|
699
|
+
if (left.kind === "value" && right.kind === "entity") return overlapsValueAndEntity(left, right);
|
|
700
|
+
if (left.kind === "entity" && right.kind === "value") return overlapsValueAndEntity(right, left);
|
|
701
|
+
if (left.kind === "dictionary" && right.kind === "dictionary") return sameAddress(left.at, right.at);
|
|
702
|
+
if (left.kind === "dictionary" && right.kind === "dictionary-key") return sameAddress(left.at, right.at);
|
|
703
|
+
if (left.kind === "dictionary-key" && right.kind === "dictionary") return sameAddress(left.at, right.at);
|
|
704
|
+
if (left.kind === "dictionary-key" && right.kind === "dictionary-key") return sameAddress(left.at, right.at) && left.key === right.key;
|
|
705
|
+
if (left.kind === "collection" && right.kind === "collection") return sameAddress(left.at, right.at);
|
|
706
|
+
if (left.kind === "collection" && right.kind === "entity") return sameAddress(left.at, right.at);
|
|
707
|
+
if (left.kind === "entity" && right.kind === "collection") return sameAddress(left.at, right.at);
|
|
708
|
+
if (left.kind === "entity" && right.kind === "entity") return sameAddress(left.at, right.at) && left.id === right.id;
|
|
709
|
+
if (left.kind === "list" && (right.kind === "list" || right.kind === "list-item")) return sameAddress(left.at, right.at);
|
|
710
|
+
if (right.kind === "list" && left.kind === "list-item") return sameAddress(left.at, right.at);
|
|
711
|
+
if (left.kind === "list-item" && right.kind === "list-item") return sameAddress(left.at, right.at) && left.key === right.key;
|
|
712
|
+
if (left.kind === "tree" && (right.kind === "tree" || right.kind === "tree-node")) return sameAddress(left.at, right.at);
|
|
713
|
+
if (right.kind === "tree" && left.kind === "tree-node") return sameAddress(left.at, right.at);
|
|
714
|
+
if (left.kind === "tree-node" && right.kind === "tree-node") return sameAddress(left.at, right.at) && left.id === right.id;
|
|
715
|
+
return false;
|
|
716
|
+
};
|
|
717
|
+
const footprintsOverlap = (left, right) => left.some((leftTarget) => right.some((rightTarget) => targetsOverlap(leftTarget, rightTarget)));
|
|
718
|
+
const decodedTarget = (value) => {
|
|
719
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
720
|
+
const record = value;
|
|
721
|
+
const at = address(record.at);
|
|
722
|
+
if (!at || typeof record.kind !== "string") return void 0;
|
|
723
|
+
switch (record.kind) {
|
|
724
|
+
case "value":
|
|
725
|
+
case "dictionary":
|
|
726
|
+
case "collection":
|
|
727
|
+
case "list":
|
|
728
|
+
case "tree": return freezeTarget({
|
|
729
|
+
kind: record.kind,
|
|
730
|
+
at
|
|
731
|
+
});
|
|
732
|
+
case "dictionary-key":
|
|
733
|
+
case "list-item": return typeof record.key === "string" ? freezeTarget({
|
|
734
|
+
kind: record.kind,
|
|
735
|
+
at,
|
|
736
|
+
key: record.key
|
|
737
|
+
}) : void 0;
|
|
738
|
+
case "entity":
|
|
739
|
+
case "tree-node": return typeof record.id === "string" ? freezeTarget({
|
|
740
|
+
kind: record.kind,
|
|
741
|
+
at,
|
|
742
|
+
id: record.id
|
|
743
|
+
}) : void 0;
|
|
744
|
+
default: return;
|
|
462
745
|
}
|
|
463
746
|
};
|
|
747
|
+
const decodeCommandFootprint = (value) => {
|
|
748
|
+
if (!Array.isArray(value)) return void 0;
|
|
749
|
+
const targets = /* @__PURE__ */ new Map();
|
|
750
|
+
for (const entry of value) {
|
|
751
|
+
const target = decodedTarget(entry);
|
|
752
|
+
if (!target) return void 0;
|
|
753
|
+
targets.set(targetKey(target), target);
|
|
754
|
+
}
|
|
755
|
+
return Object.freeze(Array.from(targets.values()));
|
|
756
|
+
};
|
|
464
757
|
//#endregion
|
|
465
758
|
//#region core/src/runtime/access.ts
|
|
466
759
|
const states = /* @__PURE__ */ new WeakMap();
|
|
@@ -487,6 +780,11 @@ const readWith = (runtime, run, dependencies) => {
|
|
|
487
780
|
//#region core/src/runtime/notification.ts
|
|
488
781
|
const ROOT_BUCKET = Symbol("document-root");
|
|
489
782
|
const notifications = /* @__PURE__ */ new WeakMap();
|
|
783
|
+
const readableOwners = /* @__PURE__ */ new WeakMap();
|
|
784
|
+
const bindDocumentReadable = (readable, runtime) => {
|
|
785
|
+
readableOwners.set(readable, runtime);
|
|
786
|
+
};
|
|
787
|
+
const documentReadableOwner = (readable) => readableOwners.get(readable);
|
|
490
788
|
const key = (value) => bucket(value) ?? ROOT_BUCKET;
|
|
491
789
|
const createNotification = (runtime) => {
|
|
492
790
|
const notification = {
|
|
@@ -561,7 +859,7 @@ const subscribeTargets = (notification, targets, listener) => {
|
|
|
561
859
|
});
|
|
562
860
|
};
|
|
563
861
|
};
|
|
564
|
-
const notify = (notification, commit) => {
|
|
862
|
+
const notify = (notification, commit, afterSettle) => {
|
|
565
863
|
notification.notifying = true;
|
|
566
864
|
const errors = [];
|
|
567
865
|
const call = (listener) => {
|
|
@@ -612,6 +910,7 @@ const notify = (notification, commit) => {
|
|
|
612
910
|
}));
|
|
613
911
|
}
|
|
614
912
|
}
|
|
913
|
+
if (afterSettle) errors.push(...afterSettle());
|
|
615
914
|
const candidates = notification.candidates;
|
|
616
915
|
candidates.clear();
|
|
617
916
|
if (commit.impact.kind === "reset") notification.filtered.forEach((entry) => candidates.add(entry));
|
|
@@ -985,239 +1284,34 @@ const assertScope = (active) => {
|
|
|
985
1284
|
if (!active()) throw new Error("Projection reader or writer is no longer active.");
|
|
986
1285
|
};
|
|
987
1286
|
//#endregion
|
|
988
|
-
//#region core/src/projection/
|
|
989
|
-
const
|
|
990
|
-
|
|
991
|
-
const
|
|
992
|
-
const
|
|
993
|
-
const
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
clear: () => {
|
|
1015
|
-
commits = [];
|
|
1016
|
-
},
|
|
1017
|
-
context: (active) => {
|
|
1018
|
-
assertScope(active);
|
|
1019
|
-
if (state.disposed) throw new Error("Document has been disposed.");
|
|
1020
|
-
const read = collection ? readerFor(nodeAt(state.schema, collection.address), {
|
|
1021
|
-
root: () => state.document,
|
|
1022
|
-
active
|
|
1023
|
-
}, collection.address) : documentReader(state.schema, () => state.document, active);
|
|
1024
|
-
return Object.freeze({
|
|
1025
|
-
read,
|
|
1026
|
-
target: collection,
|
|
1027
|
-
revision: runtime.revision(),
|
|
1028
|
-
commits: Object.freeze(commits.slice()),
|
|
1029
|
-
reset: record.reset()
|
|
1030
|
-
});
|
|
1031
|
-
}
|
|
1032
|
-
};
|
|
1033
|
-
const handle = collection ? {} : {
|
|
1034
|
-
collection: (pick) => {
|
|
1035
|
-
scheduler.assertIdle();
|
|
1036
|
-
const selector = state.schema.collection(pick);
|
|
1037
|
-
const node = nodeAt(state.schema, selector.address);
|
|
1038
|
-
if (node?.kind !== "table" && node?.kind !== "map") throw new TypeError("Expected a table or map collection path.");
|
|
1039
|
-
return make([selector], selector);
|
|
1040
|
-
},
|
|
1041
|
-
targets: (...selected) => {
|
|
1042
|
-
scheduler.assertIdle();
|
|
1043
|
-
if (!selected.length) throw new TypeError("Expected at least one target.");
|
|
1044
|
-
return make(selected);
|
|
1045
|
-
}
|
|
1046
|
-
};
|
|
1047
|
-
Object.freeze(handle);
|
|
1048
|
-
bindings.push({
|
|
1049
|
-
handle,
|
|
1050
|
-
targets,
|
|
1051
|
-
record
|
|
1052
|
-
});
|
|
1053
|
-
if (collection) collections.set(handle, {
|
|
1054
|
-
source: handle,
|
|
1055
|
-
target: collection
|
|
1056
|
-
});
|
|
1057
|
-
scheduler.register(handle, record);
|
|
1058
|
-
receivers.set(record, (commit) => {
|
|
1059
|
-
commits.push(commit);
|
|
1060
|
-
});
|
|
1061
|
-
return handle;
|
|
1062
|
-
};
|
|
1063
|
-
const receivers = /* @__PURE__ */ new Map();
|
|
1064
|
-
const handle = make([]);
|
|
1065
|
-
const guard = (locked) => {
|
|
1066
|
-
state.projectionLocks = (state.projectionLocks ?? 0) + (locked ? 1 : -1);
|
|
1067
|
-
};
|
|
1068
|
-
scheduler.guards.add(guard);
|
|
1069
|
-
const unsubscribe = attachProjection(runtime, {
|
|
1070
|
-
capture: (commit) => {
|
|
1071
|
-
for (const binding of bindings) if (!binding.targets.length || binding.targets.some(commit.impact.affects)) {
|
|
1072
|
-
receivers.get(binding.record)(commit);
|
|
1073
|
-
scheduler.capture(binding.record);
|
|
1074
|
-
}
|
|
1075
|
-
},
|
|
1076
|
-
settle: scheduler.settle,
|
|
1077
|
-
flush: scheduler.flush,
|
|
1078
|
-
dispose: () => {
|
|
1079
|
-
bindings.forEach(({ record }) => {
|
|
1080
|
-
record.fault = new ProjectionError("source", "document disposed", [runtime.revision()], /* @__PURE__ */ new Error("Document has been disposed."));
|
|
1081
|
-
scheduler.capture(record);
|
|
1082
|
-
});
|
|
1083
|
-
scheduler.run();
|
|
1287
|
+
//#region core/src/projection/node.ts
|
|
1288
|
+
const createNode = (scheduler, spec, behavior) => {
|
|
1289
|
+
scheduler.assertIdle();
|
|
1290
|
+
const entries = Object.entries(spec.sources).map(([key, handle]) => [key, scheduler.source(handle)]);
|
|
1291
|
+
const order = scheduler.order();
|
|
1292
|
+
const node = {
|
|
1293
|
+
...behavior,
|
|
1294
|
+
publish: () => {
|
|
1295
|
+
if (node.fault) behavior.clear();
|
|
1296
|
+
else behavior.publish();
|
|
1297
|
+
},
|
|
1298
|
+
order,
|
|
1299
|
+
name: spec.name ? `${spec.name} (${order})` : `projection-${order}`,
|
|
1300
|
+
sources: entries.map(([, source]) => source),
|
|
1301
|
+
consumers: /* @__PURE__ */ new Set(),
|
|
1302
|
+
disposed: false,
|
|
1303
|
+
fault: void 0,
|
|
1304
|
+
forced: false,
|
|
1305
|
+
statusChanged: false,
|
|
1306
|
+
evaluate: (build) => {
|
|
1307
|
+
let active = true;
|
|
1308
|
+
try {
|
|
1309
|
+
const inputs = Object.fromEntries(entries.map(([key, source]) => [key, source.context(() => active)]));
|
|
1310
|
+
return behavior.evaluate(inputs, build, () => active);
|
|
1311
|
+
} finally {
|
|
1312
|
+
active = false;
|
|
1084
1313
|
}
|
|
1085
|
-
}
|
|
1086
|
-
scheduler.cleanups.add(() => {
|
|
1087
|
-
unsubscribe();
|
|
1088
|
-
scheduler.guards.delete(guard);
|
|
1089
|
-
});
|
|
1090
|
-
documents.set(state, handle);
|
|
1091
|
-
return handle;
|
|
1092
|
-
};
|
|
1093
|
-
const valueSource = (initial, equal) => {
|
|
1094
|
-
let value = initial;
|
|
1095
|
-
let previous = initial;
|
|
1096
|
-
let revision = 0;
|
|
1097
|
-
const handle = Object.freeze({});
|
|
1098
|
-
const record = {
|
|
1099
|
-
consumers: /* @__PURE__ */ new Set(),
|
|
1100
|
-
disposed: false,
|
|
1101
|
-
fault: void 0,
|
|
1102
|
-
revision: () => revision,
|
|
1103
|
-
reset: () => false,
|
|
1104
|
-
clear: () => {
|
|
1105
|
-
previous = value;
|
|
1106
|
-
},
|
|
1107
|
-
context: (active) => {
|
|
1108
|
-
assertScope(active);
|
|
1109
|
-
return Object.freeze({
|
|
1110
|
-
value,
|
|
1111
|
-
previous,
|
|
1112
|
-
revision,
|
|
1113
|
-
changed: !equal(previous, value),
|
|
1114
|
-
reset: false
|
|
1115
|
-
});
|
|
1116
|
-
}
|
|
1117
|
-
};
|
|
1118
|
-
scheduler.register(handle, record);
|
|
1119
|
-
const accept = (next) => {
|
|
1120
|
-
scheduler.assertIdle();
|
|
1121
|
-
const recovering = record.fault !== void 0;
|
|
1122
|
-
if (equal(value, next) && !recovering) return;
|
|
1123
|
-
record.fault = void 0;
|
|
1124
|
-
value = next;
|
|
1125
|
-
revision++;
|
|
1126
|
-
scheduler.capture(record);
|
|
1127
|
-
};
|
|
1128
|
-
return {
|
|
1129
|
-
source: handle,
|
|
1130
|
-
accept,
|
|
1131
|
-
set(next) {
|
|
1132
|
-
accept(next);
|
|
1133
|
-
scheduler.run();
|
|
1134
|
-
}
|
|
1135
|
-
};
|
|
1136
|
-
};
|
|
1137
|
-
return {
|
|
1138
|
-
dispose: () => {
|
|
1139
|
-
documents.clear();
|
|
1140
|
-
readables.clear();
|
|
1141
|
-
},
|
|
1142
|
-
document,
|
|
1143
|
-
input: (initial, options) => {
|
|
1144
|
-
const { source, set } = valueSource(initial, options?.isEqual ?? Object.is);
|
|
1145
|
-
return Object.freeze({
|
|
1146
|
-
source,
|
|
1147
|
-
set
|
|
1148
|
-
});
|
|
1149
|
-
},
|
|
1150
|
-
fromReadable: (readable, options) => {
|
|
1151
|
-
scheduler.assertIdle();
|
|
1152
|
-
if (projectionHandles.has(readable)) throw new Error("Projection nodes must be declared directly as sources.");
|
|
1153
|
-
const old = readables.get(readable);
|
|
1154
|
-
if (old) return old;
|
|
1155
|
-
const input = valueSource(readable.current(), options?.isEqual ?? Object.is);
|
|
1156
|
-
const receive = () => {
|
|
1157
|
-
if (!scheduler.active) return;
|
|
1158
|
-
try {
|
|
1159
|
-
input.accept(readable.current());
|
|
1160
|
-
} catch (cause) {
|
|
1161
|
-
const record = scheduler.source(input.source);
|
|
1162
|
-
record.fault = new ProjectionError("source", "external readable", [readable.revision()], cause);
|
|
1163
|
-
scheduler.capture(record);
|
|
1164
|
-
}
|
|
1165
|
-
scheduler.run();
|
|
1166
|
-
};
|
|
1167
|
-
let unsubscribe;
|
|
1168
|
-
try {
|
|
1169
|
-
unsubscribe = readable.subscribe(receive);
|
|
1170
|
-
input.accept(readable.current());
|
|
1171
|
-
} catch (error) {
|
|
1172
|
-
try {
|
|
1173
|
-
unsubscribe?.();
|
|
1174
|
-
} finally {
|
|
1175
|
-
scheduler.unregisterSource(input.source);
|
|
1176
|
-
}
|
|
1177
|
-
throw error;
|
|
1178
|
-
}
|
|
1179
|
-
scheduler.cleanups.add(unsubscribe);
|
|
1180
|
-
readables.set(readable, input.source);
|
|
1181
|
-
scheduler.run();
|
|
1182
|
-
return input.source;
|
|
1183
|
-
},
|
|
1184
|
-
collectionTarget: (handle) => {
|
|
1185
|
-
scheduler.source(handle);
|
|
1186
|
-
const value = collections.get(handle);
|
|
1187
|
-
if (!value) throw new Error("map requires a document collection source.");
|
|
1188
|
-
return value.target;
|
|
1189
|
-
}
|
|
1190
|
-
};
|
|
1191
|
-
};
|
|
1192
|
-
//#endregion
|
|
1193
|
-
//#region core/src/projection/node.ts
|
|
1194
|
-
const createNode = (scheduler, spec, behavior) => {
|
|
1195
|
-
scheduler.assertIdle();
|
|
1196
|
-
const entries = Object.entries(spec.sources).map(([key, handle]) => [key, scheduler.source(handle)]);
|
|
1197
|
-
const order = scheduler.order();
|
|
1198
|
-
const node = {
|
|
1199
|
-
...behavior,
|
|
1200
|
-
publish: () => {
|
|
1201
|
-
if (node.fault) behavior.clear();
|
|
1202
|
-
else behavior.publish();
|
|
1203
|
-
},
|
|
1204
|
-
order,
|
|
1205
|
-
name: spec.name ? `${spec.name} (${order})` : `projection-${order}`,
|
|
1206
|
-
sources: entries.map(([, source]) => source),
|
|
1207
|
-
consumers: /* @__PURE__ */ new Set(),
|
|
1208
|
-
disposed: false,
|
|
1209
|
-
fault: void 0,
|
|
1210
|
-
forced: false,
|
|
1211
|
-
statusChanged: false,
|
|
1212
|
-
evaluate: (build) => {
|
|
1213
|
-
let active = true;
|
|
1214
|
-
try {
|
|
1215
|
-
const inputs = Object.fromEntries(entries.map(([key, source]) => [key, source.context(() => active)]));
|
|
1216
|
-
return behavior.evaluate(inputs, build, () => active);
|
|
1217
|
-
} finally {
|
|
1218
|
-
active = false;
|
|
1219
|
-
}
|
|
1220
|
-
}
|
|
1314
|
+
}
|
|
1221
1315
|
};
|
|
1222
1316
|
scheduler.initialize(() => {
|
|
1223
1317
|
const invalid = node.sources.find((source) => source.fault || source.disposed);
|
|
@@ -1242,103 +1336,8 @@ const createNode = (scheduler, spec, behavior) => {
|
|
|
1242
1336
|
};
|
|
1243
1337
|
};
|
|
1244
1338
|
//#endregion
|
|
1245
|
-
//#region core/src/projection/value.ts
|
|
1246
|
-
const createValue = (scheduler, spec) => {
|
|
1247
|
-
let instance;
|
|
1248
|
-
let value;
|
|
1249
|
-
let next;
|
|
1250
|
-
let previous;
|
|
1251
|
-
let initialized = false;
|
|
1252
|
-
let revision = 0;
|
|
1253
|
-
let changed = false;
|
|
1254
|
-
let reset = false;
|
|
1255
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
1256
|
-
const owner = createNode(scheduler, spec, {
|
|
1257
|
-
evaluate: (sources, build) => {
|
|
1258
|
-
let candidate;
|
|
1259
|
-
if (build || !instance) {
|
|
1260
|
-
require_ownership.profile.materialized.rebuilt();
|
|
1261
|
-
instance = void 0;
|
|
1262
|
-
const built = spec.build(sources);
|
|
1263
|
-
assertSynchronous(built);
|
|
1264
|
-
instance = built;
|
|
1265
|
-
candidate = built.value;
|
|
1266
|
-
} else {
|
|
1267
|
-
require_ownership.profile.materialized.updated();
|
|
1268
|
-
const result = instance.update(sources);
|
|
1269
|
-
assertSynchronous(result);
|
|
1270
|
-
if (result.kind === "rebuild") {
|
|
1271
|
-
instance = void 0;
|
|
1272
|
-
const built = spec.build(sources);
|
|
1273
|
-
assertSynchronous(built);
|
|
1274
|
-
instance = built;
|
|
1275
|
-
candidate = built.value;
|
|
1276
|
-
build = true;
|
|
1277
|
-
} else candidate = result.kind === "changed" ? result.value : value;
|
|
1278
|
-
}
|
|
1279
|
-
previous = value;
|
|
1280
|
-
changed = !initialized || !(spec.isEqual ?? Object.is)(value, candidate);
|
|
1281
|
-
next = changed ? candidate : value;
|
|
1282
|
-
reset = build;
|
|
1283
|
-
return changed;
|
|
1284
|
-
},
|
|
1285
|
-
context: (active) => {
|
|
1286
|
-
assertScope(active);
|
|
1287
|
-
return Object.freeze({
|
|
1288
|
-
value: next,
|
|
1289
|
-
previous,
|
|
1290
|
-
changed,
|
|
1291
|
-
revision: revision + (changed ? 1 : 0),
|
|
1292
|
-
reset
|
|
1293
|
-
});
|
|
1294
|
-
},
|
|
1295
|
-
revision: () => revision,
|
|
1296
|
-
reset: () => reset,
|
|
1297
|
-
publish: () => {
|
|
1298
|
-
if (changed && initialized) revision++;
|
|
1299
|
-
value = next;
|
|
1300
|
-
initialized = true;
|
|
1301
|
-
},
|
|
1302
|
-
emit: (call) => {
|
|
1303
|
-
require_ownership.profile.materialized.notification();
|
|
1304
|
-
Array.from(listeners).forEach((listener) => call(listener));
|
|
1305
|
-
},
|
|
1306
|
-
clear: () => {
|
|
1307
|
-
next = value;
|
|
1308
|
-
previous = value;
|
|
1309
|
-
changed = false;
|
|
1310
|
-
reset = false;
|
|
1311
|
-
},
|
|
1312
|
-
release: () => {
|
|
1313
|
-
listeners.clear();
|
|
1314
|
-
instance = void 0;
|
|
1315
|
-
value = next = previous = void 0;
|
|
1316
|
-
}
|
|
1317
|
-
});
|
|
1318
|
-
const handle = Object.freeze({
|
|
1319
|
-
current: () => {
|
|
1320
|
-
owner.check();
|
|
1321
|
-
return value;
|
|
1322
|
-
},
|
|
1323
|
-
revision: () => {
|
|
1324
|
-
owner.check();
|
|
1325
|
-
return revision;
|
|
1326
|
-
},
|
|
1327
|
-
subscribe: (listener) => {
|
|
1328
|
-
owner.check();
|
|
1329
|
-
listeners.add(listener);
|
|
1330
|
-
return () => {
|
|
1331
|
-
listeners.delete(listener);
|
|
1332
|
-
};
|
|
1333
|
-
},
|
|
1334
|
-
rebuild: owner.rebuild,
|
|
1335
|
-
dispose: owner.dispose
|
|
1336
|
-
});
|
|
1337
|
-
owner.install(handle);
|
|
1338
|
-
return handle;
|
|
1339
|
-
};
|
|
1340
|
-
//#endregion
|
|
1341
1339
|
//#region core/src/projection/collection.ts
|
|
1340
|
+
const collectionHandles = /* @__PURE__ */ new WeakSet();
|
|
1342
1341
|
const readonlySet = (values) => {
|
|
1343
1342
|
const set = new Set(values);
|
|
1344
1343
|
const view = Object.freeze({
|
|
@@ -1666,68 +1665,463 @@ const createCollection = (scheduler, spec) => {
|
|
|
1666
1665
|
};
|
|
1667
1666
|
projectionHandles.add(handle.ids);
|
|
1668
1667
|
projectionHandles.add(handle.all);
|
|
1668
|
+
collectionHandles.add(handle);
|
|
1669
1669
|
owner.install(handle);
|
|
1670
1670
|
return Object.freeze(handle);
|
|
1671
1671
|
};
|
|
1672
1672
|
//#endregion
|
|
1673
|
-
//#region core/src/projection/
|
|
1674
|
-
const
|
|
1675
|
-
const
|
|
1676
|
-
const
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
const
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1673
|
+
//#region core/src/projection/source.ts
|
|
1674
|
+
const createSources = (scheduler) => {
|
|
1675
|
+
const documents = /* @__PURE__ */ new Map();
|
|
1676
|
+
const readables = /* @__PURE__ */ new Map();
|
|
1677
|
+
const collections = /* @__PURE__ */ new WeakSet();
|
|
1678
|
+
const document = (runtime) => {
|
|
1679
|
+
scheduler.assertIdle();
|
|
1680
|
+
const state = accessOf(runtime);
|
|
1681
|
+
if (state.disposed) throw new Error("Document has been disposed.");
|
|
1682
|
+
const existing = documents.get(state);
|
|
1683
|
+
if (existing) return existing;
|
|
1684
|
+
const bindings = [];
|
|
1685
|
+
const make = (targets, collection) => {
|
|
1686
|
+
if (state.disposed) throw new Error("Document has been disposed.");
|
|
1687
|
+
targets.forEach((value) => {
|
|
1688
|
+
if (!belongs(value, state.schema)) throw new Error("Projection target belongs to another schema.");
|
|
1689
|
+
});
|
|
1690
|
+
const old = bindings.find((entry) => Boolean(collection) === collections.has(entry.handle) && entry.targets.length === targets.length && entry.targets.every((value, i) => same(value, targets[i])));
|
|
1691
|
+
if (old) return old.handle;
|
|
1692
|
+
let commits = [];
|
|
1693
|
+
let reset = false;
|
|
1694
|
+
let orderDirty = false;
|
|
1695
|
+
const keys = /* @__PURE__ */ new Set();
|
|
1696
|
+
let candidates;
|
|
1697
|
+
const record = {
|
|
1698
|
+
consumers: /* @__PURE__ */ new Set(),
|
|
1699
|
+
disposed: false,
|
|
1700
|
+
fault: void 0,
|
|
1701
|
+
revision: runtime.revision,
|
|
1702
|
+
reset: () => reset,
|
|
1703
|
+
clear: () => {
|
|
1704
|
+
commits = [];
|
|
1705
|
+
reset = orderDirty = false;
|
|
1706
|
+
keys.clear();
|
|
1707
|
+
candidates = void 0;
|
|
1708
|
+
},
|
|
1709
|
+
context: (active) => {
|
|
1710
|
+
assertScope(active);
|
|
1711
|
+
if (state.disposed) throw new Error("Document has been disposed.");
|
|
1712
|
+
const read = collection ? readerFor(nodeAt(state.schema, collection.address, state.document) ?? collectionSchema(collection), {
|
|
1713
|
+
root: () => state.document,
|
|
1714
|
+
active
|
|
1715
|
+
}, collection.address) : documentReader(state.schema, () => state.document, active);
|
|
1716
|
+
return Object.freeze({
|
|
1717
|
+
read,
|
|
1718
|
+
target: collection,
|
|
1719
|
+
revision: runtime.revision(),
|
|
1720
|
+
commits: Object.freeze(commits.slice()),
|
|
1721
|
+
reset: record.reset(),
|
|
1722
|
+
...collection ? { candidates: candidates ??= Object.freeze({
|
|
1723
|
+
keys: Object.freeze([...keys]),
|
|
1724
|
+
orderDirty
|
|
1725
|
+
}) } : {}
|
|
1726
|
+
});
|
|
1727
|
+
}
|
|
1728
|
+
};
|
|
1729
|
+
const handle = collection ? {} : {
|
|
1730
|
+
collection: (pick) => {
|
|
1731
|
+
scheduler.assertIdle();
|
|
1732
|
+
const selector = state.schema.collection(pick);
|
|
1733
|
+
return make([selector], selector);
|
|
1734
|
+
},
|
|
1735
|
+
targets: (...selected) => {
|
|
1736
|
+
scheduler.assertIdle();
|
|
1737
|
+
if (!selected.length) throw new TypeError("Expected at least one target.");
|
|
1738
|
+
return make(selected);
|
|
1739
|
+
}
|
|
1740
|
+
};
|
|
1741
|
+
Object.freeze(handle);
|
|
1742
|
+
bindings.push({
|
|
1743
|
+
handle,
|
|
1744
|
+
targets,
|
|
1745
|
+
record
|
|
1746
|
+
});
|
|
1747
|
+
if (collection) collections.add(handle);
|
|
1748
|
+
scheduler.register(handle, record);
|
|
1749
|
+
receivers.set(record, (commit) => {
|
|
1750
|
+
commits.push(commit);
|
|
1751
|
+
reset ||= commit.kind === "replace";
|
|
1752
|
+
if (collection) {
|
|
1753
|
+
const change = commit.impact.collection(collection);
|
|
1754
|
+
if (change.kind === "reset") reset = true;
|
|
1755
|
+
else {
|
|
1756
|
+
change.added.forEach((key) => keys.add(key));
|
|
1757
|
+
change.removed.forEach((key) => keys.add(key));
|
|
1758
|
+
change.updated.forEach((key) => keys.add(key));
|
|
1759
|
+
orderDirty ||= Boolean(change.added.size || change.removed.size || change.orderChanged);
|
|
1700
1760
|
}
|
|
1701
|
-
|
|
1702
|
-
return { update: ({ sources, writer }) => {
|
|
1703
|
-
const input = sources.source;
|
|
1704
|
-
const keys = /* @__PURE__ */ new Set();
|
|
1705
|
-
let structural = false;
|
|
1706
|
-
for (const commit of input.commits) {
|
|
1707
|
-
const impact = commit.impact.collection(input.target);
|
|
1708
|
-
if (impact.kind === "reset") return { kind: "rebuild" };
|
|
1709
|
-
impact.added.forEach((key) => keys.add(key));
|
|
1710
|
-
impact.removed.forEach((key) => keys.add(key));
|
|
1711
|
-
impact.updated.forEach((key) => keys.add(key));
|
|
1712
|
-
structural ||= Boolean(impact.added.size || impact.removed.size || impact.orderChanged);
|
|
1713
|
-
}
|
|
1714
|
-
for (const key of keys) {
|
|
1715
|
-
const entry = input.read.get(key);
|
|
1716
|
-
if (!entry) writer.remove(key);
|
|
1717
|
-
else {
|
|
1718
|
-
require_ownership.profile.collectionView.mapped();
|
|
1719
|
-
writer.set(key, mapper(key, entry));
|
|
1720
|
-
}
|
|
1721
|
-
}
|
|
1722
|
-
if (structural) {
|
|
1723
|
-
const ids = input.read.ids();
|
|
1724
|
-
require_ownership.profile.collectionView.idsScanned(ids.length);
|
|
1725
|
-
writer.order(ids);
|
|
1726
|
-
}
|
|
1727
|
-
} };
|
|
1761
|
+
candidates = void 0;
|
|
1728
1762
|
}
|
|
1729
1763
|
});
|
|
1764
|
+
return handle;
|
|
1765
|
+
};
|
|
1766
|
+
const receivers = /* @__PURE__ */ new Map();
|
|
1767
|
+
const handle = make([]);
|
|
1768
|
+
const guard = (locked) => {
|
|
1769
|
+
state.projectionLocks = (state.projectionLocks ?? 0) + (locked ? 1 : -1);
|
|
1770
|
+
};
|
|
1771
|
+
scheduler.guards.add(guard);
|
|
1772
|
+
const unsubscribe = attachProjection(runtime, {
|
|
1773
|
+
capture: (commit) => {
|
|
1774
|
+
for (const binding of bindings) if (!binding.targets.length || binding.targets.some(commit.impact.affects)) {
|
|
1775
|
+
receivers.get(binding.record)(commit);
|
|
1776
|
+
scheduler.capture(binding.record);
|
|
1777
|
+
}
|
|
1778
|
+
},
|
|
1779
|
+
settle: scheduler.settle,
|
|
1780
|
+
flush: scheduler.flush,
|
|
1781
|
+
dispose: () => {
|
|
1782
|
+
bindings.forEach(({ record }) => {
|
|
1783
|
+
record.fault = new ProjectionError("source", "document disposed", [runtime.revision()], /* @__PURE__ */ new Error("Document has been disposed."));
|
|
1784
|
+
scheduler.capture(record);
|
|
1785
|
+
});
|
|
1786
|
+
scheduler.run();
|
|
1787
|
+
}
|
|
1788
|
+
});
|
|
1789
|
+
scheduler.cleanups.add(() => {
|
|
1790
|
+
unsubscribe();
|
|
1791
|
+
scheduler.guards.delete(guard);
|
|
1792
|
+
});
|
|
1793
|
+
documents.set(state, handle);
|
|
1794
|
+
return handle;
|
|
1795
|
+
};
|
|
1796
|
+
const valueSource = (initial, equal) => {
|
|
1797
|
+
let value = initial;
|
|
1798
|
+
let previous = initial;
|
|
1799
|
+
let revision = 0;
|
|
1800
|
+
const handle = Object.freeze({});
|
|
1801
|
+
const record = {
|
|
1802
|
+
consumers: /* @__PURE__ */ new Set(),
|
|
1803
|
+
disposed: false,
|
|
1804
|
+
fault: void 0,
|
|
1805
|
+
revision: () => revision,
|
|
1806
|
+
reset: () => false,
|
|
1807
|
+
clear: () => {
|
|
1808
|
+
previous = value;
|
|
1809
|
+
},
|
|
1810
|
+
context: (active) => {
|
|
1811
|
+
assertScope(active);
|
|
1812
|
+
return Object.freeze({
|
|
1813
|
+
value,
|
|
1814
|
+
previous,
|
|
1815
|
+
revision,
|
|
1816
|
+
changed: !equal(previous, value),
|
|
1817
|
+
reset: false
|
|
1818
|
+
});
|
|
1819
|
+
}
|
|
1820
|
+
};
|
|
1821
|
+
scheduler.register(handle, record);
|
|
1822
|
+
const accept = (next) => {
|
|
1823
|
+
scheduler.assertIdle();
|
|
1824
|
+
const recovering = record.fault !== void 0;
|
|
1825
|
+
if (equal(value, next) && !recovering) return;
|
|
1826
|
+
record.fault = void 0;
|
|
1827
|
+
value = next;
|
|
1828
|
+
revision++;
|
|
1829
|
+
scheduler.capture(record);
|
|
1830
|
+
};
|
|
1831
|
+
return {
|
|
1832
|
+
source: handle,
|
|
1833
|
+
accept,
|
|
1834
|
+
set(next) {
|
|
1835
|
+
accept(next);
|
|
1836
|
+
scheduler.run();
|
|
1837
|
+
}
|
|
1838
|
+
};
|
|
1839
|
+
};
|
|
1840
|
+
return {
|
|
1841
|
+
dispose: () => {
|
|
1842
|
+
documents.clear();
|
|
1843
|
+
readables.clear();
|
|
1844
|
+
},
|
|
1845
|
+
document,
|
|
1846
|
+
input: (initial, options) => {
|
|
1847
|
+
const { source, set } = valueSource(initial, options?.isEqual ?? Object.is);
|
|
1848
|
+
return Object.freeze({
|
|
1849
|
+
source,
|
|
1850
|
+
set
|
|
1851
|
+
});
|
|
1852
|
+
},
|
|
1853
|
+
fromReadable: (readable, options) => {
|
|
1854
|
+
scheduler.assertIdle();
|
|
1855
|
+
if (projectionHandles.has(readable)) throw new Error("Projection nodes must be declared directly as sources.");
|
|
1856
|
+
const equal = options?.isEqual ?? Object.is;
|
|
1857
|
+
let bindings = readables.get(readable);
|
|
1858
|
+
const old = bindings?.get(equal);
|
|
1859
|
+
if (old) return old.source;
|
|
1860
|
+
const input = valueSource(readable.current(), equal);
|
|
1861
|
+
if (bindings) {
|
|
1862
|
+
bindings.set(equal, {
|
|
1863
|
+
source: input.source,
|
|
1864
|
+
accept: (value) => input.accept(value)
|
|
1865
|
+
});
|
|
1866
|
+
return input.source;
|
|
1867
|
+
}
|
|
1868
|
+
bindings = new Map([[equal, {
|
|
1869
|
+
source: input.source,
|
|
1870
|
+
accept: (value) => input.accept(value)
|
|
1871
|
+
}]]);
|
|
1872
|
+
const members = bindings;
|
|
1873
|
+
const receive = (settle = true) => {
|
|
1874
|
+
if (!scheduler.active) return;
|
|
1875
|
+
let value;
|
|
1876
|
+
try {
|
|
1877
|
+
value = readable.current();
|
|
1878
|
+
} catch (cause) {
|
|
1879
|
+
for (const member of members.values()) {
|
|
1880
|
+
const record = scheduler.source(member.source);
|
|
1881
|
+
record.fault = new ProjectionError("source", "external readable", [record.revision()], cause);
|
|
1882
|
+
scheduler.capture(record);
|
|
1883
|
+
}
|
|
1884
|
+
if (settle) scheduler.run();
|
|
1885
|
+
return;
|
|
1886
|
+
}
|
|
1887
|
+
for (const member of members.values()) try {
|
|
1888
|
+
member.accept(value);
|
|
1889
|
+
} catch (cause) {
|
|
1890
|
+
const record = scheduler.source(member.source);
|
|
1891
|
+
record.fault = new ProjectionError("source", "external readable", [record.revision()], cause);
|
|
1892
|
+
scheduler.capture(record);
|
|
1893
|
+
}
|
|
1894
|
+
if (settle) scheduler.run();
|
|
1895
|
+
};
|
|
1896
|
+
let unsubscribe;
|
|
1897
|
+
let detach;
|
|
1898
|
+
try {
|
|
1899
|
+
const owner = documentReadableOwner(readable);
|
|
1900
|
+
if (owner) {
|
|
1901
|
+
document(owner);
|
|
1902
|
+
detach = attachProjection(owner, {
|
|
1903
|
+
capture: () => receive(false),
|
|
1904
|
+
settle: scheduler.settle,
|
|
1905
|
+
flush: scheduler.flush,
|
|
1906
|
+
dispose: () => {
|
|
1907
|
+
for (const member of members.values()) {
|
|
1908
|
+
const record = scheduler.source(member.source);
|
|
1909
|
+
record.fault = new ProjectionError("source", "document readable disposed", [record.revision()], /* @__PURE__ */ new Error("Document has been disposed."));
|
|
1910
|
+
scheduler.capture(record);
|
|
1911
|
+
}
|
|
1912
|
+
scheduler.run();
|
|
1913
|
+
}
|
|
1914
|
+
});
|
|
1915
|
+
}
|
|
1916
|
+
unsubscribe = readable.subscribe(() => receive());
|
|
1917
|
+
input.accept(readable.current());
|
|
1918
|
+
} catch (error) {
|
|
1919
|
+
try {
|
|
1920
|
+
unsubscribe?.();
|
|
1921
|
+
detach?.();
|
|
1922
|
+
} finally {
|
|
1923
|
+
scheduler.unregisterSource(input.source);
|
|
1924
|
+
}
|
|
1925
|
+
throw error;
|
|
1926
|
+
}
|
|
1927
|
+
scheduler.cleanups.add(unsubscribe);
|
|
1928
|
+
if (detach) scheduler.cleanups.add(detach);
|
|
1929
|
+
readables.set(readable, bindings);
|
|
1930
|
+
scheduler.run();
|
|
1931
|
+
return input.source;
|
|
1932
|
+
},
|
|
1933
|
+
assertCollection: (handle) => {
|
|
1934
|
+
scheduler.source(handle);
|
|
1935
|
+
if (!collections.has(handle) && !collectionHandles.has(handle)) throw new Error("map requires a collection source.");
|
|
1936
|
+
}
|
|
1937
|
+
};
|
|
1938
|
+
};
|
|
1939
|
+
//#endregion
|
|
1940
|
+
//#region core/src/projection/value.ts
|
|
1941
|
+
const createValue = (scheduler, spec, options) => {
|
|
1942
|
+
let instance;
|
|
1943
|
+
let value;
|
|
1944
|
+
let next;
|
|
1945
|
+
let previous;
|
|
1946
|
+
let initialized = false;
|
|
1947
|
+
let revision = 0;
|
|
1948
|
+
let changed = false;
|
|
1949
|
+
let reset = false;
|
|
1950
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
1951
|
+
const owner = createNode(scheduler, spec, {
|
|
1952
|
+
evaluate: (sources, build) => {
|
|
1953
|
+
let candidate;
|
|
1954
|
+
if (build || !instance) {
|
|
1955
|
+
require_ownership.profile.materialized.rebuilt();
|
|
1956
|
+
instance = void 0;
|
|
1957
|
+
const built = spec.build(sources);
|
|
1958
|
+
assertSynchronous(built);
|
|
1959
|
+
instance = built;
|
|
1960
|
+
candidate = built.value;
|
|
1961
|
+
} else {
|
|
1962
|
+
require_ownership.profile.materialized.updated();
|
|
1963
|
+
const result = instance.update(sources);
|
|
1964
|
+
assertSynchronous(result);
|
|
1965
|
+
if (result.kind === "rebuild") {
|
|
1966
|
+
instance = void 0;
|
|
1967
|
+
const built = spec.build(sources);
|
|
1968
|
+
assertSynchronous(built);
|
|
1969
|
+
instance = built;
|
|
1970
|
+
candidate = built.value;
|
|
1971
|
+
build = true;
|
|
1972
|
+
} else candidate = result.kind === "changed" ? result.value : value;
|
|
1973
|
+
}
|
|
1974
|
+
previous = value;
|
|
1975
|
+
changed = !initialized || !(options?.isEqual ?? Object.is)(value, candidate);
|
|
1976
|
+
next = changed ? candidate : value;
|
|
1977
|
+
reset = build;
|
|
1978
|
+
return changed;
|
|
1979
|
+
},
|
|
1980
|
+
context: (active) => {
|
|
1981
|
+
assertScope(active);
|
|
1982
|
+
return Object.freeze({
|
|
1983
|
+
value: next,
|
|
1984
|
+
previous,
|
|
1985
|
+
changed,
|
|
1986
|
+
revision: revision + (changed ? 1 : 0),
|
|
1987
|
+
reset
|
|
1988
|
+
});
|
|
1730
1989
|
},
|
|
1990
|
+
revision: () => revision,
|
|
1991
|
+
reset: () => reset,
|
|
1992
|
+
publish: () => {
|
|
1993
|
+
if (changed && initialized) revision++;
|
|
1994
|
+
value = next;
|
|
1995
|
+
initialized = true;
|
|
1996
|
+
},
|
|
1997
|
+
emit: (call) => {
|
|
1998
|
+
require_ownership.profile.materialized.notification();
|
|
1999
|
+
Array.from(listeners).forEach((listener) => call(listener));
|
|
2000
|
+
},
|
|
2001
|
+
clear: () => {
|
|
2002
|
+
next = value;
|
|
2003
|
+
previous = value;
|
|
2004
|
+
changed = false;
|
|
2005
|
+
reset = false;
|
|
2006
|
+
},
|
|
2007
|
+
release: () => {
|
|
2008
|
+
listeners.clear();
|
|
2009
|
+
instance = void 0;
|
|
2010
|
+
value = next = previous = void 0;
|
|
2011
|
+
}
|
|
2012
|
+
});
|
|
2013
|
+
const handle = Object.freeze({
|
|
2014
|
+
current: () => {
|
|
2015
|
+
owner.check();
|
|
2016
|
+
return value;
|
|
2017
|
+
},
|
|
2018
|
+
revision: () => {
|
|
2019
|
+
owner.check();
|
|
2020
|
+
return revision;
|
|
2021
|
+
},
|
|
2022
|
+
subscribe: (listener) => {
|
|
2023
|
+
owner.check();
|
|
2024
|
+
listeners.add(listener);
|
|
2025
|
+
return () => {
|
|
2026
|
+
listeners.delete(listener);
|
|
2027
|
+
};
|
|
2028
|
+
},
|
|
2029
|
+
rebuild: owner.rebuild,
|
|
2030
|
+
dispose: owner.dispose
|
|
2031
|
+
});
|
|
2032
|
+
owner.install(handle);
|
|
2033
|
+
return handle;
|
|
2034
|
+
};
|
|
2035
|
+
//#endregion
|
|
2036
|
+
//#region core/src/projection/runtime.ts
|
|
2037
|
+
const debug = /* @__PURE__ */ new WeakMap();
|
|
2038
|
+
const projectionDebug = (runtime) => {
|
|
2039
|
+
const read = debug.get(runtime);
|
|
2040
|
+
if (!read) throw new Error("Unknown projection runtime.");
|
|
2041
|
+
return Object.freeze(read());
|
|
2042
|
+
};
|
|
2043
|
+
const createProjectionRuntime = (options) => {
|
|
2044
|
+
const scheduler = createScheduler(options.onError);
|
|
2045
|
+
const sources = createSources(scheduler);
|
|
2046
|
+
function value(input, computeOrOptions, options) {
|
|
2047
|
+
if (typeof computeOrOptions !== "function") return createValue(scheduler, input, computeOrOptions);
|
|
2048
|
+
const compute = (input) => {
|
|
2049
|
+
const result = computeOrOptions(input);
|
|
2050
|
+
assertSynchronous(result);
|
|
2051
|
+
return result;
|
|
2052
|
+
};
|
|
2053
|
+
return createValue(scheduler, {
|
|
2054
|
+
sources: input,
|
|
2055
|
+
build: (input) => ({
|
|
2056
|
+
value: compute(input),
|
|
2057
|
+
update: (input) => ({
|
|
2058
|
+
kind: "changed",
|
|
2059
|
+
value: compute(input)
|
|
2060
|
+
})
|
|
2061
|
+
})
|
|
2062
|
+
}, options);
|
|
2063
|
+
}
|
|
2064
|
+
const map = (source, mapper, options) => {
|
|
2065
|
+
sources.assertCollection(source);
|
|
2066
|
+
const calculate = (id, entry) => {
|
|
2067
|
+
const value = mapper(id, entry);
|
|
2068
|
+
assertSynchronous(value);
|
|
2069
|
+
return value;
|
|
2070
|
+
};
|
|
2071
|
+
return createCollection(scheduler, {
|
|
2072
|
+
sources: { source },
|
|
2073
|
+
isEqual: options?.isEqual,
|
|
2074
|
+
build: ({ sources, writer }) => {
|
|
2075
|
+
const input = sources.source;
|
|
2076
|
+
const read = "read" in input ? input.read : input;
|
|
2077
|
+
const ids = read.ids();
|
|
2078
|
+
require_ownership.profile.collectionView.idsScanned(ids.length);
|
|
2079
|
+
for (const id of ids) {
|
|
2080
|
+
require_ownership.profile.collectionView.mapped();
|
|
2081
|
+
writer.set(id, calculate(id, read.get(id)));
|
|
2082
|
+
}
|
|
2083
|
+
writer.order(ids);
|
|
2084
|
+
return { update: ({ sources, writer }) => {
|
|
2085
|
+
const input = sources.source;
|
|
2086
|
+
if (input.reset) return { kind: "rebuild" };
|
|
2087
|
+
const read = "read" in input ? input.read : input;
|
|
2088
|
+
let keys;
|
|
2089
|
+
let structural;
|
|
2090
|
+
if ("candidates" in input) {
|
|
2091
|
+
keys = input.candidates.keys;
|
|
2092
|
+
structural = input.candidates.orderDirty;
|
|
2093
|
+
} else {
|
|
2094
|
+
const change = input.change;
|
|
2095
|
+
if (!change) return;
|
|
2096
|
+
if (change.kind === "reset") return { kind: "rebuild" };
|
|
2097
|
+
keys = new Set([
|
|
2098
|
+
...change.added,
|
|
2099
|
+
...change.removed,
|
|
2100
|
+
...change.updated
|
|
2101
|
+
]);
|
|
2102
|
+
structural = Boolean(change.added.size || change.removed.size || change.orderChanged);
|
|
2103
|
+
}
|
|
2104
|
+
for (const key of keys) if (!read.has(key)) writer.remove(key);
|
|
2105
|
+
else {
|
|
2106
|
+
require_ownership.profile.collectionView.mapped();
|
|
2107
|
+
writer.set(key, calculate(key, read.get(key)));
|
|
2108
|
+
}
|
|
2109
|
+
if (structural) {
|
|
2110
|
+
const ids = read.ids();
|
|
2111
|
+
require_ownership.profile.collectionView.idsScanned(ids.length);
|
|
2112
|
+
writer.order(ids);
|
|
2113
|
+
}
|
|
2114
|
+
} };
|
|
2115
|
+
}
|
|
2116
|
+
});
|
|
2117
|
+
};
|
|
2118
|
+
const runtime = {
|
|
2119
|
+
document: sources.document,
|
|
2120
|
+
input: sources.input,
|
|
2121
|
+
fromReadable: sources.fromReadable,
|
|
2122
|
+
value,
|
|
2123
|
+
collection: () => (spec) => createCollection(scheduler, spec),
|
|
2124
|
+
map,
|
|
1731
2125
|
batch: scheduler.batch,
|
|
1732
2126
|
dispose: () => {
|
|
1733
2127
|
try {
|
|
@@ -1774,7 +2168,19 @@ Object.defineProperty(exports, "accessOf", {
|
|
|
1774
2168
|
Object.defineProperty(exports, "address", {
|
|
1775
2169
|
enumerable: true,
|
|
1776
2170
|
get: function() {
|
|
1777
|
-
return address;
|
|
2171
|
+
return address$1;
|
|
2172
|
+
}
|
|
2173
|
+
});
|
|
2174
|
+
Object.defineProperty(exports, "afterRemove", {
|
|
2175
|
+
enumerable: true,
|
|
2176
|
+
get: function() {
|
|
2177
|
+
return afterRemove;
|
|
2178
|
+
}
|
|
2179
|
+
});
|
|
2180
|
+
Object.defineProperty(exports, "at", {
|
|
2181
|
+
enumerable: true,
|
|
2182
|
+
get: function() {
|
|
2183
|
+
return at;
|
|
1778
2184
|
}
|
|
1779
2185
|
});
|
|
1780
2186
|
Object.defineProperty(exports, "belongs", {
|
|
@@ -1783,12 +2189,24 @@ Object.defineProperty(exports, "belongs", {
|
|
|
1783
2189
|
return belongs;
|
|
1784
2190
|
}
|
|
1785
2191
|
});
|
|
2192
|
+
Object.defineProperty(exports, "bindDocumentReadable", {
|
|
2193
|
+
enumerable: true,
|
|
2194
|
+
get: function() {
|
|
2195
|
+
return bindDocumentReadable;
|
|
2196
|
+
}
|
|
2197
|
+
});
|
|
1786
2198
|
Object.defineProperty(exports, "bindRuntimeAccess", {
|
|
1787
2199
|
enumerable: true,
|
|
1788
2200
|
get: function() {
|
|
1789
2201
|
return bindRuntimeAccess;
|
|
1790
2202
|
}
|
|
1791
2203
|
});
|
|
2204
|
+
Object.defineProperty(exports, "commandFootprint", {
|
|
2205
|
+
enumerable: true,
|
|
2206
|
+
get: function() {
|
|
2207
|
+
return commandFootprint;
|
|
2208
|
+
}
|
|
2209
|
+
});
|
|
1792
2210
|
Object.defineProperty(exports, "contains", {
|
|
1793
2211
|
enumerable: true,
|
|
1794
2212
|
get: function() {
|
|
@@ -1813,6 +2231,12 @@ Object.defineProperty(exports, "debugKey", {
|
|
|
1813
2231
|
return debugKey;
|
|
1814
2232
|
}
|
|
1815
2233
|
});
|
|
2234
|
+
Object.defineProperty(exports, "decodeCommandFootprint", {
|
|
2235
|
+
enumerable: true,
|
|
2236
|
+
get: function() {
|
|
2237
|
+
return decodeCommandFootprint;
|
|
2238
|
+
}
|
|
2239
|
+
});
|
|
1816
2240
|
Object.defineProperty(exports, "dict", {
|
|
1817
2241
|
enumerable: true,
|
|
1818
2242
|
get: function() {
|
|
@@ -1837,6 +2261,12 @@ Object.defineProperty(exports, "field", {
|
|
|
1837
2261
|
return field;
|
|
1838
2262
|
}
|
|
1839
2263
|
});
|
|
2264
|
+
Object.defineProperty(exports, "footprintsOverlap", {
|
|
2265
|
+
enumerable: true,
|
|
2266
|
+
get: function() {
|
|
2267
|
+
return footprintsOverlap;
|
|
2268
|
+
}
|
|
2269
|
+
});
|
|
1840
2270
|
Object.defineProperty(exports, "id", {
|
|
1841
2271
|
enumerable: true,
|
|
1842
2272
|
get: function() {
|
|
@@ -1849,6 +2279,18 @@ Object.defineProperty(exports, "impact_target_exports", {
|
|
|
1849
2279
|
return impact_target_exports;
|
|
1850
2280
|
}
|
|
1851
2281
|
});
|
|
2282
|
+
Object.defineProperty(exports, "index", {
|
|
2283
|
+
enumerable: true,
|
|
2284
|
+
get: function() {
|
|
2285
|
+
return index;
|
|
2286
|
+
}
|
|
2287
|
+
});
|
|
2288
|
+
Object.defineProperty(exports, "keys", {
|
|
2289
|
+
enumerable: true,
|
|
2290
|
+
get: function() {
|
|
2291
|
+
return keys;
|
|
2292
|
+
}
|
|
2293
|
+
});
|
|
1852
2294
|
Object.defineProperty(exports, "list", {
|
|
1853
2295
|
enumerable: true,
|
|
1854
2296
|
get: function() {
|
|
@@ -1909,12 +2351,6 @@ Object.defineProperty(exports, "readWith", {
|
|
|
1909
2351
|
return readWith;
|
|
1910
2352
|
}
|
|
1911
2353
|
});
|
|
1912
|
-
Object.defineProperty(exports, "record", {
|
|
1913
|
-
enumerable: true,
|
|
1914
|
-
get: function() {
|
|
1915
|
-
return record;
|
|
1916
|
-
}
|
|
1917
|
-
});
|
|
1918
2354
|
Object.defineProperty(exports, "resolveAddress", {
|
|
1919
2355
|
enumerable: true,
|
|
1920
2356
|
get: function() {
|
|
@@ -1927,6 +2363,12 @@ Object.defineProperty(exports, "resolveLocated", {
|
|
|
1927
2363
|
return resolveLocated;
|
|
1928
2364
|
}
|
|
1929
2365
|
});
|
|
2366
|
+
Object.defineProperty(exports, "restore", {
|
|
2367
|
+
enumerable: true,
|
|
2368
|
+
get: function() {
|
|
2369
|
+
return restore;
|
|
2370
|
+
}
|
|
2371
|
+
});
|
|
1930
2372
|
Object.defineProperty(exports, "same", {
|
|
1931
2373
|
enumerable: true,
|
|
1932
2374
|
get: function() {
|
|
@@ -1951,12 +2393,6 @@ Object.defineProperty(exports, "shareNotification", {
|
|
|
1951
2393
|
return shareNotification;
|
|
1952
2394
|
}
|
|
1953
2395
|
});
|
|
1954
|
-
Object.defineProperty(exports, "single", {
|
|
1955
|
-
enumerable: true,
|
|
1956
|
-
get: function() {
|
|
1957
|
-
return single;
|
|
1958
|
-
}
|
|
1959
|
-
});
|
|
1960
2396
|
Object.defineProperty(exports, "subscribeRoot", {
|
|
1961
2397
|
enumerable: true,
|
|
1962
2398
|
get: function() {
|
|
@@ -1981,6 +2417,18 @@ Object.defineProperty(exports, "tree", {
|
|
|
1981
2417
|
return tree;
|
|
1982
2418
|
}
|
|
1983
2419
|
});
|
|
2420
|
+
Object.defineProperty(exports, "valid", {
|
|
2421
|
+
enumerable: true,
|
|
2422
|
+
get: function() {
|
|
2423
|
+
return valid;
|
|
2424
|
+
}
|
|
2425
|
+
});
|
|
2426
|
+
Object.defineProperty(exports, "validPositions", {
|
|
2427
|
+
enumerable: true,
|
|
2428
|
+
get: function() {
|
|
2429
|
+
return validPositions;
|
|
2430
|
+
}
|
|
2431
|
+
});
|
|
1984
2432
|
Object.defineProperty(exports, "variant", {
|
|
1985
2433
|
enumerable: true,
|
|
1986
2434
|
get: function() {
|
|
@@ -1988,4 +2436,4 @@ Object.defineProperty(exports, "variant", {
|
|
|
1988
2436
|
}
|
|
1989
2437
|
});
|
|
1990
2438
|
|
|
1991
|
-
//# sourceMappingURL=runtime-
|
|
2439
|
+
//# sourceMappingURL=runtime-0mOFbe_H.cjs.map
|