doxum 0.1.26 → 0.1.28
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 +86 -3
- package/dist/advanced.cjs +40 -30
- package/dist/advanced.cjs.map +1 -1
- package/dist/advanced.d.cts +34 -2
- package/dist/advanced.d.ts +34 -2
- package/dist/advanced.js +31 -22
- package/dist/advanced.js.map +1 -1
- package/dist/{definition-xgk3YNBp.d.ts → dependency-B3E65M1E.d.cts} +27 -3
- package/dist/{definition-CDOuvb5C.d.cts → dependency-BYbdDHNa.d.ts} +27 -3
- package/dist/driver-B5vdPohL.js.map +1 -1
- package/dist/driver-BL91gn7_.cjs.map +1 -1
- package/dist/index.cjs +885 -394
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +33 -18
- package/dist/index.d.ts +33 -18
- package/dist/index.js +784 -293
- package/dist/index.js.map +1 -1
- package/dist/local-sync.cjs.map +1 -1
- package/dist/local-sync.js.map +1 -1
- package/dist/transform-B4T3AcJr.js +938 -0
- package/dist/transform-B4T3AcJr.js.map +1 -0
- package/dist/transform-DUleAsG0.cjs +1105 -0
- package/dist/transform-DUleAsG0.cjs.map +1 -0
- package/package.json +1 -1
- package/skills/doxum-runtime/SKILL.md +16 -6
- package/skills/doxum-runtime/references/api.en.md +49 -15
- package/skills/doxum-runtime/references/api.zh-CN.md +47 -13
- package/skills/doxum-runtime/references/guide.en.md +2 -1
- package/skills/doxum-runtime/references/guide.zh-CN.md +2 -1
- package/skills/doxum-runtime/references/invariants.en.md +2 -2
- package/skills/doxum-runtime/references/invariants.zh-CN.md +2 -2
- package/skills/doxum-runtime/references/patterns.en.md +1 -1
- package/skills/doxum-runtime/references/patterns.zh-CN.md +1 -1
- package/skills/doxum-runtime/references/projections.en.md +77 -4
- package/skills/doxum-runtime/references/projections.zh-CN.md +74 -3
- package/dist/scheduler--137L3j-.js +0 -500
- package/dist/scheduler--137L3j-.js.map +0 -1
- package/dist/scheduler-D4VthaaK.cjs +0 -589
- package/dist/scheduler-D4VthaaK.cjs.map +0 -1
|
@@ -0,0 +1,1105 @@
|
|
|
1
|
+
const require_record = require("./record-ChYUi8PP.cjs");
|
|
2
|
+
const profile = {
|
|
3
|
+
projection: (key, amount = 1) => {},
|
|
4
|
+
recorder: (key, amount = 1) => {},
|
|
5
|
+
access: (key) => {},
|
|
6
|
+
copy: {
|
|
7
|
+
structure: () => {},
|
|
8
|
+
treeNode: () => {},
|
|
9
|
+
shallowRecord: (items) => {}
|
|
10
|
+
},
|
|
11
|
+
equality: {
|
|
12
|
+
call: () => {},
|
|
13
|
+
container: () => {}
|
|
14
|
+
},
|
|
15
|
+
address: {
|
|
16
|
+
listIndex: (items) => {},
|
|
17
|
+
schemaStep: () => {},
|
|
18
|
+
documentStep: () => {},
|
|
19
|
+
prefixComparison: () => {},
|
|
20
|
+
segmentCompared: () => {}
|
|
21
|
+
},
|
|
22
|
+
impact: {
|
|
23
|
+
index: () => {},
|
|
24
|
+
affects: () => {}
|
|
25
|
+
},
|
|
26
|
+
dependency: {
|
|
27
|
+
comparison: () => {},
|
|
28
|
+
segmentCompared: () => {}
|
|
29
|
+
},
|
|
30
|
+
collectionIndex: {
|
|
31
|
+
node: () => {},
|
|
32
|
+
build: (items) => {}
|
|
33
|
+
},
|
|
34
|
+
collectionView: {
|
|
35
|
+
mapped: () => {},
|
|
36
|
+
idsScanned: (amount = 1) => {},
|
|
37
|
+
arrayCopied: () => {}
|
|
38
|
+
},
|
|
39
|
+
materialized: {
|
|
40
|
+
updated: () => {},
|
|
41
|
+
rebuilt: () => {},
|
|
42
|
+
notification: () => {}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
//#endregion
|
|
46
|
+
//#region core/src/projection/definition.ts
|
|
47
|
+
const projections = /* @__PURE__ */ new WeakMap();
|
|
48
|
+
const defineRef = (producer, output) => {
|
|
49
|
+
const handle = Object.freeze({});
|
|
50
|
+
projections.set(handle, Object.freeze({
|
|
51
|
+
producer,
|
|
52
|
+
output
|
|
53
|
+
}));
|
|
54
|
+
return handle;
|
|
55
|
+
};
|
|
56
|
+
const projectionRef = (projection) => {
|
|
57
|
+
const ref = projections.get(projection);
|
|
58
|
+
if (!ref) throw new TypeError("Unknown projection definition.");
|
|
59
|
+
return ref;
|
|
60
|
+
};
|
|
61
|
+
const producerOf = (projection) => projectionRef(projection).producer;
|
|
62
|
+
/** Resolves the immutable output description owned by a projection definition. */
|
|
63
|
+
const outputDefinitionOf = (projection) => {
|
|
64
|
+
const ref = projectionRef(projection);
|
|
65
|
+
const producer = ref.producer;
|
|
66
|
+
const output = producer.kind === "source" ? producer.output : producer.outputs[ref.output];
|
|
67
|
+
if (!output) throw new TypeError("Projection output does not exist.");
|
|
68
|
+
return output;
|
|
69
|
+
};
|
|
70
|
+
const isProjection = (value) => value !== null && typeof value === "object" && projections.has(value);
|
|
71
|
+
const ownProjections = (projections, owner) => {
|
|
72
|
+
const producers = new Set(projections.map(producerOf));
|
|
73
|
+
for (const producer of producers) {
|
|
74
|
+
if (producer.owner !== void 0 && producer.owner !== owner) throw new TypeError("Projection producer already belongs to another scope.");
|
|
75
|
+
if (producer.owner === void 0 && producer.materialized) throw new TypeError("A materialized root projection cannot become scope-owned.");
|
|
76
|
+
if (producer.kind !== "processor") continue;
|
|
77
|
+
for (const dependency of producer.dependencies) {
|
|
78
|
+
const dependencyOwner = producerOf(dependency).owner;
|
|
79
|
+
if (dependencyOwner !== void 0 && dependencyOwner !== owner) throw new TypeError("A scope cannot depend on another scope.");
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
for (const producer of producers) producer.owner = owner;
|
|
83
|
+
};
|
|
84
|
+
const freezeOutput = (output) => Object.freeze({
|
|
85
|
+
kind: output.kind,
|
|
86
|
+
equality: output.equality,
|
|
87
|
+
...output.path ? { path: Object.freeze([...output.path]) } : {}
|
|
88
|
+
});
|
|
89
|
+
const defineProcessor = (definition) => {
|
|
90
|
+
if (!Array.isArray(definition.dependencies)) throw new TypeError("Projection dependencies must be an array.");
|
|
91
|
+
definition.dependencies.forEach(projectionRef);
|
|
92
|
+
if (!definition.outputs.length) throw new TypeError("Projection processor requires an output.");
|
|
93
|
+
const producer = {
|
|
94
|
+
kind: "processor",
|
|
95
|
+
dependencies: Object.freeze([...definition.dependencies]),
|
|
96
|
+
outputs: Object.freeze(definition.outputs.map(freezeOutput)),
|
|
97
|
+
create: definition.create,
|
|
98
|
+
...definition.name ? { name: definition.name } : {}
|
|
99
|
+
};
|
|
100
|
+
return Object.freeze(producer.outputs.map((_, output) => defineRef(producer, output)));
|
|
101
|
+
};
|
|
102
|
+
const defineSource = (source, output) => {
|
|
103
|
+
return defineRef({
|
|
104
|
+
kind: "source",
|
|
105
|
+
source,
|
|
106
|
+
output: freezeOutput(output)
|
|
107
|
+
}, 0);
|
|
108
|
+
};
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region core/src/projection/collection/view.ts
|
|
111
|
+
const mapRead = (value) => ({
|
|
112
|
+
get: (key) => value.get(key),
|
|
113
|
+
has: (key) => value.has(key),
|
|
114
|
+
ids: () => Object.freeze([...value.keys()])
|
|
115
|
+
});
|
|
116
|
+
/** Immutable map-like view over a CollectionRead. */
|
|
117
|
+
const collectionView = (read) => {
|
|
118
|
+
const ids = read.ids();
|
|
119
|
+
const entries = function* () {
|
|
120
|
+
for (const key of ids) yield [key, read.get(key)];
|
|
121
|
+
};
|
|
122
|
+
const values = function* () {
|
|
123
|
+
for (const key of ids) yield read.get(key);
|
|
124
|
+
};
|
|
125
|
+
const view = {
|
|
126
|
+
get: (key) => read.get(key),
|
|
127
|
+
has: (key) => read.has(key),
|
|
128
|
+
get size() {
|
|
129
|
+
return ids.length;
|
|
130
|
+
},
|
|
131
|
+
keys: () => ids[Symbol.iterator](),
|
|
132
|
+
values,
|
|
133
|
+
entries,
|
|
134
|
+
forEach: (callback, thisArg) => {
|
|
135
|
+
for (const key of ids) callback.call(thisArg, read.get(key), key, view);
|
|
136
|
+
},
|
|
137
|
+
[Symbol.iterator]: entries
|
|
138
|
+
};
|
|
139
|
+
return Object.freeze(view);
|
|
140
|
+
};
|
|
141
|
+
/** Eager durable view used when a processor result may retain its dependency value. */
|
|
142
|
+
const snapshotCollectionView = (read) => {
|
|
143
|
+
const ids = read.ids();
|
|
144
|
+
const values = /* @__PURE__ */ new Map();
|
|
145
|
+
for (const key of ids) values.set(key, read.get(key));
|
|
146
|
+
return collectionView(mapRead(values));
|
|
147
|
+
};
|
|
148
|
+
//#endregion
|
|
149
|
+
//#region core/src/projection/dependency.ts
|
|
150
|
+
/** Owns validation of the shared named dependency object shape. */
|
|
151
|
+
const readNamedDependencyEntries = (dependencies, label) => {
|
|
152
|
+
if (!require_record.isPlainObject(dependencies) || isProjection(dependencies)) throw new TypeError(`${label} dependencies must be a plain object.`);
|
|
153
|
+
const entries = [];
|
|
154
|
+
for (const name of Reflect.ownKeys(dependencies)) {
|
|
155
|
+
if (typeof name !== "string") throw new TypeError(`${label} dependency names must be strings.`);
|
|
156
|
+
const descriptor = Object.getOwnPropertyDescriptor(dependencies, name);
|
|
157
|
+
if (!descriptor?.enumerable || !("value" in descriptor)) throw new TypeError(`${label} dependencies must be enumerable data properties.`);
|
|
158
|
+
entries.push(Object.freeze({
|
|
159
|
+
name,
|
|
160
|
+
value: descriptor.value
|
|
161
|
+
}));
|
|
162
|
+
}
|
|
163
|
+
return Object.freeze(entries);
|
|
164
|
+
};
|
|
165
|
+
/** Creates the durable dependency value exposed to pure derive callbacks. */
|
|
166
|
+
const snapshotDependencyValue = (source) => source.kind === "value" ? source.value : snapshotCollectionView(source.read);
|
|
167
|
+
/** Compiles the shared named Projection dependency declaration contract. */
|
|
168
|
+
const compileProjectionDependencies = (dependencies, label) => {
|
|
169
|
+
const names = [];
|
|
170
|
+
const projections = [];
|
|
171
|
+
for (const { name, value } of readNamedDependencyEntries(dependencies, label)) {
|
|
172
|
+
const projection = value;
|
|
173
|
+
projectionRef(projection);
|
|
174
|
+
names.push(name);
|
|
175
|
+
projections.push(projection);
|
|
176
|
+
}
|
|
177
|
+
return Object.freeze({
|
|
178
|
+
names: Object.freeze(names),
|
|
179
|
+
projections: Object.freeze(projections)
|
|
180
|
+
});
|
|
181
|
+
};
|
|
182
|
+
//#endregion
|
|
183
|
+
//#region core/src/projection/collection/change.ts
|
|
184
|
+
const commonOrderChanged = (before, after, added, removed) => {
|
|
185
|
+
const beforeCommon = before.filter((key) => !removed.has(key));
|
|
186
|
+
const afterCommon = after.filter((key) => !added.has(key));
|
|
187
|
+
return beforeCommon.some((key, index) => afterCommon[index] !== key);
|
|
188
|
+
};
|
|
189
|
+
/** Builds the canonical incremental CollectionChange from already-known net transitions. */
|
|
190
|
+
const createCollectionChange = (input) => {
|
|
191
|
+
const addedKeys = new Set(input.added.map((entry) => entry.key));
|
|
192
|
+
const removedKeys = new Set(input.removed.map((entry) => entry.key));
|
|
193
|
+
const orderChanged = input.beforeOrder !== input.afterOrder && commonOrderChanged(input.beforeOrder, input.afterOrder, addedKeys, removedKeys);
|
|
194
|
+
if (!input.added.length && !input.updated.length && !input.removed.length && !orderChanged) return void 0;
|
|
195
|
+
return Object.freeze({
|
|
196
|
+
kind: "incremental",
|
|
197
|
+
added: Object.freeze([...input.added]),
|
|
198
|
+
updated: Object.freeze([...input.updated]),
|
|
199
|
+
removed: Object.freeze([...input.removed]),
|
|
200
|
+
...orderChanged ? { order: Object.freeze({
|
|
201
|
+
before: Object.freeze([...input.beforeOrder]),
|
|
202
|
+
after: Object.freeze([...input.afterOrder])
|
|
203
|
+
}) } : {}
|
|
204
|
+
});
|
|
205
|
+
};
|
|
206
|
+
/** Exact fallback diff between two published map-like snapshots. */
|
|
207
|
+
const diffCollection = (previous, current, isEqual = Object.is) => {
|
|
208
|
+
const added = [];
|
|
209
|
+
const updated = [];
|
|
210
|
+
const removed = [];
|
|
211
|
+
for (const [key, before] of previous) if (!current.has(key)) removed.push({
|
|
212
|
+
key,
|
|
213
|
+
before
|
|
214
|
+
});
|
|
215
|
+
else {
|
|
216
|
+
const after = current.get(key);
|
|
217
|
+
if (!isEqual(before, after)) updated.push({
|
|
218
|
+
key,
|
|
219
|
+
before,
|
|
220
|
+
after
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
for (const [key, after] of current) if (!previous.has(key)) added.push({
|
|
224
|
+
key,
|
|
225
|
+
after
|
|
226
|
+
});
|
|
227
|
+
return createCollectionChange({
|
|
228
|
+
added,
|
|
229
|
+
updated,
|
|
230
|
+
removed,
|
|
231
|
+
beforeOrder: [...previous.keys()],
|
|
232
|
+
afterOrder: [...current.keys()]
|
|
233
|
+
});
|
|
234
|
+
};
|
|
235
|
+
const changedKeys = function* (change) {
|
|
236
|
+
if (change.kind !== "incremental") throw new TypeError("collectionChange.keys requires an incremental CollectionChange.");
|
|
237
|
+
for (const entry of change.added) yield entry.key;
|
|
238
|
+
for (const entry of change.updated) yield entry.key;
|
|
239
|
+
for (const entry of change.removed) yield entry.key;
|
|
240
|
+
};
|
|
241
|
+
const collectionChange = Object.freeze({ keys: changedKeys });
|
|
242
|
+
const collectionHasStructuralChange = (change) => change.kind === "reset" || Boolean(change.added.length || change.removed.length || change.order);
|
|
243
|
+
//#endregion
|
|
244
|
+
//#region core/src/projection/contract.ts
|
|
245
|
+
var ProjectionError = class extends Error {
|
|
246
|
+
cause;
|
|
247
|
+
constructor(phase, cause) {
|
|
248
|
+
super(`Projection ${phase} failed.`, { cause });
|
|
249
|
+
this.phase = phase;
|
|
250
|
+
this.name = "ProjectionError";
|
|
251
|
+
this.cause = cause;
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
var ProjectionDisposedError = class extends Error {
|
|
255
|
+
constructor() {
|
|
256
|
+
super("Projection has been disposed.");
|
|
257
|
+
this.name = "ProjectionDisposedError";
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
//#endregion
|
|
261
|
+
//#region core/src/projection/graph/scheduler.ts
|
|
262
|
+
const createScheduler = (onError) => {
|
|
263
|
+
let disposed = false;
|
|
264
|
+
let depth = 0;
|
|
265
|
+
let batchSequence = 0;
|
|
266
|
+
let activeBatch;
|
|
267
|
+
let phase = "idle";
|
|
268
|
+
let sequence = 0;
|
|
269
|
+
const sources = /* @__PURE__ */ new Set();
|
|
270
|
+
const processors = /* @__PURE__ */ new Set();
|
|
271
|
+
const pendingSources = /* @__PURE__ */ new Set();
|
|
272
|
+
const heap = [];
|
|
273
|
+
const queued = /* @__PURE__ */ new Set();
|
|
274
|
+
const completed = /* @__PURE__ */ new Set();
|
|
275
|
+
const emissions = /* @__PURE__ */ new Set();
|
|
276
|
+
const errors = [];
|
|
277
|
+
let reportingFailures = [];
|
|
278
|
+
const guards = /* @__PURE__ */ new Set();
|
|
279
|
+
const assertActive = () => {
|
|
280
|
+
if (disposed) throw new ProjectionDisposedError();
|
|
281
|
+
};
|
|
282
|
+
const assertIdle = () => {
|
|
283
|
+
assertActive();
|
|
284
|
+
if (phase !== "idle") throw new Error("Projection cannot be re-entered during processing or notification.");
|
|
285
|
+
};
|
|
286
|
+
const lock = (value) => guards.forEach((guard) => guard(value));
|
|
287
|
+
const enqueue = (processor) => {
|
|
288
|
+
if (processor.disposed || queued.has(processor)) return;
|
|
289
|
+
queued.add(processor);
|
|
290
|
+
profile.projection("scheduledNodes");
|
|
291
|
+
let index = heap.length;
|
|
292
|
+
heap.push(processor);
|
|
293
|
+
while (index > 0) {
|
|
294
|
+
const parent = index - 1 >> 1;
|
|
295
|
+
if (heap[parent].order < processor.order) break;
|
|
296
|
+
heap[index] = heap[parent];
|
|
297
|
+
index = parent;
|
|
298
|
+
}
|
|
299
|
+
heap[index] = processor;
|
|
300
|
+
};
|
|
301
|
+
const pop = () => {
|
|
302
|
+
const first = heap[0];
|
|
303
|
+
const last = heap.pop();
|
|
304
|
+
if (heap.length) {
|
|
305
|
+
let index = 0;
|
|
306
|
+
while (index * 2 + 1 < heap.length) {
|
|
307
|
+
let child = index * 2 + 1;
|
|
308
|
+
if (child + 1 < heap.length && heap[child + 1].order < heap[child].order) child++;
|
|
309
|
+
if (last.order < heap[child].order) break;
|
|
310
|
+
heap[index] = heap[child];
|
|
311
|
+
index = child;
|
|
312
|
+
}
|
|
313
|
+
heap[index] = last;
|
|
314
|
+
}
|
|
315
|
+
return first;
|
|
316
|
+
};
|
|
317
|
+
const errorFor = (producer, cause, kind = producer.kind === "source" ? "source" : "processor") => new ProjectionError(kind, cause);
|
|
318
|
+
const capture = (source) => {
|
|
319
|
+
if (disposed) return;
|
|
320
|
+
if (phase !== "idle") {
|
|
321
|
+
source.fault = errorFor(source, /* @__PURE__ */ new Error("Source changed while projection was running."), "source");
|
|
322
|
+
errors.push(source.fault);
|
|
323
|
+
throw source.fault;
|
|
324
|
+
}
|
|
325
|
+
pendingSources.add(source);
|
|
326
|
+
profile.projection("sourceEvents");
|
|
327
|
+
if (source.fault) errors.push(source.fault);
|
|
328
|
+
};
|
|
329
|
+
const settleCause = () => {
|
|
330
|
+
if (activeBatch?.cause !== void 0) return activeBatch.cause;
|
|
331
|
+
for (const source of pendingSources) {
|
|
332
|
+
const cause = source.pendingCause();
|
|
333
|
+
if (cause !== void 0) return cause;
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
const settle = () => {
|
|
337
|
+
if (disposed || depth || phase !== "idle") return;
|
|
338
|
+
phase = "compute";
|
|
339
|
+
lock(true);
|
|
340
|
+
const cause = settleCause();
|
|
341
|
+
try {
|
|
342
|
+
for (const source of pendingSources) {
|
|
343
|
+
if (source.disposed) continue;
|
|
344
|
+
const wasFaulted = source.fault !== void 0;
|
|
345
|
+
let changed = false;
|
|
346
|
+
let force = false;
|
|
347
|
+
if (!source.fault || source.recovering()) try {
|
|
348
|
+
const prepared = source.prepare(cause);
|
|
349
|
+
changed = prepared.changed;
|
|
350
|
+
force = prepared.force;
|
|
351
|
+
source.fault = void 0;
|
|
352
|
+
} catch (failure) {
|
|
353
|
+
source.fault = errorFor(source, failure, "source");
|
|
354
|
+
errors.push(source.fault);
|
|
355
|
+
}
|
|
356
|
+
const recovered = wasFaulted && !source.fault;
|
|
357
|
+
if (changed) source.publish();
|
|
358
|
+
if (source.fault || changed || force || recovered) {
|
|
359
|
+
const output = source.outputs[0];
|
|
360
|
+
emissions.add(output);
|
|
361
|
+
output.forEachConsumer(enqueue);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
while (heap.length) {
|
|
365
|
+
const processor = pop();
|
|
366
|
+
if (processor.disposed) continue;
|
|
367
|
+
const wasFaulted = processor.fault !== void 0;
|
|
368
|
+
profile.projection("processedNodes");
|
|
369
|
+
let changedOutputs = Object.freeze([]);
|
|
370
|
+
const blocked = processor.dependencies.find((output) => output.owner.fault || output.owner.disposed);
|
|
371
|
+
if (blocked) processor.fault = errorFor(processor, blocked.owner.fault ?? new ProjectionDisposedError(), "blocked");
|
|
372
|
+
else {
|
|
373
|
+
const reset = wasFaulted || processor.dependencies.some((output) => output.reset());
|
|
374
|
+
try {
|
|
375
|
+
changedOutputs = processor.evaluate(reset, cause, wasFaulted);
|
|
376
|
+
const dependencyFailure = processor.dependencies.find((output) => output.owner.fault)?.owner.fault;
|
|
377
|
+
if (dependencyFailure) throw dependencyFailure;
|
|
378
|
+
processor.fault = void 0;
|
|
379
|
+
} catch (failure) {
|
|
380
|
+
const error = errorFor(processor, failure);
|
|
381
|
+
processor.fault = error;
|
|
382
|
+
if (!reset) try {
|
|
383
|
+
changedOutputs = processor.evaluate(true, cause, true);
|
|
384
|
+
const dependencyFailure = processor.dependencies.find((output) => output.owner.fault)?.owner.fault;
|
|
385
|
+
if (dependencyFailure) throw dependencyFailure;
|
|
386
|
+
processor.fault = void 0;
|
|
387
|
+
errors.push(error);
|
|
388
|
+
} catch (rebuildFailure) {
|
|
389
|
+
processor.fault = errorFor(processor, rebuildFailure);
|
|
390
|
+
errors.push(processor.fault);
|
|
391
|
+
}
|
|
392
|
+
else errors.push(error);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
completed.add(processor);
|
|
396
|
+
const recovered = wasFaulted && !processor.fault;
|
|
397
|
+
if (processor.fault) processor.outputs.forEach((output) => {
|
|
398
|
+
emissions.add(output);
|
|
399
|
+
output.forEachConsumer(enqueue);
|
|
400
|
+
});
|
|
401
|
+
else {
|
|
402
|
+
if (changedOutputs.length) {
|
|
403
|
+
processor.publish();
|
|
404
|
+
changedOutputs.forEach((output) => emissions.add(output));
|
|
405
|
+
}
|
|
406
|
+
(recovered ? processor.outputs : changedOutputs).forEach((output) => output.forEachConsumer(enqueue));
|
|
407
|
+
}
|
|
408
|
+
if (processor.fault || changedOutputs.length) profile.projection("publishedNodes");
|
|
409
|
+
}
|
|
410
|
+
} finally {
|
|
411
|
+
lock(false);
|
|
412
|
+
phase = "idle";
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
const flush = () => {
|
|
416
|
+
if (disposed || depth) return [];
|
|
417
|
+
if (pendingSources.size || completed.size) profile.projection("flushes");
|
|
418
|
+
phase = "notify";
|
|
419
|
+
lock(true);
|
|
420
|
+
const reportFailures = [];
|
|
421
|
+
try {
|
|
422
|
+
emissions.forEach((output) => output.emit((listener, change) => {
|
|
423
|
+
try {
|
|
424
|
+
listener(change);
|
|
425
|
+
} catch (cause) {
|
|
426
|
+
errors.push(errorFor(output.owner, cause, "listener"));
|
|
427
|
+
}
|
|
428
|
+
}));
|
|
429
|
+
for (const error of errors.slice()) try {
|
|
430
|
+
onError(error);
|
|
431
|
+
} catch (cause) {
|
|
432
|
+
reportFailures.push(cause);
|
|
433
|
+
}
|
|
434
|
+
return Object.freeze([...errors.map((error) => Object.freeze({
|
|
435
|
+
phase: error.phase === "listener" ? "listener" : "processor",
|
|
436
|
+
error
|
|
437
|
+
})), ...reportFailures.map((error) => Object.freeze({
|
|
438
|
+
phase: "listener",
|
|
439
|
+
error
|
|
440
|
+
}))]);
|
|
441
|
+
} finally {
|
|
442
|
+
pendingSources.forEach((source) => source.clear());
|
|
443
|
+
completed.forEach((processor) => processor.clear());
|
|
444
|
+
pendingSources.clear();
|
|
445
|
+
queued.clear();
|
|
446
|
+
completed.clear();
|
|
447
|
+
emissions.clear();
|
|
448
|
+
errors.length = 0;
|
|
449
|
+
reportingFailures = reportFailures;
|
|
450
|
+
lock(false);
|
|
451
|
+
phase = "idle";
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
const run = () => {
|
|
455
|
+
settle();
|
|
456
|
+
const result = flush();
|
|
457
|
+
const failures = reportingFailures;
|
|
458
|
+
reportingFailures = [];
|
|
459
|
+
if (failures.length) throw new AggregateError(failures, "Projection error reporter failed.");
|
|
460
|
+
return result;
|
|
461
|
+
};
|
|
462
|
+
const batch = (callback, options) => {
|
|
463
|
+
assertIdle();
|
|
464
|
+
if (depth === 0) activeBatch = Object.freeze({
|
|
465
|
+
id: ++batchSequence,
|
|
466
|
+
...options?.cause === void 0 ? {} : { cause: options.cause }
|
|
467
|
+
});
|
|
468
|
+
depth++;
|
|
469
|
+
let failed = false;
|
|
470
|
+
try {
|
|
471
|
+
const value = callback();
|
|
472
|
+
assertSynchronous(value);
|
|
473
|
+
return value;
|
|
474
|
+
} catch (error) {
|
|
475
|
+
failed = true;
|
|
476
|
+
throw error;
|
|
477
|
+
} finally {
|
|
478
|
+
depth--;
|
|
479
|
+
if (!depth) try {
|
|
480
|
+
if (failed) try {
|
|
481
|
+
run();
|
|
482
|
+
} catch {}
|
|
483
|
+
else run();
|
|
484
|
+
} finally {
|
|
485
|
+
activeBatch = void 0;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
const releaseProducer = (producer) => {
|
|
490
|
+
assertIdle();
|
|
491
|
+
if (producer.outputs.some((output) => output.hasConsumers())) throw new Error("Projection producer is still used by another processor.");
|
|
492
|
+
producer.disposed = true;
|
|
493
|
+
if (producer.kind === "processor") {
|
|
494
|
+
producer.dependencies.forEach((output) => output.detachConsumer(producer));
|
|
495
|
+
processors.delete(producer);
|
|
496
|
+
queued.delete(producer);
|
|
497
|
+
completed.delete(producer);
|
|
498
|
+
} else {
|
|
499
|
+
sources.delete(producer);
|
|
500
|
+
pendingSources.delete(producer);
|
|
501
|
+
}
|
|
502
|
+
const failures = [];
|
|
503
|
+
try {
|
|
504
|
+
producer.release();
|
|
505
|
+
} catch (error) {
|
|
506
|
+
failures.push(error);
|
|
507
|
+
}
|
|
508
|
+
try {
|
|
509
|
+
producer.clear();
|
|
510
|
+
} catch (error) {
|
|
511
|
+
failures.push(error);
|
|
512
|
+
}
|
|
513
|
+
producer.outputs.forEach((output) => emissions.delete(output));
|
|
514
|
+
if (failures.length) throw failures[0];
|
|
515
|
+
};
|
|
516
|
+
return {
|
|
517
|
+
assertActive,
|
|
518
|
+
assertIdle,
|
|
519
|
+
capture,
|
|
520
|
+
settle,
|
|
521
|
+
flush,
|
|
522
|
+
run,
|
|
523
|
+
registerGuard(guard) {
|
|
524
|
+
assertActive();
|
|
525
|
+
guards.add(guard);
|
|
526
|
+
let registered = true;
|
|
527
|
+
return () => {
|
|
528
|
+
if (!registered) return;
|
|
529
|
+
registered = false;
|
|
530
|
+
guards.delete(guard);
|
|
531
|
+
};
|
|
532
|
+
},
|
|
533
|
+
get active() {
|
|
534
|
+
return !disposed;
|
|
535
|
+
},
|
|
536
|
+
addSource(source) {
|
|
537
|
+
assertIdle();
|
|
538
|
+
sources.add(source);
|
|
539
|
+
},
|
|
540
|
+
addProcessor(processor) {
|
|
541
|
+
assertIdle();
|
|
542
|
+
processors.add(processor);
|
|
543
|
+
processor.dependencies.forEach((output) => output.attachConsumer(processor));
|
|
544
|
+
},
|
|
545
|
+
releaseProducer,
|
|
546
|
+
order: () => sequence++,
|
|
547
|
+
initialize(callback) {
|
|
548
|
+
assertIdle();
|
|
549
|
+
phase = "compute";
|
|
550
|
+
lock(true);
|
|
551
|
+
try {
|
|
552
|
+
return callback();
|
|
553
|
+
} finally {
|
|
554
|
+
lock(false);
|
|
555
|
+
phase = "idle";
|
|
556
|
+
}
|
|
557
|
+
},
|
|
558
|
+
batch,
|
|
559
|
+
batchContext: () => activeBatch,
|
|
560
|
+
dispose() {
|
|
561
|
+
if (disposed) return;
|
|
562
|
+
assertIdle();
|
|
563
|
+
disposed = true;
|
|
564
|
+
const failures = [];
|
|
565
|
+
processors.forEach((processor) => {
|
|
566
|
+
processor.disposed = true;
|
|
567
|
+
try {
|
|
568
|
+
processor.release();
|
|
569
|
+
} catch (error) {
|
|
570
|
+
failures.push(error);
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
sources.forEach((source) => {
|
|
574
|
+
source.disposed = true;
|
|
575
|
+
try {
|
|
576
|
+
source.release();
|
|
577
|
+
} catch (error) {
|
|
578
|
+
failures.push(error);
|
|
579
|
+
}
|
|
580
|
+
});
|
|
581
|
+
processors.clear();
|
|
582
|
+
sources.clear();
|
|
583
|
+
pendingSources.clear();
|
|
584
|
+
heap.length = 0;
|
|
585
|
+
queued.clear();
|
|
586
|
+
completed.clear();
|
|
587
|
+
emissions.clear();
|
|
588
|
+
guards.clear();
|
|
589
|
+
errors.length = 0;
|
|
590
|
+
reportingFailures = [];
|
|
591
|
+
if (failures.length) throw new AggregateError(failures, "Projection cleanup failed.");
|
|
592
|
+
}
|
|
593
|
+
};
|
|
594
|
+
};
|
|
595
|
+
const assertSynchronous = (value) => {
|
|
596
|
+
if (value != null && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function") throw new TypeError("Projection callbacks must be synchronous.");
|
|
597
|
+
};
|
|
598
|
+
const assertScope = (active) => {
|
|
599
|
+
if (!active()) throw new Error("Projection reader or writer is no longer active.");
|
|
600
|
+
};
|
|
601
|
+
//#endregion
|
|
602
|
+
//#region core/src/projection/keyed/relation.ts
|
|
603
|
+
/** Runtime-local domain-neutral many-to-many keyed relation. */
|
|
604
|
+
const createKeyRelation = () => {
|
|
605
|
+
const forward = /* @__PURE__ */ new Map();
|
|
606
|
+
const reverse = /* @__PURE__ */ new Map();
|
|
607
|
+
const detach = (left, right) => {
|
|
608
|
+
for (const key of right) {
|
|
609
|
+
const dependents = reverse.get(key);
|
|
610
|
+
dependents?.delete(left);
|
|
611
|
+
if (dependents?.size === 0) reverse.delete(key);
|
|
612
|
+
}
|
|
613
|
+
};
|
|
614
|
+
const attach = (left, right) => {
|
|
615
|
+
for (const key of right) {
|
|
616
|
+
const dependents = reverse.get(key);
|
|
617
|
+
if (dependents) dependents.add(left);
|
|
618
|
+
else reverse.set(key, new Set([left]));
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
return {
|
|
622
|
+
replace(left, right) {
|
|
623
|
+
const previous = forward.get(left) ?? Object.freeze([]);
|
|
624
|
+
if (previous.length === right.length && previous.every((key, index) => key === right[index])) return false;
|
|
625
|
+
detach(left, previous);
|
|
626
|
+
if (!right.length) {
|
|
627
|
+
forward.delete(left);
|
|
628
|
+
return true;
|
|
629
|
+
}
|
|
630
|
+
const next = Object.freeze([...right]);
|
|
631
|
+
forward.set(left, next);
|
|
632
|
+
attach(left, next);
|
|
633
|
+
return true;
|
|
634
|
+
},
|
|
635
|
+
delete(left) {
|
|
636
|
+
const previous = forward.get(left);
|
|
637
|
+
if (!previous) return false;
|
|
638
|
+
detach(left, previous);
|
|
639
|
+
forward.delete(left);
|
|
640
|
+
return true;
|
|
641
|
+
},
|
|
642
|
+
forward: (left) => forward.get(left),
|
|
643
|
+
reverse: (right) => reverse.get(right),
|
|
644
|
+
lefts: () => forward.keys(),
|
|
645
|
+
rights: () => reverse.keys(),
|
|
646
|
+
clear() {
|
|
647
|
+
forward.clear();
|
|
648
|
+
reverse.clear();
|
|
649
|
+
}
|
|
650
|
+
};
|
|
651
|
+
};
|
|
652
|
+
//#endregion
|
|
653
|
+
//#region core/src/projection/keyed/dependency.ts
|
|
654
|
+
const outputKind = (projection) => outputDefinitionOf(projection).kind;
|
|
655
|
+
const assertKeyedProjection = (projection, role) => {
|
|
656
|
+
if (outputKind(projection) !== "collection") throw new TypeError(`${role} must be a keyed collection projection.`);
|
|
657
|
+
};
|
|
658
|
+
const compileDynamicDependency = (value, label) => {
|
|
659
|
+
if (!require_record.isPlainObject(value) || isProjection(value)) throw new TypeError(`${label} dependencies must be projections or singular/plural keyed lookups.`);
|
|
660
|
+
const candidate = {};
|
|
661
|
+
const allowed = new Set([
|
|
662
|
+
"source",
|
|
663
|
+
"key",
|
|
664
|
+
"keys"
|
|
665
|
+
]);
|
|
666
|
+
let hasKey = false;
|
|
667
|
+
let hasKeys = false;
|
|
668
|
+
for (const name of Reflect.ownKeys(value)) {
|
|
669
|
+
if (typeof name !== "string" || !allowed.has(name)) throw new TypeError(`${label} dynamic keyed dependency contains an unknown property.`);
|
|
670
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, name);
|
|
671
|
+
if (!descriptor?.enumerable || !("value" in descriptor)) throw new TypeError(`${label} dynamic keyed dependency must use enumerable data properties.`);
|
|
672
|
+
candidate[name] = descriptor.value;
|
|
673
|
+
if (name === "key") hasKey = true;
|
|
674
|
+
if (name === "keys") hasKeys = true;
|
|
675
|
+
}
|
|
676
|
+
if (!isProjection(candidate.source)) throw new TypeError(`${label} dynamic keyed dependency source must be a projection.`);
|
|
677
|
+
if (hasKey === hasKeys) throw new TypeError(`${label} dynamic keyed dependency must declare exactly one of key or keys.`);
|
|
678
|
+
const singular = hasKey;
|
|
679
|
+
const selector = singular ? candidate.key : candidate.keys;
|
|
680
|
+
if (typeof selector !== "function") throw new TypeError(`${label} dynamic keyed dependency selector must be a function.`);
|
|
681
|
+
assertKeyedProjection(candidate.source, `${label} dynamic keyed dependency source`);
|
|
682
|
+
return singular ? {
|
|
683
|
+
kind: "one",
|
|
684
|
+
projection: candidate.source,
|
|
685
|
+
select: selector
|
|
686
|
+
} : {
|
|
687
|
+
kind: "many",
|
|
688
|
+
projection: candidate.source,
|
|
689
|
+
select: selector
|
|
690
|
+
};
|
|
691
|
+
};
|
|
692
|
+
const compileKeyedDependencies = (driver, dependencySpecs, label) => {
|
|
693
|
+
const entries = [];
|
|
694
|
+
const projections = [driver];
|
|
695
|
+
if (dependencySpecs === void 0) return Object.freeze({
|
|
696
|
+
entries: Object.freeze(entries),
|
|
697
|
+
projections: Object.freeze(projections)
|
|
698
|
+
});
|
|
699
|
+
for (const { name, value: dependency } of readNamedDependencyEntries(dependencySpecs, label)) {
|
|
700
|
+
if (isProjection(dependency)) {
|
|
701
|
+
entries.push(Object.freeze({
|
|
702
|
+
name,
|
|
703
|
+
kind: "global",
|
|
704
|
+
projection: dependency
|
|
705
|
+
}));
|
|
706
|
+
projections.push(dependency);
|
|
707
|
+
continue;
|
|
708
|
+
}
|
|
709
|
+
const dynamic = compileDynamicDependency(dependency, label);
|
|
710
|
+
entries.push(Object.freeze({
|
|
711
|
+
name,
|
|
712
|
+
...dynamic
|
|
713
|
+
}));
|
|
714
|
+
projections.push(dynamic.projection);
|
|
715
|
+
}
|
|
716
|
+
return Object.freeze({
|
|
717
|
+
entries: Object.freeze(entries),
|
|
718
|
+
projections: Object.freeze(projections)
|
|
719
|
+
});
|
|
720
|
+
};
|
|
721
|
+
const selectedKeys = (dependency, value, key) => {
|
|
722
|
+
const result = dependency.select(value, key);
|
|
723
|
+
assertSynchronous(result);
|
|
724
|
+
if (dependency.kind === "one") {
|
|
725
|
+
if (result === void 0) return Object.freeze([]);
|
|
726
|
+
if (typeof result !== "string") throw new TypeError("Dynamic keyed dependency key must be a string or undefined.");
|
|
727
|
+
return Object.freeze([result]);
|
|
728
|
+
}
|
|
729
|
+
if (!Array.isArray(result)) throw new TypeError("Dynamic keyed dependency keys must be an array of strings.");
|
|
730
|
+
const seen = /* @__PURE__ */ new Set();
|
|
731
|
+
const keys = [];
|
|
732
|
+
for (const selected of result) {
|
|
733
|
+
if (typeof selected !== "string") throw new TypeError("Dynamic keyed dependency keys must contain only strings.");
|
|
734
|
+
if (seen.has(selected)) throw new TypeError("Dynamic keyed dependency keys must not contain duplicates.");
|
|
735
|
+
seen.add(selected);
|
|
736
|
+
keys.push(selected);
|
|
737
|
+
}
|
|
738
|
+
return Object.freeze(keys);
|
|
739
|
+
};
|
|
740
|
+
const emptyValues = Object.freeze(Object.create(null));
|
|
741
|
+
const createKeyedDependencyRuntime = (compiled) => {
|
|
742
|
+
const states = compiled.entries.map((entry, index) => entry.kind === "global" ? {
|
|
743
|
+
kind: "global",
|
|
744
|
+
entry,
|
|
745
|
+
sourceIndex: index + 1,
|
|
746
|
+
revision: -1,
|
|
747
|
+
globalValue: void 0
|
|
748
|
+
} : {
|
|
749
|
+
kind: "dynamic",
|
|
750
|
+
entry,
|
|
751
|
+
sourceIndex: index + 1,
|
|
752
|
+
relation: createKeyRelation(),
|
|
753
|
+
revision: -1
|
|
754
|
+
});
|
|
755
|
+
let driverRevision = -1;
|
|
756
|
+
return {
|
|
757
|
+
prepare(sources, reset) {
|
|
758
|
+
for (const state of states) {
|
|
759
|
+
if (state.kind !== "global") continue;
|
|
760
|
+
const source = sources[state.sourceIndex];
|
|
761
|
+
if (reset || state.revision !== source.revision) state.globalValue = snapshotDependencyValue(source);
|
|
762
|
+
}
|
|
763
|
+
},
|
|
764
|
+
resolve(driverValue, driverKey, sources) {
|
|
765
|
+
if (!states.length) return emptyValues;
|
|
766
|
+
const values = Object.create(null);
|
|
767
|
+
for (const state of states) {
|
|
768
|
+
if (state.kind === "global") {
|
|
769
|
+
values[state.entry.name] = state.globalValue;
|
|
770
|
+
continue;
|
|
771
|
+
}
|
|
772
|
+
const dependency = state.entry;
|
|
773
|
+
const source = sources[state.sourceIndex];
|
|
774
|
+
if (source.kind !== "collection") throw new TypeError("Dynamic keyed dependency resolved to a non-collection source.");
|
|
775
|
+
const keys = selectedKeys(dependency, driverValue, driverKey);
|
|
776
|
+
state.relation.replace(driverKey, keys);
|
|
777
|
+
if (dependency.kind === "one") {
|
|
778
|
+
const selected = keys[0];
|
|
779
|
+
values[dependency.name] = selected === void 0 ? void 0 : source.read.get(selected);
|
|
780
|
+
continue;
|
|
781
|
+
}
|
|
782
|
+
const selected = /* @__PURE__ */ new Map();
|
|
783
|
+
for (const key of keys) if (source.read.has(key)) selected.set(key, source.read.get(key));
|
|
784
|
+
values[dependency.name] = collectionView(mapRead(selected));
|
|
785
|
+
}
|
|
786
|
+
return Object.freeze(values);
|
|
787
|
+
},
|
|
788
|
+
driverChanged(source) {
|
|
789
|
+
return driverRevision !== source.revision;
|
|
790
|
+
},
|
|
791
|
+
collectInvalidated(sources, dirty) {
|
|
792
|
+
let all = false;
|
|
793
|
+
for (const state of states) {
|
|
794
|
+
const source = sources[state.sourceIndex];
|
|
795
|
+
if (state.revision === source.revision) continue;
|
|
796
|
+
state.entry;
|
|
797
|
+
if (state.kind === "global") {
|
|
798
|
+
all = true;
|
|
799
|
+
continue;
|
|
800
|
+
}
|
|
801
|
+
if (source.kind !== "collection" || !source.change || source.change.kind === "reset") {
|
|
802
|
+
all = true;
|
|
803
|
+
continue;
|
|
804
|
+
}
|
|
805
|
+
for (const sourceKey of collectionChange.keys(source.change)) for (const dependent of state.relation.reverse(sourceKey) ?? []) dirty.add(dependent);
|
|
806
|
+
}
|
|
807
|
+
return all;
|
|
808
|
+
},
|
|
809
|
+
remove(driverKey) {
|
|
810
|
+
for (const state of states) if (state.kind === "dynamic") state.relation.delete(driverKey);
|
|
811
|
+
},
|
|
812
|
+
clearBindings() {
|
|
813
|
+
for (const state of states) if (state.kind === "dynamic") state.relation.clear();
|
|
814
|
+
},
|
|
815
|
+
remember(sources) {
|
|
816
|
+
driverRevision = sources[0]?.revision ?? -1;
|
|
817
|
+
for (const state of states) state.revision = sources[state.sourceIndex].revision;
|
|
818
|
+
},
|
|
819
|
+
release() {
|
|
820
|
+
for (const state of states) {
|
|
821
|
+
state.revision = -1;
|
|
822
|
+
if (state.kind === "global") state.globalValue = void 0;
|
|
823
|
+
else state.relation.clear();
|
|
824
|
+
}
|
|
825
|
+
driverRevision = -1;
|
|
826
|
+
}
|
|
827
|
+
};
|
|
828
|
+
};
|
|
829
|
+
//#endregion
|
|
830
|
+
//#region core/src/projection/keyed/transform.ts
|
|
831
|
+
const keyedAbsent = Symbol("keyed-transform-absent");
|
|
832
|
+
/** Shared driver-keyed lifecycle for pure and retained keyed transforms. */
|
|
833
|
+
const createKeyedTransform = (definition) => {
|
|
834
|
+
assertKeyedProjection(definition.source, `${definition.name} source`);
|
|
835
|
+
const compiled = compileKeyedDependencies(definition.source, definition.dependencies, definition.name);
|
|
836
|
+
const [projection] = defineProcessor({
|
|
837
|
+
dependencies: compiled.projections,
|
|
838
|
+
outputs: [{
|
|
839
|
+
kind: "collection",
|
|
840
|
+
equality: definition.equality ?? Object.is
|
|
841
|
+
}],
|
|
842
|
+
create: () => {
|
|
843
|
+
const dependencies = createKeyedDependencyRuntime(compiled);
|
|
844
|
+
const states = /* @__PURE__ */ new Map();
|
|
845
|
+
const dropState = (key) => {
|
|
846
|
+
states.delete(key);
|
|
847
|
+
dependencies.remove(key);
|
|
848
|
+
};
|
|
849
|
+
return {
|
|
850
|
+
evaluate: (evaluation) => {
|
|
851
|
+
const driver = evaluation.sources[0];
|
|
852
|
+
const output = evaluation.outputs[0];
|
|
853
|
+
if (driver.kind !== "collection" || output.kind !== "collection") throw new Error(`${definition.name} requires collection input and output.`);
|
|
854
|
+
dependencies.prepare(evaluation.sources, evaluation.reset);
|
|
855
|
+
const stateFor = (key, value) => {
|
|
856
|
+
if (states.has(key)) return states.get(key);
|
|
857
|
+
const state = definition.state ? definition.state(value, key) : void 0;
|
|
858
|
+
assertSynchronous(state);
|
|
859
|
+
if (definition.state) states.set(key, state);
|
|
860
|
+
return state;
|
|
861
|
+
};
|
|
862
|
+
const project = (key) => {
|
|
863
|
+
if (!driver.read.has(key)) return false;
|
|
864
|
+
const value = driver.read.get(key);
|
|
865
|
+
const beforePresent = output.previous.has(key);
|
|
866
|
+
const next = definition.evaluate({
|
|
867
|
+
key,
|
|
868
|
+
value,
|
|
869
|
+
dependencies: dependencies.resolve(value, key, evaluation.sources),
|
|
870
|
+
state: stateFor(key, value),
|
|
871
|
+
reset: evaluation.reset,
|
|
872
|
+
cause: evaluation.cause
|
|
873
|
+
});
|
|
874
|
+
assertSynchronous(next);
|
|
875
|
+
if (next === keyedAbsent) output.output.remove(key);
|
|
876
|
+
else output.output.set(key, next);
|
|
877
|
+
return beforePresent !== output.next.has(key);
|
|
878
|
+
};
|
|
879
|
+
if (evaluation.reset) {
|
|
880
|
+
dependencies.clearBindings();
|
|
881
|
+
const ids = driver.read.ids();
|
|
882
|
+
const present = new Set(ids);
|
|
883
|
+
for (const key of [...states.keys()]) if (!present.has(key)) states.delete(key);
|
|
884
|
+
for (const key of ids) project(key);
|
|
885
|
+
output.output.order(ids.filter((key) => output.next.has(key)));
|
|
886
|
+
dependencies.remember(evaluation.sources);
|
|
887
|
+
return;
|
|
888
|
+
}
|
|
889
|
+
const dirty = /* @__PURE__ */ new Set();
|
|
890
|
+
let all = false;
|
|
891
|
+
let updateOrder = false;
|
|
892
|
+
let membershipChanged = false;
|
|
893
|
+
if (dependencies.driverChanged(driver)) {
|
|
894
|
+
const change = driver.change;
|
|
895
|
+
if (!change || change.kind === "reset") {
|
|
896
|
+
all = true;
|
|
897
|
+
updateOrder = true;
|
|
898
|
+
for (const key of output.previous.ids()) {
|
|
899
|
+
if (driver.read.has(key)) continue;
|
|
900
|
+
output.output.remove(key);
|
|
901
|
+
dropState(key);
|
|
902
|
+
membershipChanged = true;
|
|
903
|
+
}
|
|
904
|
+
} else {
|
|
905
|
+
for (const entry of change.removed) {
|
|
906
|
+
membershipChanged ||= output.previous.has(entry.key);
|
|
907
|
+
output.output.remove(entry.key);
|
|
908
|
+
dropState(entry.key);
|
|
909
|
+
dirty.delete(entry.key);
|
|
910
|
+
}
|
|
911
|
+
for (const entry of change.added) dirty.add(entry.key);
|
|
912
|
+
for (const entry of change.updated) dirty.add(entry.key);
|
|
913
|
+
updateOrder = Boolean(change.order);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
all ||= dependencies.collectInvalidated(evaluation.sources, dirty);
|
|
917
|
+
if (all) for (const key of driver.read.ids()) dirty.add(key);
|
|
918
|
+
for (const key of dirty) {
|
|
919
|
+
const changedMembership = project(key);
|
|
920
|
+
membershipChanged ||= changedMembership;
|
|
921
|
+
}
|
|
922
|
+
if (updateOrder || membershipChanged) output.output.order(driver.read.ids().filter((key) => output.next.has(key)));
|
|
923
|
+
dependencies.remember(evaluation.sources);
|
|
924
|
+
},
|
|
925
|
+
release: () => {
|
|
926
|
+
states.clear();
|
|
927
|
+
dependencies.release();
|
|
928
|
+
}
|
|
929
|
+
};
|
|
930
|
+
},
|
|
931
|
+
name: definition.name
|
|
932
|
+
});
|
|
933
|
+
return projection;
|
|
934
|
+
};
|
|
935
|
+
//#endregion
|
|
936
|
+
Object.defineProperty(exports, "ProjectionDisposedError", {
|
|
937
|
+
enumerable: true,
|
|
938
|
+
get: function() {
|
|
939
|
+
return ProjectionDisposedError;
|
|
940
|
+
}
|
|
941
|
+
});
|
|
942
|
+
Object.defineProperty(exports, "ProjectionError", {
|
|
943
|
+
enumerable: true,
|
|
944
|
+
get: function() {
|
|
945
|
+
return ProjectionError;
|
|
946
|
+
}
|
|
947
|
+
});
|
|
948
|
+
Object.defineProperty(exports, "assertKeyedProjection", {
|
|
949
|
+
enumerable: true,
|
|
950
|
+
get: function() {
|
|
951
|
+
return assertKeyedProjection;
|
|
952
|
+
}
|
|
953
|
+
});
|
|
954
|
+
Object.defineProperty(exports, "assertScope", {
|
|
955
|
+
enumerable: true,
|
|
956
|
+
get: function() {
|
|
957
|
+
return assertScope;
|
|
958
|
+
}
|
|
959
|
+
});
|
|
960
|
+
Object.defineProperty(exports, "assertSynchronous", {
|
|
961
|
+
enumerable: true,
|
|
962
|
+
get: function() {
|
|
963
|
+
return assertSynchronous;
|
|
964
|
+
}
|
|
965
|
+
});
|
|
966
|
+
Object.defineProperty(exports, "collectionChange", {
|
|
967
|
+
enumerable: true,
|
|
968
|
+
get: function() {
|
|
969
|
+
return collectionChange;
|
|
970
|
+
}
|
|
971
|
+
});
|
|
972
|
+
Object.defineProperty(exports, "collectionHasStructuralChange", {
|
|
973
|
+
enumerable: true,
|
|
974
|
+
get: function() {
|
|
975
|
+
return collectionHasStructuralChange;
|
|
976
|
+
}
|
|
977
|
+
});
|
|
978
|
+
Object.defineProperty(exports, "collectionView", {
|
|
979
|
+
enumerable: true,
|
|
980
|
+
get: function() {
|
|
981
|
+
return collectionView;
|
|
982
|
+
}
|
|
983
|
+
});
|
|
984
|
+
Object.defineProperty(exports, "compileKeyedDependencies", {
|
|
985
|
+
enumerable: true,
|
|
986
|
+
get: function() {
|
|
987
|
+
return compileKeyedDependencies;
|
|
988
|
+
}
|
|
989
|
+
});
|
|
990
|
+
Object.defineProperty(exports, "compileProjectionDependencies", {
|
|
991
|
+
enumerable: true,
|
|
992
|
+
get: function() {
|
|
993
|
+
return compileProjectionDependencies;
|
|
994
|
+
}
|
|
995
|
+
});
|
|
996
|
+
Object.defineProperty(exports, "createCollectionChange", {
|
|
997
|
+
enumerable: true,
|
|
998
|
+
get: function() {
|
|
999
|
+
return createCollectionChange;
|
|
1000
|
+
}
|
|
1001
|
+
});
|
|
1002
|
+
Object.defineProperty(exports, "createKeyRelation", {
|
|
1003
|
+
enumerable: true,
|
|
1004
|
+
get: function() {
|
|
1005
|
+
return createKeyRelation;
|
|
1006
|
+
}
|
|
1007
|
+
});
|
|
1008
|
+
Object.defineProperty(exports, "createKeyedDependencyRuntime", {
|
|
1009
|
+
enumerable: true,
|
|
1010
|
+
get: function() {
|
|
1011
|
+
return createKeyedDependencyRuntime;
|
|
1012
|
+
}
|
|
1013
|
+
});
|
|
1014
|
+
Object.defineProperty(exports, "createKeyedTransform", {
|
|
1015
|
+
enumerable: true,
|
|
1016
|
+
get: function() {
|
|
1017
|
+
return createKeyedTransform;
|
|
1018
|
+
}
|
|
1019
|
+
});
|
|
1020
|
+
Object.defineProperty(exports, "createScheduler", {
|
|
1021
|
+
enumerable: true,
|
|
1022
|
+
get: function() {
|
|
1023
|
+
return createScheduler;
|
|
1024
|
+
}
|
|
1025
|
+
});
|
|
1026
|
+
Object.defineProperty(exports, "defineProcessor", {
|
|
1027
|
+
enumerable: true,
|
|
1028
|
+
get: function() {
|
|
1029
|
+
return defineProcessor;
|
|
1030
|
+
}
|
|
1031
|
+
});
|
|
1032
|
+
Object.defineProperty(exports, "defineSource", {
|
|
1033
|
+
enumerable: true,
|
|
1034
|
+
get: function() {
|
|
1035
|
+
return defineSource;
|
|
1036
|
+
}
|
|
1037
|
+
});
|
|
1038
|
+
Object.defineProperty(exports, "diffCollection", {
|
|
1039
|
+
enumerable: true,
|
|
1040
|
+
get: function() {
|
|
1041
|
+
return diffCollection;
|
|
1042
|
+
}
|
|
1043
|
+
});
|
|
1044
|
+
Object.defineProperty(exports, "isProjection", {
|
|
1045
|
+
enumerable: true,
|
|
1046
|
+
get: function() {
|
|
1047
|
+
return isProjection;
|
|
1048
|
+
}
|
|
1049
|
+
});
|
|
1050
|
+
Object.defineProperty(exports, "keyedAbsent", {
|
|
1051
|
+
enumerable: true,
|
|
1052
|
+
get: function() {
|
|
1053
|
+
return keyedAbsent;
|
|
1054
|
+
}
|
|
1055
|
+
});
|
|
1056
|
+
Object.defineProperty(exports, "mapRead", {
|
|
1057
|
+
enumerable: true,
|
|
1058
|
+
get: function() {
|
|
1059
|
+
return mapRead;
|
|
1060
|
+
}
|
|
1061
|
+
});
|
|
1062
|
+
Object.defineProperty(exports, "outputKind", {
|
|
1063
|
+
enumerable: true,
|
|
1064
|
+
get: function() {
|
|
1065
|
+
return outputKind;
|
|
1066
|
+
}
|
|
1067
|
+
});
|
|
1068
|
+
Object.defineProperty(exports, "ownProjections", {
|
|
1069
|
+
enumerable: true,
|
|
1070
|
+
get: function() {
|
|
1071
|
+
return ownProjections;
|
|
1072
|
+
}
|
|
1073
|
+
});
|
|
1074
|
+
Object.defineProperty(exports, "producerOf", {
|
|
1075
|
+
enumerable: true,
|
|
1076
|
+
get: function() {
|
|
1077
|
+
return producerOf;
|
|
1078
|
+
}
|
|
1079
|
+
});
|
|
1080
|
+
Object.defineProperty(exports, "profile", {
|
|
1081
|
+
enumerable: true,
|
|
1082
|
+
get: function() {
|
|
1083
|
+
return profile;
|
|
1084
|
+
}
|
|
1085
|
+
});
|
|
1086
|
+
Object.defineProperty(exports, "projectionRef", {
|
|
1087
|
+
enumerable: true,
|
|
1088
|
+
get: function() {
|
|
1089
|
+
return projectionRef;
|
|
1090
|
+
}
|
|
1091
|
+
});
|
|
1092
|
+
Object.defineProperty(exports, "snapshotCollectionView", {
|
|
1093
|
+
enumerable: true,
|
|
1094
|
+
get: function() {
|
|
1095
|
+
return snapshotCollectionView;
|
|
1096
|
+
}
|
|
1097
|
+
});
|
|
1098
|
+
Object.defineProperty(exports, "snapshotDependencyValue", {
|
|
1099
|
+
enumerable: true,
|
|
1100
|
+
get: function() {
|
|
1101
|
+
return snapshotDependencyValue;
|
|
1102
|
+
}
|
|
1103
|
+
});
|
|
1104
|
+
|
|
1105
|
+
//# sourceMappingURL=transform-DUleAsG0.cjs.map
|