vestjs-runtime 1.7.0 → 2.0.2
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/IsolateSerializer/package.json +12 -8
- package/README.md +3 -1
- package/dist/IsolateKeys-B21aPuBk.mjs +23 -0
- package/dist/IsolateKeys-B21aPuBk.mjs.map +1 -0
- package/dist/IsolateKeys-CCvALpZC.cjs +35 -0
- package/dist/IsolateKeys-CCvALpZC.cjs.map +1 -0
- package/dist/IsolateSerializer-B1hE3gmT.mjs +1004 -0
- package/dist/IsolateSerializer-B1hE3gmT.mjs.map +1 -0
- package/dist/IsolateSerializer-pbEf5gB2.cjs +1121 -0
- package/dist/IsolateSerializer-pbEf5gB2.cjs.map +1 -0
- package/dist/chunk-CLMFDpHK.mjs +18 -0
- package/dist/exports/IsolateSerializer.cjs +4 -0
- package/dist/exports/IsolateSerializer.mjs +4 -0
- package/dist/exports/test-utils.cjs +21 -0
- package/dist/exports/test-utils.cjs.map +1 -0
- package/dist/exports/test-utils.mjs +21 -0
- package/dist/exports/test-utils.mjs.map +1 -0
- package/dist/vestjs-runtime.cjs +153 -0
- package/dist/vestjs-runtime.cjs.map +1 -0
- package/dist/vestjs-runtime.mjs +117 -0
- package/dist/vestjs-runtime.mjs.map +1 -0
- package/docs/IsolateRegistry.docs.md +146 -0
- package/docs/Isolates.md +97 -0
- package/package.json +43 -88
- package/src/Bus.ts +46 -0
- package/src/Isolate/Isolate.ts +163 -0
- package/src/Isolate/IsolateFocused.ts +93 -0
- package/src/Isolate/IsolateIndexer.ts +42 -0
- package/src/Isolate/IsolateInspector.ts +93 -0
- package/src/Isolate/IsolateKeys.ts +18 -0
- package/src/Isolate/IsolateMutator.ts +165 -0
- package/src/Isolate/IsolateRegistry.ts +176 -0
- package/src/Isolate/IsolateReorderable.ts +11 -0
- package/src/Isolate/IsolateSelectors.ts +25 -0
- package/src/Isolate/IsolateStateMachine.ts +30 -0
- package/src/Isolate/IsolateStatus.ts +8 -0
- package/src/Isolate/IsolateTransient.ts +27 -0
- package/src/Isolate/IsolateTypes.ts +33 -0
- package/src/Isolate/__tests__/Isolate.test.ts +123 -0
- package/src/Isolate/__tests__/IsolateFocused.test.ts +199 -0
- package/src/Isolate/__tests__/IsolateInspector.test.ts +136 -0
- package/src/Isolate/__tests__/IsolateMutator.test.ts +164 -0
- package/src/Isolate/__tests__/IsolatePropagation.test.ts +170 -0
- package/src/Isolate/__tests__/IsolateReorderable.test.ts +111 -0
- package/src/Isolate/__tests__/IsolateSelectors.test.ts +72 -0
- package/src/Isolate/__tests__/IsolateStatus.test.ts +44 -0
- package/src/Isolate/__tests__/IsolateTransient.test.ts +58 -0
- package/src/Isolate/__tests__/__snapshots__/asyncIsolate.test.ts.snap +71 -0
- package/src/Isolate/__tests__/asyncIsolate.test.ts +85 -0
- package/src/IsolateWalker.ts +359 -0
- package/src/Orchestrator/RuntimeStates.ts +4 -0
- package/src/Reconciler.ts +178 -0
- package/src/RuntimeEvents.ts +9 -0
- package/src/VestRuntime.ts +421 -0
- package/src/__tests__/Bus.test.ts +57 -0
- package/src/__tests__/IsolateWalker.iterative.test.ts +77 -0
- package/src/__tests__/IsolateWalker.test.ts +418 -0
- package/src/__tests__/Reconciler.test.ts +193 -0
- package/src/__tests__/Reconciler.transient.test.ts +166 -0
- package/src/__tests__/VestRuntime.test.ts +212 -0
- package/src/__tests__/VestRuntimeStateMachine.test.ts +36 -0
- package/src/__tests__/vestjs-runtime.test.ts +19 -0
- package/src/errors/ErrorStrings.ts +6 -0
- package/src/exports/IsolateSerializer.ts +131 -0
- package/src/exports/__tests__/IsolateSerializer.test.ts +334 -0
- package/src/exports/__tests__/IsolateSerializer.transient.test.ts +101 -0
- package/src/exports/__tests__/__snapshots__/IsolateSerializer.test.ts.snap +5 -0
- package/src/exports/test-utils.ts +17 -0
- package/src/vestjs-runtime.ts +28 -0
- package/test-utils/package.json +12 -8
- package/types/Isolate-DChR7h5K.d.mts +58 -0
- package/types/Isolate-DChR7h5K.d.mts.map +1 -0
- package/types/Isolate-HYIh82M8.d.cts +58 -0
- package/types/Isolate-HYIh82M8.d.cts.map +1 -0
- package/types/IsolateSerializer-BCg01Px5.d.mts +13 -0
- package/types/IsolateSerializer-BCg01Px5.d.mts.map +1 -0
- package/types/IsolateSerializer-CQpP6A4m.d.cts +13 -0
- package/types/IsolateSerializer-CQpP6A4m.d.cts.map +1 -0
- package/types/exports/IsolateSerializer.d.cts +3 -0
- package/types/exports/IsolateSerializer.d.mts +3 -0
- package/types/exports/test-utils.d.cts +7 -0
- package/types/exports/test-utils.d.cts.map +1 -0
- package/types/exports/test-utils.d.mts +7 -0
- package/types/exports/test-utils.d.mts.map +1 -0
- package/types/vestjs-runtime.d.cts +372 -0
- package/types/vestjs-runtime.d.cts.map +1 -0
- package/types/vestjs-runtime.d.mts +370 -0
- package/types/vestjs-runtime.d.mts.map +1 -0
- package/types/vestjs-runtime.d.ts +351 -257
- package/vitest.config.ts +9 -17
- package/dist/cjs/IsolateSerializer.development.js +0 -135
- package/dist/cjs/IsolateSerializer.development.js.map +0 -1
- package/dist/cjs/IsolateSerializer.js +0 -6
- package/dist/cjs/IsolateSerializer.production.js +0 -2
- package/dist/cjs/IsolateSerializer.production.js.map +0 -1
- package/dist/cjs/package.json +0 -1
- package/dist/cjs/test-utils.development.js +0 -61
- package/dist/cjs/test-utils.development.js.map +0 -1
- package/dist/cjs/test-utils.js +0 -6
- package/dist/cjs/test-utils.production.js +0 -2
- package/dist/cjs/test-utils.production.js.map +0 -1
- package/dist/cjs/vestjs-runtime.development.js +0 -686
- package/dist/cjs/vestjs-runtime.development.js.map +0 -1
- package/dist/cjs/vestjs-runtime.js +0 -6
- package/dist/cjs/vestjs-runtime.production.js +0 -2
- package/dist/cjs/vestjs-runtime.production.js.map +0 -1
- package/dist/es/IsolateSerializer.development.js +0 -133
- package/dist/es/IsolateSerializer.development.js.map +0 -1
- package/dist/es/IsolateSerializer.production.js +0 -2
- package/dist/es/IsolateSerializer.production.js.map +0 -1
- package/dist/es/package.json +0 -1
- package/dist/es/test-utils.development.js +0 -59
- package/dist/es/test-utils.development.js.map +0 -1
- package/dist/es/test-utils.production.js +0 -2
- package/dist/es/test-utils.production.js.map +0 -1
- package/dist/es/vestjs-runtime.development.js +0 -675
- package/dist/es/vestjs-runtime.development.js.map +0 -1
- package/dist/es/vestjs-runtime.production.js +0 -2
- package/dist/es/vestjs-runtime.production.js.map +0 -1
- package/dist/umd/IsolateSerializer.development.js +0 -138
- package/dist/umd/IsolateSerializer.development.js.map +0 -1
- package/dist/umd/IsolateSerializer.production.js +0 -2
- package/dist/umd/IsolateSerializer.production.js.map +0 -1
- package/dist/umd/test-utils.development.js +0 -67
- package/dist/umd/test-utils.development.js.map +0 -1
- package/dist/umd/test-utils.production.js +0 -2
- package/dist/umd/test-utils.production.js.map +0 -1
- package/dist/umd/vestjs-runtime.development.js +0 -688
- package/dist/umd/vestjs-runtime.development.js.map +0 -1
- package/dist/umd/vestjs-runtime.production.js +0 -2
- package/dist/umd/vestjs-runtime.production.js.map +0 -1
- package/types/IsolateSerializer.d.ts +0 -42
- package/types/IsolateSerializer.d.ts.map +0 -1
- package/types/test-utils.d.ts +0 -37
- package/types/test-utils.d.ts.map +0 -1
- package/types/vestjs-runtime.d.ts.map +0 -1
|
@@ -0,0 +1,1004 @@
|
|
|
1
|
+
import { t as __export } from "./chunk-CLMFDpHK.mjs";
|
|
2
|
+
import { n as IsolateKeys, t as ExcludedFromDump } from "./IsolateKeys-B21aPuBk.mjs";
|
|
3
|
+
import { StateMachine, asArray, assign, bus, deferThrow, dynamicValue, hasOwnProperty, invariant, isFailure, isNotEmpty, isNotNullish, isNullish, isPromise, isStringValue, isUnsafeKey, makeResult, noop, text, tinyState } from "vest-utils";
|
|
4
|
+
import { createCascade } from "context";
|
|
5
|
+
import { expandObject, minifyObject } from "vest-utils/minifyObject";
|
|
6
|
+
|
|
7
|
+
//#region src/Isolate/IsolateStatus.ts
|
|
8
|
+
const IsolateStatus = {
|
|
9
|
+
DONE: "DONE",
|
|
10
|
+
HAS_PENDING: "HAS_PENDING",
|
|
11
|
+
INITIAL: "INITIAL",
|
|
12
|
+
PENDING: "PENDING"
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/Isolate/IsolateInspector.ts
|
|
17
|
+
var IsolateInspector = class IsolateInspector {
|
|
18
|
+
static at(isolate, at) {
|
|
19
|
+
if (isNullish(isolate)) return null;
|
|
20
|
+
return isolate.children?.[at] ?? null;
|
|
21
|
+
}
|
|
22
|
+
static cursor(isolate) {
|
|
23
|
+
if (isNullish(isolate)) return 0;
|
|
24
|
+
return isolate.children?.length ?? 0;
|
|
25
|
+
}
|
|
26
|
+
static canReorder(isolate) {
|
|
27
|
+
if (isNullish(isolate)) return false;
|
|
28
|
+
return IsolateInspector.allowsReorder(isolate.parent);
|
|
29
|
+
}
|
|
30
|
+
static allowsReorder(isolate) {
|
|
31
|
+
return isolate?.allowReorder === true;
|
|
32
|
+
}
|
|
33
|
+
static usesKey(isolate) {
|
|
34
|
+
if (isNullish(isolate)) return false;
|
|
35
|
+
return isNotNullish(isolate.key);
|
|
36
|
+
}
|
|
37
|
+
static getChildByKey(isolate, key) {
|
|
38
|
+
if (isNullish(isolate)) return null;
|
|
39
|
+
return isolate.keys?.[key] ?? null;
|
|
40
|
+
}
|
|
41
|
+
static getStatus(isolate) {
|
|
42
|
+
if (isNullish(isolate)) return IsolateStatus.INITIAL;
|
|
43
|
+
return isolate.status ?? IsolateStatus.INITIAL;
|
|
44
|
+
}
|
|
45
|
+
static statusEquals(isolate, status) {
|
|
46
|
+
return IsolateInspector.getStatus(isolate) === status;
|
|
47
|
+
}
|
|
48
|
+
static isPending(isolate) {
|
|
49
|
+
return IsolateInspector.statusEquals(isolate, IsolateStatus.PENDING);
|
|
50
|
+
}
|
|
51
|
+
static isHasPending(isolate) {
|
|
52
|
+
return IsolateInspector.statusEquals(isolate, IsolateStatus.HAS_PENDING);
|
|
53
|
+
}
|
|
54
|
+
static hasPending(isolate) {
|
|
55
|
+
return IsolateInspector.isPending(isolate) || IsolateInspector.isHasPending(isolate);
|
|
56
|
+
}
|
|
57
|
+
static hasActiveChildren(isolate) {
|
|
58
|
+
if (isNullish(isolate) || isNullish(isolate.children)) return false;
|
|
59
|
+
return isolate.children.some((child) => IsolateInspector.hasPending(child));
|
|
60
|
+
}
|
|
61
|
+
static getParent(isolate) {
|
|
62
|
+
return isolate?.parent ?? null;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
//#endregion
|
|
67
|
+
//#region src/Isolate/IsolateStateMachine.ts
|
|
68
|
+
const machine = {
|
|
69
|
+
initial: IsolateStatus.INITIAL,
|
|
70
|
+
states: {
|
|
71
|
+
[IsolateStatus.DONE]: {},
|
|
72
|
+
[IsolateStatus.INITIAL]: {
|
|
73
|
+
[IsolateStatus.PENDING]: IsolateStatus.PENDING,
|
|
74
|
+
[IsolateStatus.HAS_PENDING]: IsolateStatus.HAS_PENDING,
|
|
75
|
+
[IsolateStatus.DONE]: IsolateStatus.DONE
|
|
76
|
+
},
|
|
77
|
+
[IsolateStatus.PENDING]: { [IsolateStatus.DONE]: IsolateStatus.DONE },
|
|
78
|
+
[IsolateStatus.HAS_PENDING]: {
|
|
79
|
+
[IsolateStatus.DONE]: [IsolateStatus.DONE, (isolate) => !IsolateInspector.hasActiveChildren(isolate)],
|
|
80
|
+
[IsolateStatus.PENDING]: IsolateStatus.PENDING
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
const IsolateStateMachine = StateMachine(machine);
|
|
85
|
+
|
|
86
|
+
//#endregion
|
|
87
|
+
//#region src/Isolate/IsolateMutator.ts
|
|
88
|
+
function bubbleUpPending(isolate) {
|
|
89
|
+
if (isNullish(isolate)) return;
|
|
90
|
+
if (IsolateInspector.isHasPending(isolate)) return;
|
|
91
|
+
if (isFailure(IsolateMutator.setHasPending(isolate))) return;
|
|
92
|
+
bubbleUpPending(isolate.parent);
|
|
93
|
+
}
|
|
94
|
+
function bubbleUpDone(isolate) {
|
|
95
|
+
if (isNullish(isolate)) return;
|
|
96
|
+
if (!IsolateInspector.isHasPending(isolate)) return;
|
|
97
|
+
if (isFailure(IsolateMutator.setStatus(isolate, IsolateStatus.DONE, isolate))) return;
|
|
98
|
+
bubbleUpDone(isolate.parent);
|
|
99
|
+
}
|
|
100
|
+
var IsolateMutator = class IsolateMutator {
|
|
101
|
+
static setParent(isolate, parent) {
|
|
102
|
+
isolate.parent = parent;
|
|
103
|
+
return isolate;
|
|
104
|
+
}
|
|
105
|
+
static saveOutput(isolate, output) {
|
|
106
|
+
isolate.output = output;
|
|
107
|
+
return isolate;
|
|
108
|
+
}
|
|
109
|
+
static setKey(isolate, key) {
|
|
110
|
+
isolate.key = key;
|
|
111
|
+
return isolate;
|
|
112
|
+
}
|
|
113
|
+
static addChild(isolate, child) {
|
|
114
|
+
invariant(isolate);
|
|
115
|
+
isolate.children = isolate.children ?? [];
|
|
116
|
+
isolate.children.push(child);
|
|
117
|
+
IsolateMutator.setParent(child, isolate);
|
|
118
|
+
if (IsolateInspector.hasPending(child)) bubbleUpPending(isolate);
|
|
119
|
+
}
|
|
120
|
+
static removeChild(isolate, node) {
|
|
121
|
+
isolate.children = isolate.children?.filter((child) => child !== node) ?? null;
|
|
122
|
+
}
|
|
123
|
+
static addChildKey(isolate, key, node) {
|
|
124
|
+
invariant(isolate);
|
|
125
|
+
isolate.keys = isolate.keys ?? {};
|
|
126
|
+
isolate.keys[key] = node;
|
|
127
|
+
}
|
|
128
|
+
static slice(isolate, at) {
|
|
129
|
+
if (isNullish(isolate.children)) return;
|
|
130
|
+
isolate.children.length = at;
|
|
131
|
+
}
|
|
132
|
+
static setData(isolate, data) {
|
|
133
|
+
isolate.data = data;
|
|
134
|
+
}
|
|
135
|
+
static abort(isolate, reason) {
|
|
136
|
+
if (isNullish(isolate.abortController)) return;
|
|
137
|
+
isolate.abortController.abort(reason);
|
|
138
|
+
}
|
|
139
|
+
static setStatus(isolate, status, payload) {
|
|
140
|
+
if (isolate.status === status) return makeResult.Err(`Isolate status is already ${status}`);
|
|
141
|
+
isolate.status = IsolateStateMachine.staticTransition(isolate.status ?? IsolateStatus.INITIAL, status, payload);
|
|
142
|
+
return makeResult.Ok(isolate.status);
|
|
143
|
+
}
|
|
144
|
+
static setPending(isolate) {
|
|
145
|
+
if (isFailure(IsolateMutator.setStatus(isolate, IsolateStatus.PENDING))) return;
|
|
146
|
+
RuntimeApi.registerPending(isolate);
|
|
147
|
+
bubbleUpPending(isolate.parent);
|
|
148
|
+
}
|
|
149
|
+
static setHasPending(isolate) {
|
|
150
|
+
return IsolateMutator.setStatus(isolate, IsolateStatus.HAS_PENDING);
|
|
151
|
+
}
|
|
152
|
+
static setDone(isolate) {
|
|
153
|
+
if (isFailure(IsolateMutator.setStatus(isolate, IsolateStatus.DONE, isolate))) return;
|
|
154
|
+
bubbleUpDone(isolate.parent);
|
|
155
|
+
RuntimeApi.removePending(isolate);
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
//#endregion
|
|
160
|
+
//#region src/IsolateWalker.ts
|
|
161
|
+
var IsolateWalker_exports = /* @__PURE__ */ __export({
|
|
162
|
+
closest: () => closest,
|
|
163
|
+
closestExists: () => closestExists,
|
|
164
|
+
every: () => every,
|
|
165
|
+
find: () => find,
|
|
166
|
+
findAll: () => findAll,
|
|
167
|
+
findClosest: () => findClosest,
|
|
168
|
+
has: () => has,
|
|
169
|
+
mapFirst: () => mapFirst,
|
|
170
|
+
pluck: () => pluck,
|
|
171
|
+
reduce: () => reduce,
|
|
172
|
+
some: () => some,
|
|
173
|
+
walk: () => walk
|
|
174
|
+
});
|
|
175
|
+
/**
|
|
176
|
+
* Walks the isolate tree starting from the given node.
|
|
177
|
+
* @param startNode - The starting node for the traversal.
|
|
178
|
+
* @param callback - The callback function to be called for each visited node.
|
|
179
|
+
* @param visitOnly - Optional predicate to filter which nodes to visit.
|
|
180
|
+
*/
|
|
181
|
+
function walk(startNode, callback, visitOnly) {
|
|
182
|
+
if (!startNode) return makeResult.Ok(void 0);
|
|
183
|
+
const stack = [startNode];
|
|
184
|
+
while (stack.length > 0) {
|
|
185
|
+
const node = stack.pop();
|
|
186
|
+
const res = visit(node, visitOnly, callback);
|
|
187
|
+
if (isFailure(res)) return res;
|
|
188
|
+
if (node.children) pushChildren(stack, node.children);
|
|
189
|
+
}
|
|
190
|
+
return makeResult.Ok(void 0);
|
|
191
|
+
}
|
|
192
|
+
function visit(node, visitOnly, callback) {
|
|
193
|
+
if (shouldVisit(node, visitOnly)) return callback(node);
|
|
194
|
+
return makeResult.Ok(void 0);
|
|
195
|
+
}
|
|
196
|
+
function pushChildren(stack, children) {
|
|
197
|
+
for (let i = children.length - 1; i >= 0; i--) stack.push(children[i]);
|
|
198
|
+
}
|
|
199
|
+
function shouldVisit(node, visitOnly) {
|
|
200
|
+
return isNullish(visitOnly) || dynamicValue(visitOnly, node);
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Reduces the isolate tree to a single value.
|
|
204
|
+
* @param startNode - The starting node for the traversal.
|
|
205
|
+
* @param callback - The reducer function.
|
|
206
|
+
* @param initialValue - The initial value for the accumulator.
|
|
207
|
+
* @param visitOnly - Optional predicate to filter which nodes to visit.
|
|
208
|
+
* @returns The final accumulated value.
|
|
209
|
+
*/
|
|
210
|
+
function reduce(startNode, callback, initialValue, visitOnly) {
|
|
211
|
+
let acc = initialValue;
|
|
212
|
+
walk(startNode, (node) => {
|
|
213
|
+
const res = callback(acc, node);
|
|
214
|
+
if (isFailure(res)) return makeResult.Err(res.error);
|
|
215
|
+
acc = res.unwrap();
|
|
216
|
+
return makeResult.Ok(void 0);
|
|
217
|
+
}, visitOnly);
|
|
218
|
+
return acc;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Checks if any node in the tree satisfies the predicate.
|
|
222
|
+
* @param startNode - The starting node for the traversal.
|
|
223
|
+
* @param predicate - The predicate function to test each node.
|
|
224
|
+
* @param visitOnly - Optional predicate to filter which nodes to visit.
|
|
225
|
+
* @returns True if any node satisfies the predicate, false otherwise.
|
|
226
|
+
*/
|
|
227
|
+
function some(startNode, predicate, visitOnly) {
|
|
228
|
+
let hasMatch = false;
|
|
229
|
+
walk(startNode, (node) => {
|
|
230
|
+
if (predicate(node)) {
|
|
231
|
+
hasMatch = true;
|
|
232
|
+
return makeResult.Err(void 0);
|
|
233
|
+
}
|
|
234
|
+
return makeResult.Ok(void 0);
|
|
235
|
+
}, visitOnly);
|
|
236
|
+
return hasMatch;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Checks if the tree contains a node that matches the predicate.
|
|
240
|
+
* @param startNode - The starting node for the traversal.
|
|
241
|
+
* @param match - The predicate function to match nodes.
|
|
242
|
+
* @returns True if a matching node is found, false otherwise.
|
|
243
|
+
*/
|
|
244
|
+
function has(startNode, match) {
|
|
245
|
+
return some(startNode, () => true, match);
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Traverses up the tree to find the closest ancestor that satisfies the predicate,
|
|
249
|
+
* then returns the first direct descendant of that ancestor that satisfies the predicate.
|
|
250
|
+
* @param startNode - The starting node.
|
|
251
|
+
* @param predicate - The predicate to match.
|
|
252
|
+
* @returns The found node or null.
|
|
253
|
+
*/
|
|
254
|
+
function findClosest(startNode, predicate) {
|
|
255
|
+
let found = null;
|
|
256
|
+
let current = startNode;
|
|
257
|
+
while (current) {
|
|
258
|
+
found = current.children?.find(predicate) ?? null;
|
|
259
|
+
if (found) break;
|
|
260
|
+
current = current.parent;
|
|
261
|
+
}
|
|
262
|
+
return found;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Finds the first node in the tree that satisfies the predicate.
|
|
266
|
+
* @param startNode - The starting node.
|
|
267
|
+
* @param predicate - The predicate to match.
|
|
268
|
+
* @param visitOnly - Optional predicate to filter which nodes to visit.
|
|
269
|
+
* @returns The found node or null.
|
|
270
|
+
*/
|
|
271
|
+
function find(startNode, predicate, visitOnly) {
|
|
272
|
+
let found = null;
|
|
273
|
+
walk(startNode, (node) => {
|
|
274
|
+
if (predicate(node)) {
|
|
275
|
+
found = node;
|
|
276
|
+
return makeResult.Err(void 0);
|
|
277
|
+
}
|
|
278
|
+
return makeResult.Ok(void 0);
|
|
279
|
+
}, visitOnly);
|
|
280
|
+
return found;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Finds all nodes in the tree that satisfy the predicate.
|
|
284
|
+
* @param startNode - The starting node.
|
|
285
|
+
* @param predicate - The predicate to match.
|
|
286
|
+
* @param visitOnly - Optional predicate to filter which nodes to visit.
|
|
287
|
+
* @returns An array of found nodes.
|
|
288
|
+
*/
|
|
289
|
+
function findAll(startNode, predicate, visitOnly) {
|
|
290
|
+
const found = [];
|
|
291
|
+
walk(startNode, (node) => {
|
|
292
|
+
if (predicate(node)) found.push(node);
|
|
293
|
+
return makeResult.Ok(void 0);
|
|
294
|
+
}, visitOnly);
|
|
295
|
+
return found;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Checks if every node in the tree satisfies the predicate.
|
|
299
|
+
* @param startNode - The starting node.
|
|
300
|
+
* @param predicate - The predicate to match.
|
|
301
|
+
* @param visitOnly - Optional predicate to filter which nodes to visit.
|
|
302
|
+
* @returns True if all nodes satisfy the predicate, false otherwise.
|
|
303
|
+
*/
|
|
304
|
+
function every(startNode, predicate, visitOnly) {
|
|
305
|
+
let hasMatch = true;
|
|
306
|
+
walk(startNode, (node) => {
|
|
307
|
+
if (!predicate(node)) {
|
|
308
|
+
hasMatch = false;
|
|
309
|
+
return makeResult.Err(void 0);
|
|
310
|
+
}
|
|
311
|
+
return makeResult.Ok(void 0);
|
|
312
|
+
}, visitOnly);
|
|
313
|
+
return hasMatch;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Removes nodes from the tree that satisfy the predicate.
|
|
317
|
+
* @param startNode - The starting node.
|
|
318
|
+
* @param predicate - The predicate to match nodes to remove.
|
|
319
|
+
* @param visitOnly - Optional predicate to filter which nodes to visit.
|
|
320
|
+
*/
|
|
321
|
+
function pluck(startNode, predicate, visitOnly) {
|
|
322
|
+
walk(startNode, (node) => {
|
|
323
|
+
if (predicate(node) && node.parent) IsolateMutator.removeChild(node.parent, node);
|
|
324
|
+
return makeResult.Ok(void 0);
|
|
325
|
+
}, visitOnly);
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Finds the closest ancestor of the startNode that satisfies the predicate.
|
|
329
|
+
* @param startNode - The starting node.
|
|
330
|
+
* @param predicate - The predicate to match.
|
|
331
|
+
* @returns The found ancestor or null.
|
|
332
|
+
*/
|
|
333
|
+
function closest(startNode, predicate) {
|
|
334
|
+
let current = startNode;
|
|
335
|
+
do {
|
|
336
|
+
if (predicate(current)) return current;
|
|
337
|
+
current = current.parent;
|
|
338
|
+
} while (current);
|
|
339
|
+
return null;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Checks if an ancestor satisfying the predicate exists.
|
|
343
|
+
* @param startNode - The starting node.
|
|
344
|
+
* @param predicate - The predicate to match.
|
|
345
|
+
* @returns True if such an ancestor exists, false otherwise.
|
|
346
|
+
*/
|
|
347
|
+
function closestExists(startNode, predicate) {
|
|
348
|
+
return !!closest(startNode, predicate);
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Traverses the tree and returns the first non-nullish value returned by the callback.
|
|
352
|
+
* It optimizes traversal by only visiting nodes that have pending isolates or are pending themselves.
|
|
353
|
+
*/
|
|
354
|
+
function mapFirst(startNode, callback) {
|
|
355
|
+
const stack = [startNode];
|
|
356
|
+
let result = null;
|
|
357
|
+
const breakout = (value) => result = { value };
|
|
358
|
+
while (stack.length > 0) {
|
|
359
|
+
if (result) break;
|
|
360
|
+
processNode(stack.pop(), stack, callback, breakout);
|
|
361
|
+
}
|
|
362
|
+
return result?.value ?? null;
|
|
363
|
+
}
|
|
364
|
+
function processNode(node, stack, callback, breakout) {
|
|
365
|
+
if (!IsolateInspector.hasPending(node)) return;
|
|
366
|
+
runCallback(node, callback, breakout);
|
|
367
|
+
if (node.children) pushChildren(stack, node.children);
|
|
368
|
+
}
|
|
369
|
+
function runCallback(node, callback, breakout) {
|
|
370
|
+
if (IsolateInspector.isPending(node)) callback(node, breakout);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
//#endregion
|
|
374
|
+
//#region src/Isolate/IsolateTransient.ts
|
|
375
|
+
/**
|
|
376
|
+
* Creates a transient isolate.
|
|
377
|
+
*
|
|
378
|
+
* Transient isolates are isolates that:
|
|
379
|
+
* 1. Do not persist in the history tree.
|
|
380
|
+
* 2. Are not reconciled with previous runs.
|
|
381
|
+
* 3. Do not appear in the serialized suite dump.
|
|
382
|
+
* 4. Do not interfere with the index of their siblings (they are skipped by the reconciler).
|
|
383
|
+
*
|
|
384
|
+
* This is useful for "structural" isolates that are used for control flow or grouping
|
|
385
|
+
* but do not hold state that needs to be preserved between runs, such as `focused` (skip/only) isolates.
|
|
386
|
+
*/
|
|
387
|
+
function IsolateTransient(callback, type = "Transient", payload = {}) {
|
|
388
|
+
return Isolate.create(type, callback, {
|
|
389
|
+
...payload,
|
|
390
|
+
transient: true
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
//#endregion
|
|
395
|
+
//#region src/Isolate/IsolateFocused.ts
|
|
396
|
+
const VestIsolateTypeFocused = "Focused";
|
|
397
|
+
let FocusModes = /* @__PURE__ */ function(FocusModes$1) {
|
|
398
|
+
FocusModes$1["SKIP"] = "skip";
|
|
399
|
+
FocusModes$1["ONLY"] = "only";
|
|
400
|
+
return FocusModes$1;
|
|
401
|
+
}({});
|
|
402
|
+
/**
|
|
403
|
+
* Creates a focused isolate.
|
|
404
|
+
* Focused isolates are transient because they only affect the current run
|
|
405
|
+
* and do not need to be preserved in history or appearing in the suite result.
|
|
406
|
+
*/
|
|
407
|
+
function IsolateFocused(focusMode, match) {
|
|
408
|
+
const matchedFields = asArray(match).filter(isStringValue).filter(isNotEmpty);
|
|
409
|
+
const matchAll = match === true;
|
|
410
|
+
if (!isNotEmpty(matchedFields) && !matchAll) return;
|
|
411
|
+
return IsolateTransient(noop, VestIsolateTypeFocused, {
|
|
412
|
+
focusMode,
|
|
413
|
+
match: matchedFields,
|
|
414
|
+
matchAll
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
var FocusSelectors = class {
|
|
418
|
+
static isSkipFocused(focus, fieldName) {
|
|
419
|
+
if (!focus) return false;
|
|
420
|
+
const data = focus.data;
|
|
421
|
+
if (!data || data.focusMode !== FocusModes.SKIP) return false;
|
|
422
|
+
if (data.matchAll) return true;
|
|
423
|
+
return hasFocus(focus, fieldName);
|
|
424
|
+
}
|
|
425
|
+
static isOnlyFocused(focus, fieldName) {
|
|
426
|
+
if (!focus) return false;
|
|
427
|
+
const data = focus.data;
|
|
428
|
+
if (!data || data.focusMode !== FocusModes.ONLY) return false;
|
|
429
|
+
if (data.matchAll) return true;
|
|
430
|
+
return hasFocus(focus, fieldName);
|
|
431
|
+
}
|
|
432
|
+
static isIsolateFocused(isolate) {
|
|
433
|
+
return isolate[IsolateKeys.Type] === VestIsolateTypeFocused;
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
function hasFocus(focus, fieldName) {
|
|
437
|
+
const match = asArray(focus?.data?.match);
|
|
438
|
+
if (!match.length) return false;
|
|
439
|
+
return !fieldName || match.includes(fieldName);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
//#endregion
|
|
443
|
+
//#region src/errors/ErrorStrings.ts
|
|
444
|
+
let ErrorStrings = /* @__PURE__ */ function(ErrorStrings$1) {
|
|
445
|
+
ErrorStrings$1["NO_ACTIVE_ISOLATE"] = "Not within an active isolate";
|
|
446
|
+
ErrorStrings$1["UNABLE_TO_PICK_NEXT_ISOLATE"] = "Unable to pick next isolate. This is a bug, please report it to the Vest maintainers.";
|
|
447
|
+
ErrorStrings$1["ENCOUNTERED_THE_SAME_KEY_TWICE"] = "Encountered the same key \"{key}\" twice. This may lead to inconsistent or overriding of results.";
|
|
448
|
+
ErrorStrings$1["INVALID_ISOLATE_CANNOT_PARSE"] = "Invalid isolate was passed to IsolateSerializer. Cannot proceed.";
|
|
449
|
+
return ErrorStrings$1;
|
|
450
|
+
}({});
|
|
451
|
+
|
|
452
|
+
//#endregion
|
|
453
|
+
//#region src/Orchestrator/RuntimeStates.ts
|
|
454
|
+
let RuntimeState = /* @__PURE__ */ function(RuntimeState$1) {
|
|
455
|
+
RuntimeState$1["PENDING"] = "PENDING";
|
|
456
|
+
RuntimeState$1["STABLE"] = "STABLE";
|
|
457
|
+
return RuntimeState$1;
|
|
458
|
+
}({});
|
|
459
|
+
|
|
460
|
+
//#endregion
|
|
461
|
+
//#region src/VestRuntime.ts
|
|
462
|
+
const PersistedContext = createCascade((stateRef, parentContext) => {
|
|
463
|
+
if (parentContext) return null;
|
|
464
|
+
invariant(stateRef.historyRoot);
|
|
465
|
+
const ref = stateRef;
|
|
466
|
+
const [historyRootNode] = ref.historyRoot();
|
|
467
|
+
ref.implicitOnlyNodes.clear();
|
|
468
|
+
const ctxRef = {};
|
|
469
|
+
assign(ctxRef, {
|
|
470
|
+
historyNode: historyRootNode,
|
|
471
|
+
runtimeNode: null,
|
|
472
|
+
runtimeRoot: null,
|
|
473
|
+
stateRef
|
|
474
|
+
});
|
|
475
|
+
return ctxRef;
|
|
476
|
+
});
|
|
477
|
+
/**
|
|
478
|
+
* Runs a function within the Vest runtime context.
|
|
479
|
+
* This is the main entry point for executing Vest suites.
|
|
480
|
+
*/
|
|
481
|
+
const Run = PersistedContext.run;
|
|
482
|
+
/**
|
|
483
|
+
* Retrieves the current runtime state (e.g., STABLE, PENDING).
|
|
484
|
+
*/
|
|
485
|
+
function useRuntimeState() {
|
|
486
|
+
return useIsStable() ? RuntimeState.STABLE : RuntimeState.PENDING;
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Checks if the runtime is currently stable (no pending tests).
|
|
490
|
+
*/
|
|
491
|
+
function useIsStable() {
|
|
492
|
+
const root = useAvailableRoot();
|
|
493
|
+
if (!root) return true;
|
|
494
|
+
return !IsolateInspector.hasPending(root);
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Retrieves the application-specific data stored in the runtime.
|
|
498
|
+
*/
|
|
499
|
+
function useXAppData() {
|
|
500
|
+
return useX().stateRef.appData;
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Creates a new state reference for such as the history root, pending isolates, and the current runtime state.
|
|
504
|
+
*/
|
|
505
|
+
function createRef(Reconciler$1, setter) {
|
|
506
|
+
return Object.freeze({
|
|
507
|
+
Bus: bus.createBus(),
|
|
508
|
+
Reconciler: Reconciler$1,
|
|
509
|
+
appData: dynamicValue(setter),
|
|
510
|
+
historyRoot: tinyState.createTinyState(null),
|
|
511
|
+
implicitOnlyNodes: /* @__PURE__ */ new Set()
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Dispatches a runtime event to the internal Bus.
|
|
516
|
+
* This is used to trigger state changes and notifications.
|
|
517
|
+
*/
|
|
518
|
+
function dispatch(event) {
|
|
519
|
+
useX().stateRef.Bus.emit(event.type, event.payload);
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Registers an isolate as pending.
|
|
523
|
+
* This is used to track async tests and other async operations.
|
|
524
|
+
*/
|
|
525
|
+
function registerPending(isolate) {
|
|
526
|
+
dispatch({
|
|
527
|
+
type: "ISOLATE_PENDING",
|
|
528
|
+
payload: isolate
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Removes an isolate from the pending set.
|
|
533
|
+
* This is used when an async test or operation completes.
|
|
534
|
+
*/
|
|
535
|
+
function removePending(isolate) {
|
|
536
|
+
dispatch({
|
|
537
|
+
type: "ISOLATE_DONE",
|
|
538
|
+
payload: isolate
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Retrieves the Reconciler used by the current runtime.
|
|
543
|
+
*/
|
|
544
|
+
function useReconciler() {
|
|
545
|
+
return useX().stateRef.Reconciler;
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Persists the current runtime context to a callback function.
|
|
549
|
+
* This allows the callback to be executed later (e.g. in an async operation)
|
|
550
|
+
* while still having access to the correct runtime context.
|
|
551
|
+
*/
|
|
552
|
+
function persist(cb) {
|
|
553
|
+
const prev = PersistedContext.useX();
|
|
554
|
+
return ((...args) => {
|
|
555
|
+
const ctxToUse = PersistedContext.use() ?? prev;
|
|
556
|
+
return PersistedContext.run(ctxToUse.stateRef, () => cb(...args));
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Retrieves the current runtime context.
|
|
561
|
+
* Throws if called outside of a Vest runtime.
|
|
562
|
+
*/
|
|
563
|
+
function useX() {
|
|
564
|
+
return PersistedContext.useX();
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Retrieves the history root state.
|
|
568
|
+
*/
|
|
569
|
+
function useHistoryRoot() {
|
|
570
|
+
return useX().stateRef.historyRoot();
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Retrieves the current history isolate (the one matching the current runtime isolate).
|
|
574
|
+
*/
|
|
575
|
+
function useHistoryIsolate() {
|
|
576
|
+
return useX().historyNode;
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Returns the history isolate at the current position.
|
|
580
|
+
* If there is a parent isolate, it returns the history node from the parent's children.
|
|
581
|
+
* Otherwise, it returns the history node.
|
|
582
|
+
* @returns {Nullable<TIsolate>} The history isolate at the current position.
|
|
583
|
+
*/
|
|
584
|
+
function useHistoryIsolateAtCurrentPosition() {
|
|
585
|
+
const parent = useIsolate();
|
|
586
|
+
const historyNode = useHistoryIsolate();
|
|
587
|
+
if (!parent) return historyNode;
|
|
588
|
+
if (isNullish(historyNode)) return null;
|
|
589
|
+
const nonTransientIndex = countNonTransientBefore(parent.children || [], IsolateInspector.cursor(parent));
|
|
590
|
+
return findNthNonTransient(historyNode.children || [], nonTransientIndex);
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Counts non-transient children before the given cursor position.
|
|
594
|
+
*/
|
|
595
|
+
function countNonTransientBefore(siblings, cursor) {
|
|
596
|
+
let count = 0;
|
|
597
|
+
for (let i = 0; i < cursor; i++) if (!siblings[i]?.transient) count++;
|
|
598
|
+
return count;
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* Finds the Nth non-transient child in a children array.
|
|
602
|
+
* This is used to align the reconciler cursor, skipping over
|
|
603
|
+
* transient nodes that should not affect the index of stateful nodes.
|
|
604
|
+
*/
|
|
605
|
+
function findNthNonTransient(children, n) {
|
|
606
|
+
return children.filter((child) => child && !child.transient)[n] ?? null;
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Sets the history root for the runtime.
|
|
610
|
+
* This is used to hydrate the runtime with previous results.
|
|
611
|
+
*/
|
|
612
|
+
function useSetHistoryRoot(history) {
|
|
613
|
+
const [, setHistoryRoot] = useHistoryRoot();
|
|
614
|
+
setHistoryRoot(history);
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Retrieves the currently active isolate in the runtime tree.
|
|
618
|
+
*/
|
|
619
|
+
function useIsolate() {
|
|
620
|
+
return useX().runtimeNode ?? null;
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* Retrieves the current cursor position within the active isolate.
|
|
624
|
+
*/
|
|
625
|
+
function useCurrentCursor() {
|
|
626
|
+
const isolate = useIsolate();
|
|
627
|
+
return isolate ? IsolateInspector.cursor(isolate) : 0;
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Retrieves the root of the current runtime tree.
|
|
631
|
+
*/
|
|
632
|
+
function useRuntimeRoot() {
|
|
633
|
+
return useX().runtimeRoot;
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Adds a child isolate to the current isolate and sets the parent-child relationship.
|
|
637
|
+
*/
|
|
638
|
+
function useSetNextIsolateChild(child) {
|
|
639
|
+
const currentIsolate = useIsolate();
|
|
640
|
+
invariant(currentIsolate, ErrorStrings.NO_ACTIVE_ISOLATE);
|
|
641
|
+
IsolateMutator.addChild(currentIsolate, child);
|
|
642
|
+
IsolateMutator.setParent(child, currentIsolate);
|
|
643
|
+
if (FocusSelectors.isIsolateFocused(child) && child.data?.focusMode === FocusModes.ONLY) useX().stateRef.implicitOnlyNodes.add(currentIsolate);
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* Sets a key for a child isolate within the current isolate.
|
|
647
|
+
* Throws if the key is already taken.
|
|
648
|
+
*/
|
|
649
|
+
function useSetIsolateKey(key, node) {
|
|
650
|
+
if (!key) return;
|
|
651
|
+
const currentIsolate = useIsolate();
|
|
652
|
+
invariant(currentIsolate, ErrorStrings.NO_ACTIVE_ISOLATE);
|
|
653
|
+
if (isNullish(IsolateInspector.getChildByKey(currentIsolate, key))) {
|
|
654
|
+
IsolateMutator.addChildKey(currentIsolate, key, node);
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
deferThrow(text(ErrorStrings.ENCOUNTERED_THE_SAME_KEY_TWICE, { key }));
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Returns the available root isolate.
|
|
661
|
+
* If a runtime root exists (i.e. we are currently running a suite), it returns that.
|
|
662
|
+
* Otherwise, it returns the history root (i.e. the result of the last run).
|
|
663
|
+
*/
|
|
664
|
+
function useAvailableRoot() {
|
|
665
|
+
const root = useRuntimeRoot();
|
|
666
|
+
if (root) return root;
|
|
667
|
+
const [historyRoot] = useHistoryRoot();
|
|
668
|
+
return historyRoot;
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Checks whether a specific key is heavily focused out.
|
|
672
|
+
*/
|
|
673
|
+
function useIsFocusedOut(key) {
|
|
674
|
+
const current = useIsolate();
|
|
675
|
+
if (!current) return false;
|
|
676
|
+
const focusMatch = findClosest(current, (child) => {
|
|
677
|
+
if (!FocusSelectors.isIsolateFocused(child)) return false;
|
|
678
|
+
const data = child.data;
|
|
679
|
+
if (!data) return false;
|
|
680
|
+
if (data.matchAll) return true;
|
|
681
|
+
if (isNullish(key)) return false;
|
|
682
|
+
return asArray(data.match).includes(key);
|
|
683
|
+
});
|
|
684
|
+
if (focusMatch) {
|
|
685
|
+
if (FocusSelectors.isSkipFocused(focusMatch, key)) return true;
|
|
686
|
+
if (FocusSelectors.isOnlyFocused(focusMatch, key)) return false;
|
|
687
|
+
}
|
|
688
|
+
return hasImplicitOnly();
|
|
689
|
+
}
|
|
690
|
+
function hasImplicitOnly() {
|
|
691
|
+
let current = useIsolate();
|
|
692
|
+
const registry = useX().stateRef.implicitOnlyNodes;
|
|
693
|
+
while (current) {
|
|
694
|
+
if (registry.has(current)) return true;
|
|
695
|
+
current = current.parent;
|
|
696
|
+
}
|
|
697
|
+
return false;
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Resets the history root.
|
|
701
|
+
*/
|
|
702
|
+
function reset() {
|
|
703
|
+
const [, , resetHistoryRoot] = useHistoryRoot();
|
|
704
|
+
resetHistoryRoot();
|
|
705
|
+
}
|
|
706
|
+
const RuntimeApi = {
|
|
707
|
+
Run,
|
|
708
|
+
createRef,
|
|
709
|
+
dispatch,
|
|
710
|
+
hasImplicitOnly,
|
|
711
|
+
persist,
|
|
712
|
+
registerPending,
|
|
713
|
+
removePending,
|
|
714
|
+
reset,
|
|
715
|
+
useAvailableRoot,
|
|
716
|
+
useCurrentCursor,
|
|
717
|
+
useHistoryRoot,
|
|
718
|
+
useIsFocusedOut,
|
|
719
|
+
useIsStable,
|
|
720
|
+
useRuntimeState,
|
|
721
|
+
useSetHistoryRoot,
|
|
722
|
+
useSetNextIsolateChild,
|
|
723
|
+
useXAppData
|
|
724
|
+
};
|
|
725
|
+
|
|
726
|
+
//#endregion
|
|
727
|
+
//#region src/Bus.ts
|
|
728
|
+
var Bus_exports = /* @__PURE__ */ __export({
|
|
729
|
+
useBus: () => useBus,
|
|
730
|
+
useEmit: () => useEmit,
|
|
731
|
+
usePrepareEmitter: () => usePrepareEmitter
|
|
732
|
+
});
|
|
733
|
+
function useBus() {
|
|
734
|
+
return useX().stateRef.Bus;
|
|
735
|
+
}
|
|
736
|
+
function useEmit(event, data) {
|
|
737
|
+
const emit = useBus().emit;
|
|
738
|
+
if (!isNullish(event)) emit(event, data);
|
|
739
|
+
return persist(emit);
|
|
740
|
+
}
|
|
741
|
+
function usePrepareEmitter(event) {
|
|
742
|
+
const emit = useEmit();
|
|
743
|
+
return (arg) => emit(event, arg);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
//#endregion
|
|
747
|
+
//#region src/Isolate/IsolateIndexer.ts
|
|
748
|
+
function createHistoryIndex(children) {
|
|
749
|
+
const index = /* @__PURE__ */ new Map();
|
|
750
|
+
if (!children) return index;
|
|
751
|
+
for (const child of children) addToIndex(index, child);
|
|
752
|
+
return index;
|
|
753
|
+
}
|
|
754
|
+
function addToIndex(index, isolate) {
|
|
755
|
+
const { key } = isolate;
|
|
756
|
+
if (isNullish(key)) return;
|
|
757
|
+
const existing = index.get(key);
|
|
758
|
+
if (existing) if (Array.isArray(existing)) existing.push(isolate);
|
|
759
|
+
else index.set(key, [existing, isolate]);
|
|
760
|
+
else index.set(key, isolate);
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
//#endregion
|
|
764
|
+
//#region src/Isolate/IsolateSelectors.ts
|
|
765
|
+
var IsolateSelectors_exports = /* @__PURE__ */ __export({
|
|
766
|
+
isIsolateType: () => isIsolateType,
|
|
767
|
+
isSameIsolateIdentity: () => isSameIsolateIdentity,
|
|
768
|
+
isSameIsolateType: () => isSameIsolateType
|
|
769
|
+
});
|
|
770
|
+
function isIsolateType(node, type) {
|
|
771
|
+
return node?.[IsolateKeys.Type] === type;
|
|
772
|
+
}
|
|
773
|
+
function isSameIsolateType(a, b) {
|
|
774
|
+
return isIsolateType(a, b[IsolateKeys.Type]);
|
|
775
|
+
}
|
|
776
|
+
function isSameIsolateIdentity(a, b) {
|
|
777
|
+
return Object.is(a, b) || isSameIsolateType(a, b) && a.key === b.key;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
//#endregion
|
|
781
|
+
//#region src/Reconciler.ts
|
|
782
|
+
function BaseReconciler(currentNode, historyNode) {
|
|
783
|
+
if (isNullish(historyNode)) return currentNode;
|
|
784
|
+
return currentNode;
|
|
785
|
+
}
|
|
786
|
+
var Reconciler = class {
|
|
787
|
+
/**
|
|
788
|
+
* Reconciles the current isolate with the history isolate.
|
|
789
|
+
* If the current isolate is of a different type than the history isolate,
|
|
790
|
+
* the current isolate is returned.
|
|
791
|
+
* Otherwise, the reconciler function is called to determine the next isolate.
|
|
792
|
+
* If the reconciler function returns null or undefined, the base reconciler is used.
|
|
793
|
+
* If no history isolate exists, the current isolate is returned.
|
|
794
|
+
* @param node The current isolate to reconcile.
|
|
795
|
+
* @returns The next isolate after reconciliation.
|
|
796
|
+
*/
|
|
797
|
+
static reconcile(node) {
|
|
798
|
+
if (node.transient) return node;
|
|
799
|
+
const nextNodeResult = pickNextNode(node, useHistoryIsolateAtCurrentPosition());
|
|
800
|
+
invariant(nextNodeResult, ErrorStrings.UNABLE_TO_PICK_NEXT_ISOLATE);
|
|
801
|
+
return nextNodeResult;
|
|
802
|
+
}
|
|
803
|
+
static dropNextNodesOnReorder(reorderLogic, newNode, prevNode) {
|
|
804
|
+
const didReorder = reorderLogic(newNode, prevNode);
|
|
805
|
+
if (didReorder) removeAllNextNodesInIsolate();
|
|
806
|
+
return didReorder;
|
|
807
|
+
}
|
|
808
|
+
static handleIsolateNodeWithKey(node, revoke) {
|
|
809
|
+
invariant(IsolateInspector.usesKey(node));
|
|
810
|
+
const prevNodeByKey = getNodeByKey(node.key);
|
|
811
|
+
let nextNode = node;
|
|
812
|
+
if (!isNullish(prevNodeByKey) && !dynamicValue(revoke, prevNodeByKey)) nextNode = prevNodeByKey;
|
|
813
|
+
useSetIsolateKey(node.key, nextNode);
|
|
814
|
+
return nextNode;
|
|
815
|
+
}
|
|
816
|
+
};
|
|
817
|
+
function pickNextNode(currentNode, historyNode) {
|
|
818
|
+
if (isNullish(historyNode)) return handleNoHistoryNode(currentNode);
|
|
819
|
+
if (!isSameIsolateType(currentNode, historyNode)) return currentNode;
|
|
820
|
+
return useReconciler()(currentNode, historyNode) ?? BaseReconciler(currentNode, historyNode);
|
|
821
|
+
}
|
|
822
|
+
function handleNoHistoryNode(newNode) {
|
|
823
|
+
if (IsolateInspector.usesKey(newNode)) return Reconciler.handleIsolateNodeWithKey(newNode, false);
|
|
824
|
+
return newNode;
|
|
825
|
+
}
|
|
826
|
+
function removeAllNextNodesInIsolate() {
|
|
827
|
+
const currentNode = useIsolate();
|
|
828
|
+
const historyNode = useHistoryIsolate();
|
|
829
|
+
if (!historyNode || !currentNode)
|
|
830
|
+
/* istanbul ignore next */
|
|
831
|
+
return;
|
|
832
|
+
IsolateMutator.slice(historyNode, IsolateInspector.cursor(currentNode));
|
|
833
|
+
}
|
|
834
|
+
const historyIndexCache = /* @__PURE__ */ new WeakMap();
|
|
835
|
+
function getNodeByKey(key) {
|
|
836
|
+
const historyParent = useHistoryIsolate();
|
|
837
|
+
if (isNullish(key) || !historyParent) return null;
|
|
838
|
+
const match = getHistoryIndex(historyParent).get(key);
|
|
839
|
+
if (!match) return null;
|
|
840
|
+
if (Array.isArray(match)) return match[0];
|
|
841
|
+
return match;
|
|
842
|
+
}
|
|
843
|
+
function getHistoryIndex(historyParent) {
|
|
844
|
+
let index = historyIndexCache.get(historyParent);
|
|
845
|
+
if (!index) {
|
|
846
|
+
index = createHistoryIndex(historyParent.children);
|
|
847
|
+
historyIndexCache.set(historyParent, index);
|
|
848
|
+
}
|
|
849
|
+
return index;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
//#endregion
|
|
853
|
+
//#region src/Isolate/Isolate.ts
|
|
854
|
+
let _IsolateKeys$Keys, _IsolateKeys$Parent, _IsolateKeys$AllowReo, _IsolateKeys$Transien, _IsolateKeys$Status, _IsolateKeys$AbortCon;
|
|
855
|
+
var Isolate = class {
|
|
856
|
+
static create(type, callback, payload = void 0, key) {
|
|
857
|
+
const parent = useIsolate();
|
|
858
|
+
const newCreatedNode = IsolateMutator.setParent(baseIsolate(type, payload, key), parent);
|
|
859
|
+
const nextIsolateChild = Reconciler.reconcile(newCreatedNode);
|
|
860
|
+
const localHistoryNode = useHistoryIsolateAtCurrentPosition();
|
|
861
|
+
const shouldRunNew = Object.is(nextIsolateChild, newCreatedNode);
|
|
862
|
+
if (parent) useSetNextIsolateChild(nextIsolateChild);
|
|
863
|
+
let output;
|
|
864
|
+
if (shouldRunNew) output = useRunAsNew(localHistoryNode, newCreatedNode, callback);
|
|
865
|
+
else {
|
|
866
|
+
const emit = useEmit();
|
|
867
|
+
output = nextIsolateChild.output;
|
|
868
|
+
emit("ISOLATE_RECONCILED", nextIsolateChild);
|
|
869
|
+
}
|
|
870
|
+
IsolateMutator.saveOutput(nextIsolateChild, output);
|
|
871
|
+
if (!parent) useSetHistoryRoot(nextIsolateChild);
|
|
872
|
+
return nextIsolateChild;
|
|
873
|
+
}
|
|
874
|
+
static isIsolate(node) {
|
|
875
|
+
return isNotNullish(node) && node[IsolateKeys.Type];
|
|
876
|
+
}
|
|
877
|
+
};
|
|
878
|
+
/**
|
|
879
|
+
* Creates a new child isolate context where the local history node is the current history node, thus advancing the history cursor.
|
|
880
|
+
* Runs the callback function and returns its output.
|
|
881
|
+
* @param localHistoryNode The local history node.
|
|
882
|
+
* @param current The current isolate.
|
|
883
|
+
* @param callback The callback function to execute.
|
|
884
|
+
* @returns The output of the callback function.
|
|
885
|
+
*/
|
|
886
|
+
function useRunAsNew(localHistoryNode, current, callback) {
|
|
887
|
+
const runtimeRoot = useRuntimeRoot();
|
|
888
|
+
const output = Run({
|
|
889
|
+
historyNode: localHistoryNode,
|
|
890
|
+
runtimeNode: current,
|
|
891
|
+
...!runtimeRoot && { runtimeRoot: current }
|
|
892
|
+
}, () => useRunAsNewCallback(current, callback));
|
|
893
|
+
current.output = output;
|
|
894
|
+
return output;
|
|
895
|
+
}
|
|
896
|
+
function useRunAsNewCallback(current, callback) {
|
|
897
|
+
const emit = useEmit();
|
|
898
|
+
emit("ISOLATE_ENTER", current);
|
|
899
|
+
const output = callback(current);
|
|
900
|
+
if (isPromise(output)) {
|
|
901
|
+
emit("ISOLATE_PENDING", current);
|
|
902
|
+
IsolateMutator.setPending(current);
|
|
903
|
+
output.then(persist((iso) => {
|
|
904
|
+
if (Isolate.isIsolate(iso)) IsolateMutator.addChild(current, iso);
|
|
905
|
+
IsolateMutator.setDone(current);
|
|
906
|
+
emit("ASYNC_ISOLATE_DONE", current);
|
|
907
|
+
}), persist(() => {
|
|
908
|
+
IsolateMutator.setDone(current);
|
|
909
|
+
emit("ASYNC_ISOLATE_DONE", current);
|
|
910
|
+
}));
|
|
911
|
+
} else IsolateMutator.setDone(current);
|
|
912
|
+
return output;
|
|
913
|
+
}
|
|
914
|
+
var IsolateInstance = class {
|
|
915
|
+
static {
|
|
916
|
+
IsolateKeys.Type, _IsolateKeys$Keys = IsolateKeys.Keys, _IsolateKeys$Parent = IsolateKeys.Parent, _IsolateKeys$AllowReo = IsolateKeys.AllowReorder, _IsolateKeys$Transien = IsolateKeys.Transient, _IsolateKeys$Status = IsolateKeys.Status, _IsolateKeys$AbortCon = IsolateKeys.AbortController, IsolateKeys.Data;
|
|
917
|
+
}
|
|
918
|
+
constructor(type, payload = void 0, key = null) {
|
|
919
|
+
this.children = null;
|
|
920
|
+
this[_IsolateKeys$Keys] = null;
|
|
921
|
+
this[_IsolateKeys$Parent] = null;
|
|
922
|
+
this.output = null;
|
|
923
|
+
this.key = null;
|
|
924
|
+
this[_IsolateKeys$AllowReo] = void 0;
|
|
925
|
+
this[_IsolateKeys$Transien] = void 0;
|
|
926
|
+
this[_IsolateKeys$Status] = IsolateStatus.INITIAL;
|
|
927
|
+
this[_IsolateKeys$AbortCon] = null;
|
|
928
|
+
this[IsolateKeys.Type] = type;
|
|
929
|
+
this.key = key;
|
|
930
|
+
const { allowReorder, transient, status, ...data } = payload ?? {};
|
|
931
|
+
this[IsolateKeys.AllowReorder] = allowReorder;
|
|
932
|
+
this[IsolateKeys.Transient] = transient;
|
|
933
|
+
if (status) this[IsolateKeys.Status] = status;
|
|
934
|
+
this[IsolateKeys.Data] = data;
|
|
935
|
+
}
|
|
936
|
+
};
|
|
937
|
+
function baseIsolate(type, payload = void 0, key = null) {
|
|
938
|
+
return new IsolateInstance(type, payload, key);
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
//#endregion
|
|
942
|
+
//#region src/exports/IsolateSerializer.ts
|
|
943
|
+
var IsolateSerializer = class IsolateSerializer {
|
|
944
|
+
static safeDeserialize(node) {
|
|
945
|
+
try {
|
|
946
|
+
const expanded = expandNode(node);
|
|
947
|
+
if (isFailure(IsolateSerializer.validateIsolate(expanded))) return makeResult.Err(new Error(ErrorStrings.INVALID_ISOLATE_CANNOT_PARSE));
|
|
948
|
+
return makeResult.Ok(hydrateIsolate(expanded));
|
|
949
|
+
} catch (error) {
|
|
950
|
+
return makeResult.Err(error instanceof Error ? error : new Error(String(error)));
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
static deserialize(node) {
|
|
954
|
+
return IsolateSerializer.safeDeserialize(node).unwrap();
|
|
955
|
+
}
|
|
956
|
+
static serialize(isolate, replacer) {
|
|
957
|
+
if (isNullish(isolate)) return "";
|
|
958
|
+
const minified = minifyObject(isolate, (value, key) => {
|
|
959
|
+
if (ExcludedFromDump.has(key)) return;
|
|
960
|
+
if (value?.transient) return;
|
|
961
|
+
if (replacer) return replacer(value, key);
|
|
962
|
+
return value;
|
|
963
|
+
});
|
|
964
|
+
return JSON.stringify(minified);
|
|
965
|
+
}
|
|
966
|
+
static validateIsolate(node) {
|
|
967
|
+
return hasOwnProperty(node, IsolateKeys.Type) ? makeResult.Ok(node) : makeResult.Err(text(ErrorStrings.INVALID_ISOLATE_CANNOT_PARSE));
|
|
968
|
+
}
|
|
969
|
+
};
|
|
970
|
+
function processChildren(current, queue) {
|
|
971
|
+
const children = current.children;
|
|
972
|
+
if (!children) return;
|
|
973
|
+
current.children = children.map((child) => {
|
|
974
|
+
const nextChild = { ...child };
|
|
975
|
+
IsolateMutator.setParent(nextChild, current);
|
|
976
|
+
queue.push(nextChild);
|
|
977
|
+
if (nextChild.key) {
|
|
978
|
+
current.keys = current.keys ?? {};
|
|
979
|
+
current.keys[nextChild.key] = nextChild;
|
|
980
|
+
}
|
|
981
|
+
return nextChild;
|
|
982
|
+
});
|
|
983
|
+
}
|
|
984
|
+
function hydrateIsolate(root) {
|
|
985
|
+
const queue = [root];
|
|
986
|
+
while (queue.length) {
|
|
987
|
+
const current = queue.shift();
|
|
988
|
+
if (current) processChildren(current, queue);
|
|
989
|
+
}
|
|
990
|
+
return root;
|
|
991
|
+
}
|
|
992
|
+
function expandNode(node) {
|
|
993
|
+
const parsed = isStringValue(node) ? JSON.parse(node, safeReviver) : { ...node };
|
|
994
|
+
const root = Array.isArray(parsed) ? parsed : [parsed, {}];
|
|
995
|
+
return expandObject(root[0], root[1]);
|
|
996
|
+
}
|
|
997
|
+
function safeReviver(key, value) {
|
|
998
|
+
if (isUnsafeKey(key)) return;
|
|
999
|
+
return value;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
//#endregion
|
|
1003
|
+
export { Bus_exports as a, FocusModes as c, IsolateTransient as d, IsolateWalker_exports as f, IsolateStatus as g, IsolateInspector as h, IsolateSelectors_exports as i, FocusSelectors as l, IsolateStateMachine as m, Isolate as n, RuntimeApi as o, IsolateMutator as p, Reconciler as r, useAvailableRoot as s, IsolateSerializer as t, IsolateFocused as u };
|
|
1004
|
+
//# sourceMappingURL=IsolateSerializer-B1hE3gmT.mjs.map
|