jotai-state-tree 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +168 -0
- package/dist/chunk-XXZK62DD.mjs +931 -0
- package/dist/index.d.mts +1109 -0
- package/dist/index.d.ts +1109 -0
- package/dist/index.js +3579 -0
- package/dist/index.mjs +2625 -0
- package/dist/react.d.mts +144 -0
- package/dist/react.d.ts +144 -0
- package/dist/react.js +1259 -0
- package/dist/react.mjs +372 -0
- package/package.json +77 -0
- package/src/__tests__/index.test.ts +1371 -0
- package/src/__tests__/memory.test.ts +681 -0
- package/src/__tests__/performance.test.ts +667 -0
- package/src/__tests__/react.react.test.tsx +811 -0
- package/src/__tests__/registry.test.ts +589 -0
- package/src/array.ts +335 -0
- package/src/compat.ts +294 -0
- package/src/index.ts +647 -0
- package/src/lifecycle.ts +580 -0
- package/src/map.ts +276 -0
- package/src/model.ts +832 -0
- package/src/primitives.ts +400 -0
- package/src/react.ts +626 -0
- package/src/registry.ts +741 -0
- package/src/tree.ts +1275 -0
- package/src/types.ts +520 -0
- package/src/undo.ts +566 -0
- package/src/utilities.ts +616 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2625 @@
|
|
|
1
|
+
import {
|
|
2
|
+
$treenode,
|
|
3
|
+
StateTreeNode,
|
|
4
|
+
__toCommonJS,
|
|
5
|
+
applyPatch,
|
|
6
|
+
applySnapshot,
|
|
7
|
+
cleanupStaleEntries,
|
|
8
|
+
clearAllRegistries,
|
|
9
|
+
clone,
|
|
10
|
+
cloneDeep,
|
|
11
|
+
destroy,
|
|
12
|
+
detach,
|
|
13
|
+
findAll,
|
|
14
|
+
findFirst,
|
|
15
|
+
freeze,
|
|
16
|
+
getEnv,
|
|
17
|
+
getGlobalStore,
|
|
18
|
+
getIdentifier,
|
|
19
|
+
getMembers,
|
|
20
|
+
getOrCreatePath,
|
|
21
|
+
getParent,
|
|
22
|
+
getParentOfType,
|
|
23
|
+
getPath,
|
|
24
|
+
getPathParts,
|
|
25
|
+
getRegistryStats,
|
|
26
|
+
getRelativePath,
|
|
27
|
+
getRoot,
|
|
28
|
+
getSnapshot,
|
|
29
|
+
getStateTreeNode,
|
|
30
|
+
getTreeStats,
|
|
31
|
+
getType,
|
|
32
|
+
hasParent,
|
|
33
|
+
hasStateTreeNode,
|
|
34
|
+
haveSameRoot,
|
|
35
|
+
init_tree,
|
|
36
|
+
isAlive,
|
|
37
|
+
isAncestor,
|
|
38
|
+
isFrozen,
|
|
39
|
+
isRoot,
|
|
40
|
+
isStateTreeNode,
|
|
41
|
+
isValidReference,
|
|
42
|
+
onAction,
|
|
43
|
+
onLifecycleChange,
|
|
44
|
+
onPatch,
|
|
45
|
+
onSnapshot,
|
|
46
|
+
recordPatches,
|
|
47
|
+
registerActionRecorderHook,
|
|
48
|
+
resetGlobalStore,
|
|
49
|
+
resolveIdentifier,
|
|
50
|
+
resolvePath,
|
|
51
|
+
setGlobalStore,
|
|
52
|
+
trackAction,
|
|
53
|
+
tree_exports,
|
|
54
|
+
tryGetParent,
|
|
55
|
+
tryResolve,
|
|
56
|
+
unfreeze,
|
|
57
|
+
walk
|
|
58
|
+
} from "./chunk-XXZK62DD.mjs";
|
|
59
|
+
|
|
60
|
+
// src/primitives.ts
|
|
61
|
+
function createSimpleType(name, validator, defaultValue) {
|
|
62
|
+
return {
|
|
63
|
+
name,
|
|
64
|
+
_kind: "simple",
|
|
65
|
+
_C: void 0,
|
|
66
|
+
_S: void 0,
|
|
67
|
+
_T: void 0,
|
|
68
|
+
create(snapshot) {
|
|
69
|
+
if (snapshot === void 0) {
|
|
70
|
+
if (defaultValue !== void 0) {
|
|
71
|
+
return defaultValue;
|
|
72
|
+
}
|
|
73
|
+
throw new Error(`[jotai-state-tree] A value of type '${name}' is required`);
|
|
74
|
+
}
|
|
75
|
+
if (!validator(snapshot)) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
`[jotai-state-tree] Value '${String(snapshot)}' is not a valid '${name}'`
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
return snapshot;
|
|
81
|
+
},
|
|
82
|
+
is(value) {
|
|
83
|
+
return validator(value);
|
|
84
|
+
},
|
|
85
|
+
validate(value, context) {
|
|
86
|
+
if (validator(value)) {
|
|
87
|
+
return { valid: true, errors: [] };
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
valid: false,
|
|
91
|
+
errors: [
|
|
92
|
+
{
|
|
93
|
+
context,
|
|
94
|
+
value,
|
|
95
|
+
message: `Value '${String(value)}' is not a valid '${name}'`
|
|
96
|
+
}
|
|
97
|
+
]
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
var string = createSimpleType(
|
|
103
|
+
"string",
|
|
104
|
+
(value) => typeof value === "string"
|
|
105
|
+
);
|
|
106
|
+
var number = createSimpleType(
|
|
107
|
+
"number",
|
|
108
|
+
(value) => typeof value === "number" && !isNaN(value)
|
|
109
|
+
);
|
|
110
|
+
var integer = createSimpleType(
|
|
111
|
+
"integer",
|
|
112
|
+
(value) => typeof value === "number" && !isNaN(value) && Number.isInteger(value)
|
|
113
|
+
);
|
|
114
|
+
var boolean = createSimpleType(
|
|
115
|
+
"boolean",
|
|
116
|
+
(value) => typeof value === "boolean"
|
|
117
|
+
);
|
|
118
|
+
var DatePrimitive = {
|
|
119
|
+
name: "Date",
|
|
120
|
+
_kind: "simple",
|
|
121
|
+
_C: void 0,
|
|
122
|
+
_S: void 0,
|
|
123
|
+
_T: void 0,
|
|
124
|
+
create(snapshot) {
|
|
125
|
+
if (snapshot === void 0) {
|
|
126
|
+
return /* @__PURE__ */ new Date();
|
|
127
|
+
}
|
|
128
|
+
if (snapshot instanceof Date) {
|
|
129
|
+
return snapshot;
|
|
130
|
+
}
|
|
131
|
+
if (typeof snapshot === "number") {
|
|
132
|
+
return new Date(snapshot);
|
|
133
|
+
}
|
|
134
|
+
throw new Error(`[jotai-state-tree] Value is not a valid Date`);
|
|
135
|
+
},
|
|
136
|
+
is(value) {
|
|
137
|
+
return value instanceof Date;
|
|
138
|
+
},
|
|
139
|
+
validate(value, context) {
|
|
140
|
+
if (value instanceof Date || typeof value === "number") {
|
|
141
|
+
return { valid: true, errors: [] };
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
valid: false,
|
|
145
|
+
errors: [
|
|
146
|
+
{
|
|
147
|
+
context,
|
|
148
|
+
value,
|
|
149
|
+
message: "Value is not a valid Date"
|
|
150
|
+
}
|
|
151
|
+
]
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
var nullType = createSimpleType(
|
|
156
|
+
"null",
|
|
157
|
+
(value) => value === null
|
|
158
|
+
);
|
|
159
|
+
var undefinedType = createSimpleType(
|
|
160
|
+
"undefined",
|
|
161
|
+
(value) => value === void 0
|
|
162
|
+
);
|
|
163
|
+
var identifier = {
|
|
164
|
+
...createSimpleType(
|
|
165
|
+
"identifier",
|
|
166
|
+
(value) => typeof value === "string"
|
|
167
|
+
),
|
|
168
|
+
_kind: "identifier",
|
|
169
|
+
identifierAttribute: "id"
|
|
170
|
+
};
|
|
171
|
+
var identifierNumber = {
|
|
172
|
+
...createSimpleType(
|
|
173
|
+
"identifierNumber",
|
|
174
|
+
(value) => typeof value === "number" && !isNaN(value)
|
|
175
|
+
),
|
|
176
|
+
_kind: "identifierNumber",
|
|
177
|
+
identifierAttribute: "id"
|
|
178
|
+
};
|
|
179
|
+
function literal(value) {
|
|
180
|
+
return {
|
|
181
|
+
name: `literal(${JSON.stringify(value)})`,
|
|
182
|
+
_kind: "literal",
|
|
183
|
+
_value: value,
|
|
184
|
+
_C: void 0,
|
|
185
|
+
_S: void 0,
|
|
186
|
+
_T: void 0,
|
|
187
|
+
create(snapshot) {
|
|
188
|
+
if (snapshot === void 0) {
|
|
189
|
+
return value;
|
|
190
|
+
}
|
|
191
|
+
if (snapshot !== value) {
|
|
192
|
+
throw new Error(
|
|
193
|
+
`[jotai-state-tree] Value '${String(snapshot)}' is not the literal '${String(value)}'`
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
return snapshot;
|
|
197
|
+
},
|
|
198
|
+
is(v) {
|
|
199
|
+
return v === value;
|
|
200
|
+
},
|
|
201
|
+
validate(v, context) {
|
|
202
|
+
if (v === value) {
|
|
203
|
+
return { valid: true, errors: [] };
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
valid: false,
|
|
207
|
+
errors: [
|
|
208
|
+
{
|
|
209
|
+
context,
|
|
210
|
+
value: v,
|
|
211
|
+
message: `Value '${String(v)}' is not the literal '${String(value)}'`
|
|
212
|
+
}
|
|
213
|
+
]
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
function enumeration(nameOrOptions, maybeOptions) {
|
|
219
|
+
const name = typeof nameOrOptions === "string" ? nameOrOptions : "enumeration";
|
|
220
|
+
const options = typeof nameOrOptions === "string" ? maybeOptions : nameOrOptions;
|
|
221
|
+
const optionSet = new Set(options);
|
|
222
|
+
return {
|
|
223
|
+
name,
|
|
224
|
+
_kind: "enumeration",
|
|
225
|
+
_options: options,
|
|
226
|
+
_C: void 0,
|
|
227
|
+
_S: void 0,
|
|
228
|
+
_T: void 0,
|
|
229
|
+
create(snapshot) {
|
|
230
|
+
if (snapshot === void 0) {
|
|
231
|
+
throw new Error(`[jotai-state-tree] A value for enumeration '${name}' is required`);
|
|
232
|
+
}
|
|
233
|
+
if (!optionSet.has(snapshot)) {
|
|
234
|
+
throw new Error(
|
|
235
|
+
`[jotai-state-tree] Value '${snapshot}' is not a valid option for enumeration '${name}'. Expected one of: ${options.join(", ")}`
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
return snapshot;
|
|
239
|
+
},
|
|
240
|
+
is(value) {
|
|
241
|
+
return typeof value === "string" && optionSet.has(value);
|
|
242
|
+
},
|
|
243
|
+
validate(value, context) {
|
|
244
|
+
if (typeof value === "string" && optionSet.has(value)) {
|
|
245
|
+
return { valid: true, errors: [] };
|
|
246
|
+
}
|
|
247
|
+
return {
|
|
248
|
+
valid: false,
|
|
249
|
+
errors: [
|
|
250
|
+
{
|
|
251
|
+
context,
|
|
252
|
+
value,
|
|
253
|
+
message: `Value '${String(value)}' is not a valid option. Expected one of: ${options.join(", ")}`
|
|
254
|
+
}
|
|
255
|
+
]
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
function frozen(defaultValue) {
|
|
261
|
+
return {
|
|
262
|
+
name: "frozen",
|
|
263
|
+
_kind: "frozen",
|
|
264
|
+
_C: void 0,
|
|
265
|
+
_S: void 0,
|
|
266
|
+
_T: void 0,
|
|
267
|
+
create(snapshot) {
|
|
268
|
+
if (snapshot === void 0) {
|
|
269
|
+
if (defaultValue !== void 0) {
|
|
270
|
+
return deepFreeze(structuredClone(defaultValue));
|
|
271
|
+
}
|
|
272
|
+
return void 0;
|
|
273
|
+
}
|
|
274
|
+
return deepFreeze(structuredClone(snapshot));
|
|
275
|
+
},
|
|
276
|
+
is(value) {
|
|
277
|
+
return true;
|
|
278
|
+
},
|
|
279
|
+
validate() {
|
|
280
|
+
return { valid: true, errors: [] };
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
function deepFreeze(obj) {
|
|
285
|
+
if (obj === null || typeof obj !== "object") {
|
|
286
|
+
return obj;
|
|
287
|
+
}
|
|
288
|
+
Object.freeze(obj);
|
|
289
|
+
if (Array.isArray(obj)) {
|
|
290
|
+
obj.forEach(deepFreeze);
|
|
291
|
+
} else {
|
|
292
|
+
Object.values(obj).forEach(deepFreeze);
|
|
293
|
+
}
|
|
294
|
+
return obj;
|
|
295
|
+
}
|
|
296
|
+
function custom(options) {
|
|
297
|
+
return {
|
|
298
|
+
name: options.name,
|
|
299
|
+
_kind: "simple",
|
|
300
|
+
_C: void 0,
|
|
301
|
+
_S: void 0,
|
|
302
|
+
_T: void 0,
|
|
303
|
+
create(snapshot) {
|
|
304
|
+
if (snapshot === void 0) {
|
|
305
|
+
throw new Error(`[jotai-state-tree] A value for custom type '${options.name}' is required`);
|
|
306
|
+
}
|
|
307
|
+
return options.fromSnapshot(snapshot);
|
|
308
|
+
},
|
|
309
|
+
is(value) {
|
|
310
|
+
return options.isTargetType(value);
|
|
311
|
+
},
|
|
312
|
+
validate(value, context) {
|
|
313
|
+
if (options.isTargetType(value)) {
|
|
314
|
+
return { valid: true, errors: [] };
|
|
315
|
+
}
|
|
316
|
+
return {
|
|
317
|
+
valid: false,
|
|
318
|
+
errors: [
|
|
319
|
+
{
|
|
320
|
+
context,
|
|
321
|
+
value,
|
|
322
|
+
message: options.getValidationMessage(value)
|
|
323
|
+
}
|
|
324
|
+
]
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
var finite = createSimpleType(
|
|
330
|
+
"finite",
|
|
331
|
+
(value) => typeof value === "number" && isFinite(value)
|
|
332
|
+
);
|
|
333
|
+
var float = number;
|
|
334
|
+
|
|
335
|
+
// src/model.ts
|
|
336
|
+
init_tree();
|
|
337
|
+
import { atom } from "jotai";
|
|
338
|
+
var MAX_CACHE_SIZE = 100;
|
|
339
|
+
var LRUCache = class {
|
|
340
|
+
constructor(maxSize = MAX_CACHE_SIZE) {
|
|
341
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
342
|
+
this.maxSize = maxSize;
|
|
343
|
+
}
|
|
344
|
+
get(key) {
|
|
345
|
+
const value = this.cache.get(key);
|
|
346
|
+
if (value !== void 0) {
|
|
347
|
+
this.cache.delete(key);
|
|
348
|
+
this.cache.set(key, value);
|
|
349
|
+
}
|
|
350
|
+
return value;
|
|
351
|
+
}
|
|
352
|
+
set(key, value) {
|
|
353
|
+
if (this.cache.has(key)) {
|
|
354
|
+
this.cache.delete(key);
|
|
355
|
+
} else if (this.cache.size >= this.maxSize) {
|
|
356
|
+
const firstKey = this.cache.keys().next().value;
|
|
357
|
+
if (firstKey !== void 0) {
|
|
358
|
+
this.cache.delete(firstKey);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
this.cache.set(key, value);
|
|
362
|
+
}
|
|
363
|
+
has(key) {
|
|
364
|
+
return this.cache.has(key);
|
|
365
|
+
}
|
|
366
|
+
clear() {
|
|
367
|
+
this.cache.clear();
|
|
368
|
+
}
|
|
369
|
+
get size() {
|
|
370
|
+
return this.cache.size;
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
var ModelType = class _ModelType {
|
|
374
|
+
constructor(config) {
|
|
375
|
+
this._kind = "model";
|
|
376
|
+
this.config = config;
|
|
377
|
+
this.name = config.name;
|
|
378
|
+
this.properties = config.properties;
|
|
379
|
+
for (const [key, type] of Object.entries(config.properties)) {
|
|
380
|
+
if (type._kind === "identifier" || type._kind === "identifierNumber") {
|
|
381
|
+
this.identifierAttribute = key;
|
|
382
|
+
break;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
create(snapshot, env) {
|
|
387
|
+
let processedSnapshot = snapshot ?? {};
|
|
388
|
+
if (this.config.preProcessor) {
|
|
389
|
+
processedSnapshot = this.config.preProcessor(
|
|
390
|
+
processedSnapshot
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
const node = new StateTreeNode(this, processedSnapshot, env);
|
|
394
|
+
node.preProcessor = this.config.preProcessor;
|
|
395
|
+
node.postProcessor = this.config.postProcessor;
|
|
396
|
+
const propertyAtoms = /* @__PURE__ */ new Map();
|
|
397
|
+
const store = getGlobalStore();
|
|
398
|
+
for (const [key, propType] of Object.entries(this.properties)) {
|
|
399
|
+
const type = propType;
|
|
400
|
+
const initialValue = processedSnapshot?.[key];
|
|
401
|
+
const isComplexType = type._kind === "model" || type._kind === "array" || type._kind === "map";
|
|
402
|
+
if (isComplexType) {
|
|
403
|
+
const childInstance = type.create(initialValue, env);
|
|
404
|
+
const childNode = getStateTreeNode(childInstance);
|
|
405
|
+
node.addChild(key, childNode);
|
|
406
|
+
propertyAtoms.set(key, childNode.valueAtom);
|
|
407
|
+
} else {
|
|
408
|
+
const value = type.create(initialValue, env);
|
|
409
|
+
if (value && typeof value === "object" && $treenode in value) {
|
|
410
|
+
const childNode = getStateTreeNode(value);
|
|
411
|
+
node.addChild(key, childNode);
|
|
412
|
+
propertyAtoms.set(key, childNode.valueAtom);
|
|
413
|
+
} else {
|
|
414
|
+
const propAtom = atom(value);
|
|
415
|
+
propertyAtoms.set(key, propAtom);
|
|
416
|
+
const childNode = new StateTreeNode(type, value, env, node, key);
|
|
417
|
+
childNode.valueAtom = propAtom;
|
|
418
|
+
node.addChild(key, childNode);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
const instance = this.createInstanceProxy(node, propertyAtoms, store);
|
|
423
|
+
if (this.identifierAttribute) {
|
|
424
|
+
const idValue = processedSnapshot?.[this.identifierAttribute];
|
|
425
|
+
if (idValue !== void 0) {
|
|
426
|
+
node.registerIdentifier(this.name, idValue);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
node.setInstance(instance);
|
|
430
|
+
for (const initializer of this.config.initializers) {
|
|
431
|
+
initializer(instance);
|
|
432
|
+
}
|
|
433
|
+
if (this.config.hooks.afterCreate) {
|
|
434
|
+
this.config.hooks.afterCreate(instance);
|
|
435
|
+
}
|
|
436
|
+
return instance;
|
|
437
|
+
}
|
|
438
|
+
createInstanceProxy(node, propertyAtoms, store) {
|
|
439
|
+
const self = this;
|
|
440
|
+
const viewCache = new LRUCache(MAX_CACHE_SIZE);
|
|
441
|
+
const actionCache = new LRUCache(MAX_CACHE_SIZE);
|
|
442
|
+
const allViews = {};
|
|
443
|
+
const allActions = {};
|
|
444
|
+
const volatileState = {};
|
|
445
|
+
const base = {
|
|
446
|
+
[$treenode]: node
|
|
447
|
+
};
|
|
448
|
+
const proxy = new Proxy(base, {
|
|
449
|
+
get(target, prop) {
|
|
450
|
+
if (prop === $treenode) {
|
|
451
|
+
return node;
|
|
452
|
+
}
|
|
453
|
+
if (prop === "$treenode") {
|
|
454
|
+
return node;
|
|
455
|
+
}
|
|
456
|
+
const propStr = String(prop);
|
|
457
|
+
if (propertyAtoms.has(propStr)) {
|
|
458
|
+
const childNode = node.getChild(propStr);
|
|
459
|
+
if (childNode) {
|
|
460
|
+
const instance = childNode.getInstance();
|
|
461
|
+
if (instance !== void 0) {
|
|
462
|
+
if (instance && typeof instance === "object" && $treenode in instance) {
|
|
463
|
+
return instance;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
return store.get(propertyAtoms.get(propStr));
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
if (propStr in node.volatileState) {
|
|
470
|
+
return node.volatileState[propStr];
|
|
471
|
+
}
|
|
472
|
+
if (propStr in allViews) {
|
|
473
|
+
const descriptor = allViews[propStr];
|
|
474
|
+
if (descriptor.get) {
|
|
475
|
+
return descriptor.get.call(proxy);
|
|
476
|
+
}
|
|
477
|
+
if (typeof descriptor.value === "function") {
|
|
478
|
+
return descriptor.value.bind(proxy);
|
|
479
|
+
}
|
|
480
|
+
return descriptor.value;
|
|
481
|
+
}
|
|
482
|
+
if (propStr in allActions) {
|
|
483
|
+
return allActions[propStr];
|
|
484
|
+
}
|
|
485
|
+
return void 0;
|
|
486
|
+
},
|
|
487
|
+
set(target, prop, value) {
|
|
488
|
+
const propStr = String(prop);
|
|
489
|
+
if (propertyAtoms.has(propStr)) {
|
|
490
|
+
const propType = self.properties[propStr];
|
|
491
|
+
const existingChildNode = node.getChild(propStr);
|
|
492
|
+
if (propType._kind === "model") {
|
|
493
|
+
if (existingChildNode) {
|
|
494
|
+
const { applySnapshotToNode } = (init_tree(), __toCommonJS(tree_exports));
|
|
495
|
+
applySnapshotToNode(existingChildNode, value);
|
|
496
|
+
}
|
|
497
|
+
return true;
|
|
498
|
+
}
|
|
499
|
+
if (propType._kind === "array" || propType._kind === "map") {
|
|
500
|
+
if (existingChildNode) {
|
|
501
|
+
existingChildNode.setValue(value);
|
|
502
|
+
}
|
|
503
|
+
return true;
|
|
504
|
+
}
|
|
505
|
+
const oldValue = existingChildNode?.getValue();
|
|
506
|
+
if (existingChildNode) {
|
|
507
|
+
existingChildNode.destroy();
|
|
508
|
+
node.getChildren().delete(propStr);
|
|
509
|
+
}
|
|
510
|
+
const newValue = propType.create(value, node.$env);
|
|
511
|
+
if (newValue && typeof newValue === "object" && $treenode in newValue) {
|
|
512
|
+
const newChildNode = getStateTreeNode(newValue);
|
|
513
|
+
node.addChild(propStr, newChildNode);
|
|
514
|
+
propertyAtoms.set(propStr, newChildNode.valueAtom);
|
|
515
|
+
} else {
|
|
516
|
+
const newChildNode = new StateTreeNode(
|
|
517
|
+
propType,
|
|
518
|
+
newValue,
|
|
519
|
+
node.$env,
|
|
520
|
+
node,
|
|
521
|
+
propStr
|
|
522
|
+
);
|
|
523
|
+
const propAtom = atom(newValue);
|
|
524
|
+
newChildNode.valueAtom = propAtom;
|
|
525
|
+
node.addChild(propStr, newChildNode);
|
|
526
|
+
propertyAtoms.set(propStr, propAtom);
|
|
527
|
+
store.set(propAtom, newValue);
|
|
528
|
+
}
|
|
529
|
+
node.notifyPropertyChange(propStr, newValue, oldValue);
|
|
530
|
+
return true;
|
|
531
|
+
}
|
|
532
|
+
if (propStr in node.volatileState) {
|
|
533
|
+
node.volatileState[propStr] = value;
|
|
534
|
+
return true;
|
|
535
|
+
}
|
|
536
|
+
return false;
|
|
537
|
+
},
|
|
538
|
+
has(target, prop) {
|
|
539
|
+
const propStr = String(prop);
|
|
540
|
+
return prop === $treenode || propertyAtoms.has(propStr) || propStr in allViews || propStr in allActions || propStr in node.volatileState;
|
|
541
|
+
},
|
|
542
|
+
ownKeys() {
|
|
543
|
+
return [
|
|
544
|
+
...propertyAtoms.keys(),
|
|
545
|
+
...Object.keys(allViews),
|
|
546
|
+
...Object.keys(allActions),
|
|
547
|
+
...Object.keys(node.volatileState)
|
|
548
|
+
];
|
|
549
|
+
},
|
|
550
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
551
|
+
const propStr = String(prop);
|
|
552
|
+
if (propertyAtoms.has(propStr) || propStr in allViews || propStr in allActions || propStr in node.volatileState) {
|
|
553
|
+
return {
|
|
554
|
+
configurable: true,
|
|
555
|
+
enumerable: true,
|
|
556
|
+
writable: true
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
return void 0;
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
for (const viewFn of this.config.views) {
|
|
563
|
+
const views = viewFn(proxy);
|
|
564
|
+
for (const [key, value] of Object.entries(
|
|
565
|
+
Object.getOwnPropertyDescriptors(views)
|
|
566
|
+
)) {
|
|
567
|
+
allViews[key] = value;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
for (const actionFn of this.config.actions) {
|
|
571
|
+
const actions = actionFn(proxy);
|
|
572
|
+
for (const [key, value] of Object.entries(actions)) {
|
|
573
|
+
if (typeof value === "function") {
|
|
574
|
+
allActions[key] = (...args) => {
|
|
575
|
+
return trackAction(node, key, args, () => {
|
|
576
|
+
return value.apply(proxy, args);
|
|
577
|
+
});
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
for (const volatileFn of this.config.volatiles) {
|
|
583
|
+
const volatile = volatileFn(proxy);
|
|
584
|
+
Object.assign(node.volatileState, volatile);
|
|
585
|
+
}
|
|
586
|
+
return proxy;
|
|
587
|
+
}
|
|
588
|
+
is(value) {
|
|
589
|
+
if (!value || typeof value !== "object") return false;
|
|
590
|
+
if (!($treenode in value)) return false;
|
|
591
|
+
const node = value[$treenode];
|
|
592
|
+
return node.$type === this || node.$type.name === this.name;
|
|
593
|
+
}
|
|
594
|
+
validate(value, context) {
|
|
595
|
+
const errors = [];
|
|
596
|
+
if (!value || typeof value !== "object") {
|
|
597
|
+
return {
|
|
598
|
+
valid: false,
|
|
599
|
+
errors: [
|
|
600
|
+
{
|
|
601
|
+
context,
|
|
602
|
+
value,
|
|
603
|
+
message: `Value is not an object`
|
|
604
|
+
}
|
|
605
|
+
]
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
for (const [key, propType] of Object.entries(this.properties)) {
|
|
609
|
+
const propValue = value[key];
|
|
610
|
+
const propContext = {
|
|
611
|
+
path: context.length > 0 ? `${context[0].path}/${key}` : `/${key}`,
|
|
612
|
+
type: propType,
|
|
613
|
+
parent: value
|
|
614
|
+
};
|
|
615
|
+
const result = propType.validate(propValue, [
|
|
616
|
+
...context,
|
|
617
|
+
propContext
|
|
618
|
+
]);
|
|
619
|
+
if (!result.valid) {
|
|
620
|
+
errors.push(...result.errors);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
return {
|
|
624
|
+
valid: errors.length === 0,
|
|
625
|
+
errors
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
// ============================================================================
|
|
629
|
+
// Model Modifiers
|
|
630
|
+
// ============================================================================
|
|
631
|
+
named(name) {
|
|
632
|
+
return new _ModelType({
|
|
633
|
+
...this.config,
|
|
634
|
+
name
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
props(properties) {
|
|
638
|
+
return new _ModelType({
|
|
639
|
+
...this.config,
|
|
640
|
+
properties: { ...this.config.properties, ...properties }
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
views(fn) {
|
|
644
|
+
return new _ModelType({
|
|
645
|
+
...this.config,
|
|
646
|
+
views: [
|
|
647
|
+
...this.config.views,
|
|
648
|
+
fn
|
|
649
|
+
]
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
actions(fn) {
|
|
653
|
+
return new _ModelType({
|
|
654
|
+
...this.config,
|
|
655
|
+
actions: [
|
|
656
|
+
...this.config.actions,
|
|
657
|
+
fn
|
|
658
|
+
]
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
volatile(fn) {
|
|
662
|
+
return new _ModelType({
|
|
663
|
+
...this.config,
|
|
664
|
+
volatiles: [
|
|
665
|
+
...this.config.volatiles,
|
|
666
|
+
fn
|
|
667
|
+
]
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
preProcessSnapshot(fn) {
|
|
671
|
+
return new _ModelType({
|
|
672
|
+
...this.config,
|
|
673
|
+
preProcessor: fn
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
postProcessSnapshot(fn) {
|
|
677
|
+
return new _ModelType({
|
|
678
|
+
...this.config,
|
|
679
|
+
postProcessor: fn
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
extend(fn) {
|
|
683
|
+
const viewsFn = (self) => {
|
|
684
|
+
const result = fn(self);
|
|
685
|
+
return result.views ?? {};
|
|
686
|
+
};
|
|
687
|
+
const actionsFn = (self) => {
|
|
688
|
+
const result = fn(self);
|
|
689
|
+
return result.actions ?? {};
|
|
690
|
+
};
|
|
691
|
+
const volatileFn = (self) => {
|
|
692
|
+
const result = fn(self);
|
|
693
|
+
return result.state ?? {};
|
|
694
|
+
};
|
|
695
|
+
return new _ModelType({
|
|
696
|
+
...this.config,
|
|
697
|
+
views: [
|
|
698
|
+
...this.config.views,
|
|
699
|
+
viewsFn
|
|
700
|
+
],
|
|
701
|
+
actions: [
|
|
702
|
+
...this.config.actions,
|
|
703
|
+
actionsFn
|
|
704
|
+
],
|
|
705
|
+
volatiles: [
|
|
706
|
+
...this.config.volatiles,
|
|
707
|
+
volatileFn
|
|
708
|
+
]
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* Add afterCreate lifecycle hook
|
|
713
|
+
*/
|
|
714
|
+
afterCreate(fn) {
|
|
715
|
+
return new _ModelType({
|
|
716
|
+
...this.config,
|
|
717
|
+
hooks: {
|
|
718
|
+
...this.config.hooks,
|
|
719
|
+
afterCreate: fn
|
|
720
|
+
}
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
/**
|
|
724
|
+
* Add afterAttach lifecycle hook
|
|
725
|
+
*/
|
|
726
|
+
afterAttach(fn) {
|
|
727
|
+
return new _ModelType({
|
|
728
|
+
...this.config,
|
|
729
|
+
hooks: {
|
|
730
|
+
...this.config.hooks,
|
|
731
|
+
afterAttach: fn
|
|
732
|
+
}
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* Add beforeDetach lifecycle hook
|
|
737
|
+
*/
|
|
738
|
+
beforeDetach(fn) {
|
|
739
|
+
return new _ModelType({
|
|
740
|
+
...this.config,
|
|
741
|
+
hooks: {
|
|
742
|
+
...this.config.hooks,
|
|
743
|
+
beforeDetach: fn
|
|
744
|
+
}
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* Add beforeDestroy lifecycle hook
|
|
749
|
+
*/
|
|
750
|
+
beforeDestroy(fn) {
|
|
751
|
+
return new _ModelType({
|
|
752
|
+
...this.config,
|
|
753
|
+
hooks: {
|
|
754
|
+
...this.config.hooks,
|
|
755
|
+
beforeDestroy: fn
|
|
756
|
+
}
|
|
757
|
+
});
|
|
758
|
+
}
|
|
759
|
+
};
|
|
760
|
+
function model(nameOrProperties, maybeProperties) {
|
|
761
|
+
const name = typeof nameOrProperties === "string" ? nameOrProperties : "AnonymousModel";
|
|
762
|
+
const properties = typeof nameOrProperties === "string" ? maybeProperties : nameOrProperties;
|
|
763
|
+
return new ModelType({
|
|
764
|
+
name,
|
|
765
|
+
properties,
|
|
766
|
+
views: [],
|
|
767
|
+
actions: [],
|
|
768
|
+
volatiles: [],
|
|
769
|
+
initializers: [],
|
|
770
|
+
hooks: {}
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
function compose(...args) {
|
|
774
|
+
const name = typeof args[0] === "string" ? args[0] : "ComposedModel";
|
|
775
|
+
const types2 = typeof args[0] === "string" ? args.slice(1) : args;
|
|
776
|
+
const mergedProperties = {};
|
|
777
|
+
for (const type of types2) {
|
|
778
|
+
Object.assign(mergedProperties, type.properties);
|
|
779
|
+
}
|
|
780
|
+
return model(name, mergedProperties);
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// src/array.ts
|
|
784
|
+
init_tree();
|
|
785
|
+
var MSTArray = class _MSTArray extends Array {
|
|
786
|
+
constructor(node, itemType, items = []) {
|
|
787
|
+
super(...items);
|
|
788
|
+
this.node = node;
|
|
789
|
+
this.itemType = itemType;
|
|
790
|
+
Object.setPrototypeOf(this, _MSTArray.prototype);
|
|
791
|
+
}
|
|
792
|
+
replace(items) {
|
|
793
|
+
this.length = 0;
|
|
794
|
+
this.push(...items);
|
|
795
|
+
this.syncToNode();
|
|
796
|
+
}
|
|
797
|
+
clear() {
|
|
798
|
+
this.length = 0;
|
|
799
|
+
this.syncToNode();
|
|
800
|
+
}
|
|
801
|
+
remove(item) {
|
|
802
|
+
const index = this.indexOf(item);
|
|
803
|
+
if (index >= 0) {
|
|
804
|
+
this.splice(index, 1);
|
|
805
|
+
this.syncToNode();
|
|
806
|
+
return true;
|
|
807
|
+
}
|
|
808
|
+
return false;
|
|
809
|
+
}
|
|
810
|
+
spliceWithArray(index, deleteCount, newItems) {
|
|
811
|
+
const result = deleteCount !== void 0 ? newItems ? this.splice(index, deleteCount, ...newItems) : this.splice(index, deleteCount) : this.splice(index);
|
|
812
|
+
this.syncToNode();
|
|
813
|
+
return result;
|
|
814
|
+
}
|
|
815
|
+
// Override mutating methods to sync
|
|
816
|
+
push(...items) {
|
|
817
|
+
const result = super.push(...items);
|
|
818
|
+
this.syncToNode();
|
|
819
|
+
return result;
|
|
820
|
+
}
|
|
821
|
+
pop() {
|
|
822
|
+
const result = super.pop();
|
|
823
|
+
this.syncToNode();
|
|
824
|
+
return result;
|
|
825
|
+
}
|
|
826
|
+
shift() {
|
|
827
|
+
const result = super.shift();
|
|
828
|
+
this.syncToNode();
|
|
829
|
+
return result;
|
|
830
|
+
}
|
|
831
|
+
unshift(...items) {
|
|
832
|
+
const result = super.unshift(...items);
|
|
833
|
+
this.syncToNode();
|
|
834
|
+
return result;
|
|
835
|
+
}
|
|
836
|
+
splice(start, deleteCount, ...items) {
|
|
837
|
+
const result = deleteCount !== void 0 ? super.splice(start, deleteCount, ...items) : super.splice(start);
|
|
838
|
+
this.syncToNode();
|
|
839
|
+
return result;
|
|
840
|
+
}
|
|
841
|
+
sort(compareFn) {
|
|
842
|
+
super.sort(compareFn);
|
|
843
|
+
this.syncToNode();
|
|
844
|
+
return this;
|
|
845
|
+
}
|
|
846
|
+
reverse() {
|
|
847
|
+
super.reverse();
|
|
848
|
+
this.syncToNode();
|
|
849
|
+
return this;
|
|
850
|
+
}
|
|
851
|
+
fill(value, start, end) {
|
|
852
|
+
super.fill(value, start, end);
|
|
853
|
+
this.syncToNode();
|
|
854
|
+
return this;
|
|
855
|
+
}
|
|
856
|
+
copyWithin(target, start, end) {
|
|
857
|
+
super.copyWithin(target, start, end);
|
|
858
|
+
this.syncToNode();
|
|
859
|
+
return this;
|
|
860
|
+
}
|
|
861
|
+
toJSON() {
|
|
862
|
+
return [...this];
|
|
863
|
+
}
|
|
864
|
+
syncToNode() {
|
|
865
|
+
const existingChildNodes = /* @__PURE__ */ new Set();
|
|
866
|
+
for (const [, child] of this.node.getChildren()) {
|
|
867
|
+
existingChildNodes.add(child);
|
|
868
|
+
}
|
|
869
|
+
const newChildren = /* @__PURE__ */ new Map();
|
|
870
|
+
const keptNodes = /* @__PURE__ */ new Set();
|
|
871
|
+
this.forEach((item, index) => {
|
|
872
|
+
const key = String(index);
|
|
873
|
+
if (item && typeof item === "object" && $treenode in item) {
|
|
874
|
+
const childNode = getStateTreeNode(item);
|
|
875
|
+
newChildren.set(key, childNode);
|
|
876
|
+
keptNodes.add(childNode);
|
|
877
|
+
} else {
|
|
878
|
+
const instance = this.itemType.create(item);
|
|
879
|
+
if (instance && typeof instance === "object" && $treenode in instance) {
|
|
880
|
+
const childNode = getStateTreeNode(instance);
|
|
881
|
+
newChildren.set(key, childNode);
|
|
882
|
+
keptNodes.add(childNode);
|
|
883
|
+
this[index] = instance;
|
|
884
|
+
} else {
|
|
885
|
+
let reusedNode = null;
|
|
886
|
+
for (const existingNode of existingChildNodes) {
|
|
887
|
+
if (!keptNodes.has(existingNode) && existingNode.getValue() === item) {
|
|
888
|
+
reusedNode = existingNode;
|
|
889
|
+
break;
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
if (reusedNode) {
|
|
893
|
+
newChildren.set(key, reusedNode);
|
|
894
|
+
keptNodes.add(reusedNode);
|
|
895
|
+
} else {
|
|
896
|
+
const childNode = new StateTreeNode(
|
|
897
|
+
this.itemType,
|
|
898
|
+
item,
|
|
899
|
+
this.node.$env
|
|
900
|
+
);
|
|
901
|
+
newChildren.set(key, childNode);
|
|
902
|
+
keptNodes.add(childNode);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
});
|
|
907
|
+
for (const existingNode of existingChildNodes) {
|
|
908
|
+
if (!keptNodes.has(existingNode)) {
|
|
909
|
+
existingNode.destroy();
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
this.node.getChildren().clear();
|
|
913
|
+
for (const [key, childNode] of newChildren) {
|
|
914
|
+
this.node.addChild(key, childNode);
|
|
915
|
+
}
|
|
916
|
+
this.node.setValue([...this]);
|
|
917
|
+
}
|
|
918
|
+
};
|
|
919
|
+
var ArrayType = class {
|
|
920
|
+
constructor(itemType) {
|
|
921
|
+
this._kind = "array";
|
|
922
|
+
this._subType = itemType;
|
|
923
|
+
this.name = `array<${itemType.name}>`;
|
|
924
|
+
}
|
|
925
|
+
create(snapshot, env) {
|
|
926
|
+
const items = snapshot ?? [];
|
|
927
|
+
const node = new StateTreeNode(this, items, env);
|
|
928
|
+
const instances = items.map((item, index) => {
|
|
929
|
+
const instance = this._subType.create(item, env);
|
|
930
|
+
if (instance && typeof instance === "object" && $treenode in instance) {
|
|
931
|
+
const childNode = getStateTreeNode(instance);
|
|
932
|
+
node.addChild(String(index), childNode);
|
|
933
|
+
} else {
|
|
934
|
+
const childNode = new StateTreeNode(
|
|
935
|
+
this._subType,
|
|
936
|
+
instance,
|
|
937
|
+
env,
|
|
938
|
+
node,
|
|
939
|
+
String(index)
|
|
940
|
+
);
|
|
941
|
+
node.addChild(String(index), childNode);
|
|
942
|
+
}
|
|
943
|
+
return instance;
|
|
944
|
+
});
|
|
945
|
+
const mstArray = new MSTArray(node, this._subType, instances);
|
|
946
|
+
Object.defineProperty(mstArray, $treenode, {
|
|
947
|
+
value: node,
|
|
948
|
+
writable: false,
|
|
949
|
+
enumerable: false
|
|
950
|
+
});
|
|
951
|
+
node.setInstance(mstArray);
|
|
952
|
+
node.setValue(instances);
|
|
953
|
+
return mstArray;
|
|
954
|
+
}
|
|
955
|
+
is(value) {
|
|
956
|
+
if (!Array.isArray(value)) return false;
|
|
957
|
+
return $treenode in value;
|
|
958
|
+
}
|
|
959
|
+
validate(value, context) {
|
|
960
|
+
const errors = [];
|
|
961
|
+
if (!Array.isArray(value)) {
|
|
962
|
+
return {
|
|
963
|
+
valid: false,
|
|
964
|
+
errors: [
|
|
965
|
+
{
|
|
966
|
+
context,
|
|
967
|
+
value,
|
|
968
|
+
message: "Value is not an array"
|
|
969
|
+
}
|
|
970
|
+
]
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
value.forEach((item, index) => {
|
|
974
|
+
const itemContext = {
|
|
975
|
+
path: context.length > 0 ? `${context[0].path}/${index}` : `/${index}`,
|
|
976
|
+
type: this._subType,
|
|
977
|
+
parent: value
|
|
978
|
+
};
|
|
979
|
+
const result = this._subType.validate(item, [...context, itemContext]);
|
|
980
|
+
if (!result.valid) {
|
|
981
|
+
errors.push(...result.errors);
|
|
982
|
+
}
|
|
983
|
+
});
|
|
984
|
+
return {
|
|
985
|
+
valid: errors.length === 0,
|
|
986
|
+
errors
|
|
987
|
+
};
|
|
988
|
+
}
|
|
989
|
+
};
|
|
990
|
+
function array(itemType) {
|
|
991
|
+
return new ArrayType(itemType);
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
// src/map.ts
|
|
995
|
+
init_tree();
|
|
996
|
+
var MSTMap = class extends Map {
|
|
997
|
+
constructor(node, valueType, entries) {
|
|
998
|
+
super();
|
|
999
|
+
this.initialized = false;
|
|
1000
|
+
this.node = node;
|
|
1001
|
+
this.valueType = valueType;
|
|
1002
|
+
this.initialized = true;
|
|
1003
|
+
if (entries) {
|
|
1004
|
+
for (const [key, value] of entries) {
|
|
1005
|
+
super.set(key, value);
|
|
1006
|
+
}
|
|
1007
|
+
this.syncToNode();
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
put(value) {
|
|
1011
|
+
let key;
|
|
1012
|
+
if (value && typeof value === "object" && $treenode in value) {
|
|
1013
|
+
const valueNode = getStateTreeNode(value);
|
|
1014
|
+
if (valueNode.identifierValue !== void 0) {
|
|
1015
|
+
key = String(valueNode.identifierValue);
|
|
1016
|
+
} else {
|
|
1017
|
+
throw new Error("[jotai-state-tree] Cannot put a value without an identifier into a map");
|
|
1018
|
+
}
|
|
1019
|
+
} else {
|
|
1020
|
+
throw new Error("[jotai-state-tree] Cannot put a non-model value using put()");
|
|
1021
|
+
}
|
|
1022
|
+
this.set(key, value);
|
|
1023
|
+
return value;
|
|
1024
|
+
}
|
|
1025
|
+
merge(values) {
|
|
1026
|
+
const entries = values instanceof Map ? values.entries() : Object.entries(values);
|
|
1027
|
+
for (const [key, value] of entries) {
|
|
1028
|
+
this.set(key, value);
|
|
1029
|
+
}
|
|
1030
|
+
return this;
|
|
1031
|
+
}
|
|
1032
|
+
replace(values) {
|
|
1033
|
+
this.clear();
|
|
1034
|
+
return this.merge(values);
|
|
1035
|
+
}
|
|
1036
|
+
// Override mutating methods to sync
|
|
1037
|
+
set(key, value) {
|
|
1038
|
+
super.set(key, value);
|
|
1039
|
+
if (this.initialized) {
|
|
1040
|
+
this.syncToNode();
|
|
1041
|
+
}
|
|
1042
|
+
return this;
|
|
1043
|
+
}
|
|
1044
|
+
// Override get to return the instance from child node for complex types
|
|
1045
|
+
get(key) {
|
|
1046
|
+
if (this.valueType._kind === "model" || this.valueType._kind === "array" || this.valueType._kind === "map") {
|
|
1047
|
+
const childNode = this.node.getChild(key);
|
|
1048
|
+
if (childNode) {
|
|
1049
|
+
return childNode.getInstance();
|
|
1050
|
+
}
|
|
1051
|
+
return void 0;
|
|
1052
|
+
}
|
|
1053
|
+
return super.get(key);
|
|
1054
|
+
}
|
|
1055
|
+
delete(key) {
|
|
1056
|
+
const result = super.delete(key);
|
|
1057
|
+
if (result && this.initialized) {
|
|
1058
|
+
this.syncToNode();
|
|
1059
|
+
}
|
|
1060
|
+
return result;
|
|
1061
|
+
}
|
|
1062
|
+
clear() {
|
|
1063
|
+
super.clear();
|
|
1064
|
+
if (this.initialized) {
|
|
1065
|
+
this.syncToNode();
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
toJSON() {
|
|
1069
|
+
const result = {};
|
|
1070
|
+
this.forEach((value, key) => {
|
|
1071
|
+
result[key] = value;
|
|
1072
|
+
});
|
|
1073
|
+
return result;
|
|
1074
|
+
}
|
|
1075
|
+
syncToNode() {
|
|
1076
|
+
const existingChildren = new Map(this.node.getChildren());
|
|
1077
|
+
const newChildren = /* @__PURE__ */ new Map();
|
|
1078
|
+
this.forEach((value, key) => {
|
|
1079
|
+
if (this.valueType._kind === "model" || this.valueType._kind === "array" || this.valueType._kind === "map") {
|
|
1080
|
+
if (value && typeof value === "object" && $treenode in value) {
|
|
1081
|
+
const childNode = getStateTreeNode(value);
|
|
1082
|
+
newChildren.set(key, childNode);
|
|
1083
|
+
} else {
|
|
1084
|
+
const childInstance = this.valueType.create(value);
|
|
1085
|
+
const childNode = getStateTreeNode(childInstance);
|
|
1086
|
+
newChildren.set(key, childNode);
|
|
1087
|
+
super.set(key, childInstance);
|
|
1088
|
+
}
|
|
1089
|
+
} else {
|
|
1090
|
+
const existingChild = existingChildren.get(key);
|
|
1091
|
+
if (existingChild && existingChild.getValue() === value) {
|
|
1092
|
+
newChildren.set(key, existingChild);
|
|
1093
|
+
} else {
|
|
1094
|
+
const childNode = new StateTreeNode(this.valueType, value, this.node.$env);
|
|
1095
|
+
newChildren.set(key, childNode);
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
});
|
|
1099
|
+
for (const [key, child] of existingChildren) {
|
|
1100
|
+
if (!newChildren.has(key)) {
|
|
1101
|
+
child.destroy();
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
this.node.getChildren().clear();
|
|
1105
|
+
for (const [key, childNode] of newChildren) {
|
|
1106
|
+
this.node.addChild(key, childNode);
|
|
1107
|
+
}
|
|
1108
|
+
this.node.setValue(this.toJSON());
|
|
1109
|
+
}
|
|
1110
|
+
};
|
|
1111
|
+
var MapType = class {
|
|
1112
|
+
constructor(valueType) {
|
|
1113
|
+
this._kind = "map";
|
|
1114
|
+
this._subType = valueType;
|
|
1115
|
+
this.name = `map<${valueType.name}>`;
|
|
1116
|
+
}
|
|
1117
|
+
create(snapshot, env) {
|
|
1118
|
+
const entries = snapshot ?? {};
|
|
1119
|
+
const node = new StateTreeNode(this, entries, env);
|
|
1120
|
+
const instanceEntries = Object.entries(entries).map(([key, value]) => {
|
|
1121
|
+
const instance = this._subType.create(value, env);
|
|
1122
|
+
if (this._subType._kind === "model" || this._subType._kind === "array" || this._subType._kind === "map") {
|
|
1123
|
+
const childNode = getStateTreeNode(instance);
|
|
1124
|
+
node.addChild(key, childNode);
|
|
1125
|
+
} else {
|
|
1126
|
+
const childNode = new StateTreeNode(this._subType, instance, env, node, key);
|
|
1127
|
+
node.addChild(key, childNode);
|
|
1128
|
+
}
|
|
1129
|
+
return [key, instance];
|
|
1130
|
+
});
|
|
1131
|
+
const mstMap = new MSTMap(
|
|
1132
|
+
node,
|
|
1133
|
+
this._subType,
|
|
1134
|
+
instanceEntries
|
|
1135
|
+
);
|
|
1136
|
+
Object.defineProperty(mstMap, $treenode, {
|
|
1137
|
+
value: node,
|
|
1138
|
+
writable: false,
|
|
1139
|
+
enumerable: false
|
|
1140
|
+
});
|
|
1141
|
+
node.setInstance(mstMap);
|
|
1142
|
+
return mstMap;
|
|
1143
|
+
}
|
|
1144
|
+
is(value) {
|
|
1145
|
+
if (!(value instanceof Map)) return false;
|
|
1146
|
+
return $treenode in value;
|
|
1147
|
+
}
|
|
1148
|
+
validate(value, context) {
|
|
1149
|
+
const errors = [];
|
|
1150
|
+
if (typeof value !== "object" || value === null) {
|
|
1151
|
+
return {
|
|
1152
|
+
valid: false,
|
|
1153
|
+
errors: [
|
|
1154
|
+
{
|
|
1155
|
+
context,
|
|
1156
|
+
value,
|
|
1157
|
+
message: "Value is not an object or Map"
|
|
1158
|
+
}
|
|
1159
|
+
]
|
|
1160
|
+
};
|
|
1161
|
+
}
|
|
1162
|
+
const entries = value instanceof Map ? Array.from(value.entries()) : Object.entries(value);
|
|
1163
|
+
for (const [key, itemValue] of entries) {
|
|
1164
|
+
const itemContext = {
|
|
1165
|
+
path: context.length > 0 ? `${context[0].path}/${key}` : `/${key}`,
|
|
1166
|
+
type: this._subType,
|
|
1167
|
+
parent: value
|
|
1168
|
+
};
|
|
1169
|
+
const result = this._subType.validate(itemValue, [...context, itemContext]);
|
|
1170
|
+
if (!result.valid) {
|
|
1171
|
+
errors.push(...result.errors);
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
return {
|
|
1175
|
+
valid: errors.length === 0,
|
|
1176
|
+
errors
|
|
1177
|
+
};
|
|
1178
|
+
}
|
|
1179
|
+
};
|
|
1180
|
+
function map(valueType) {
|
|
1181
|
+
return new MapType(valueType);
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
// src/utilities.ts
|
|
1185
|
+
init_tree();
|
|
1186
|
+
var OptionalType = class {
|
|
1187
|
+
constructor(subType, defaultValue) {
|
|
1188
|
+
this._kind = "optional";
|
|
1189
|
+
this._subType = subType;
|
|
1190
|
+
this._defaultValue = defaultValue;
|
|
1191
|
+
this.name = `optional<${subType.name}>`;
|
|
1192
|
+
}
|
|
1193
|
+
create(snapshot, env) {
|
|
1194
|
+
if (snapshot === void 0) {
|
|
1195
|
+
const defaultVal = typeof this._defaultValue === "function" ? this._defaultValue() : this._defaultValue;
|
|
1196
|
+
return this._subType.create(defaultVal, env);
|
|
1197
|
+
}
|
|
1198
|
+
return this._subType.create(snapshot, env);
|
|
1199
|
+
}
|
|
1200
|
+
is(value) {
|
|
1201
|
+
return value === void 0 || this._subType.is(value);
|
|
1202
|
+
}
|
|
1203
|
+
validate(value, context) {
|
|
1204
|
+
if (value === void 0) {
|
|
1205
|
+
return { valid: true, errors: [] };
|
|
1206
|
+
}
|
|
1207
|
+
return this._subType.validate(value, context);
|
|
1208
|
+
}
|
|
1209
|
+
};
|
|
1210
|
+
function optional(type, defaultValue) {
|
|
1211
|
+
return new OptionalType(type, defaultValue);
|
|
1212
|
+
}
|
|
1213
|
+
var MaybeType = class {
|
|
1214
|
+
constructor(subType) {
|
|
1215
|
+
this._kind = "maybe";
|
|
1216
|
+
this._subType = subType;
|
|
1217
|
+
this.name = `maybe<${subType.name}>`;
|
|
1218
|
+
}
|
|
1219
|
+
create(snapshot, env) {
|
|
1220
|
+
if (snapshot === void 0) {
|
|
1221
|
+
return void 0;
|
|
1222
|
+
}
|
|
1223
|
+
return this._subType.create(snapshot, env);
|
|
1224
|
+
}
|
|
1225
|
+
is(value) {
|
|
1226
|
+
return value === void 0 || this._subType.is(value);
|
|
1227
|
+
}
|
|
1228
|
+
validate(value, context) {
|
|
1229
|
+
if (value === void 0) {
|
|
1230
|
+
return { valid: true, errors: [] };
|
|
1231
|
+
}
|
|
1232
|
+
return this._subType.validate(value, context);
|
|
1233
|
+
}
|
|
1234
|
+
};
|
|
1235
|
+
function maybe(type) {
|
|
1236
|
+
return new MaybeType(type);
|
|
1237
|
+
}
|
|
1238
|
+
var MaybeNullType = class {
|
|
1239
|
+
constructor(subType) {
|
|
1240
|
+
this._kind = "maybeNull";
|
|
1241
|
+
this._subType = subType;
|
|
1242
|
+
this.name = `maybeNull<${subType.name}>`;
|
|
1243
|
+
}
|
|
1244
|
+
create(snapshot, env) {
|
|
1245
|
+
if (snapshot === null || snapshot === void 0) {
|
|
1246
|
+
return null;
|
|
1247
|
+
}
|
|
1248
|
+
return this._subType.create(snapshot, env);
|
|
1249
|
+
}
|
|
1250
|
+
is(value) {
|
|
1251
|
+
return value === null || this._subType.is(value);
|
|
1252
|
+
}
|
|
1253
|
+
validate(value, context) {
|
|
1254
|
+
if (value === null) {
|
|
1255
|
+
return { valid: true, errors: [] };
|
|
1256
|
+
}
|
|
1257
|
+
return this._subType.validate(value, context);
|
|
1258
|
+
}
|
|
1259
|
+
};
|
|
1260
|
+
function maybeNull(type) {
|
|
1261
|
+
return new MaybeNullType(type);
|
|
1262
|
+
}
|
|
1263
|
+
var UnionType = class {
|
|
1264
|
+
constructor(types2, options) {
|
|
1265
|
+
this._kind = "union";
|
|
1266
|
+
this._types = types2;
|
|
1267
|
+
this.dispatcher = options?.dispatcher;
|
|
1268
|
+
this.eager = options?.eager ?? true;
|
|
1269
|
+
this.name = `union(${types2.map((t) => t.name).join(" | ")})`;
|
|
1270
|
+
}
|
|
1271
|
+
create(snapshot, env) {
|
|
1272
|
+
if (this.dispatcher && snapshot !== void 0) {
|
|
1273
|
+
const type = this.dispatcher(snapshot);
|
|
1274
|
+
return type.create(snapshot, env);
|
|
1275
|
+
}
|
|
1276
|
+
for (const type of this._types) {
|
|
1277
|
+
try {
|
|
1278
|
+
const result = type.validate(snapshot, []);
|
|
1279
|
+
if (result.valid) {
|
|
1280
|
+
return type.create(snapshot, env);
|
|
1281
|
+
}
|
|
1282
|
+
} catch {
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
throw new Error(
|
|
1286
|
+
`[jotai-state-tree] No type in union matched the value: ${JSON.stringify(snapshot)}`
|
|
1287
|
+
);
|
|
1288
|
+
}
|
|
1289
|
+
is(value) {
|
|
1290
|
+
return this._types.some((type) => type.is(value));
|
|
1291
|
+
}
|
|
1292
|
+
validate(value, context) {
|
|
1293
|
+
for (const type of this._types) {
|
|
1294
|
+
const result = type.validate(value, context);
|
|
1295
|
+
if (result.valid) {
|
|
1296
|
+
return result;
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
return {
|
|
1300
|
+
valid: false,
|
|
1301
|
+
errors: [
|
|
1302
|
+
{
|
|
1303
|
+
context,
|
|
1304
|
+
value,
|
|
1305
|
+
message: `Value does not match any type in union`
|
|
1306
|
+
}
|
|
1307
|
+
]
|
|
1308
|
+
};
|
|
1309
|
+
}
|
|
1310
|
+
};
|
|
1311
|
+
function union(optionsOrType, ...rest) {
|
|
1312
|
+
if (optionsOrType && typeof optionsOrType === "object" && "dispatcher" in optionsOrType) {
|
|
1313
|
+
return new UnionType(rest, optionsOrType);
|
|
1314
|
+
}
|
|
1315
|
+
return new UnionType([optionsOrType, ...rest]);
|
|
1316
|
+
}
|
|
1317
|
+
var LateType = class {
|
|
1318
|
+
constructor(definition, name) {
|
|
1319
|
+
this._kind = "late";
|
|
1320
|
+
this._definition = definition;
|
|
1321
|
+
this.name = name ?? "late(...)";
|
|
1322
|
+
}
|
|
1323
|
+
getType() {
|
|
1324
|
+
if (!this.resolvedType) {
|
|
1325
|
+
this.resolvedType = this._definition();
|
|
1326
|
+
}
|
|
1327
|
+
return this.resolvedType;
|
|
1328
|
+
}
|
|
1329
|
+
create(snapshot, env) {
|
|
1330
|
+
return this.getType().create(snapshot, env);
|
|
1331
|
+
}
|
|
1332
|
+
is(value) {
|
|
1333
|
+
return this.getType().is(value);
|
|
1334
|
+
}
|
|
1335
|
+
validate(value, context) {
|
|
1336
|
+
return this.getType().validate(value, context);
|
|
1337
|
+
}
|
|
1338
|
+
};
|
|
1339
|
+
function late(nameOrDefinition, maybeDefinition) {
|
|
1340
|
+
if (typeof nameOrDefinition === "string") {
|
|
1341
|
+
return new LateType(maybeDefinition, nameOrDefinition);
|
|
1342
|
+
}
|
|
1343
|
+
return new LateType(nameOrDefinition);
|
|
1344
|
+
}
|
|
1345
|
+
var RefinementType = class {
|
|
1346
|
+
constructor(subType, predicate, message) {
|
|
1347
|
+
this._kind = "refinement";
|
|
1348
|
+
this._subType = subType;
|
|
1349
|
+
this._predicate = predicate;
|
|
1350
|
+
this.message = message ?? "Value failed refinement predicate";
|
|
1351
|
+
this.name = `refinement<${subType.name}>`;
|
|
1352
|
+
}
|
|
1353
|
+
create(snapshot, env) {
|
|
1354
|
+
const instance = this._subType.create(snapshot, env);
|
|
1355
|
+
if (!this._predicate(instance)) {
|
|
1356
|
+
const msg = typeof this.message === "function" ? this.message(instance) : this.message;
|
|
1357
|
+
throw new Error(`[jotai-state-tree] ${msg}`);
|
|
1358
|
+
}
|
|
1359
|
+
return instance;
|
|
1360
|
+
}
|
|
1361
|
+
is(value) {
|
|
1362
|
+
return this._subType.is(value) && this._predicate(value);
|
|
1363
|
+
}
|
|
1364
|
+
validate(value, context) {
|
|
1365
|
+
const baseResult = this._subType.validate(value, context);
|
|
1366
|
+
if (!baseResult.valid) {
|
|
1367
|
+
return baseResult;
|
|
1368
|
+
}
|
|
1369
|
+
if (!this._predicate(value)) {
|
|
1370
|
+
const msg = typeof this.message === "function" ? this.message(value) : this.message;
|
|
1371
|
+
return {
|
|
1372
|
+
valid: false,
|
|
1373
|
+
errors: [
|
|
1374
|
+
{
|
|
1375
|
+
context,
|
|
1376
|
+
value,
|
|
1377
|
+
message: msg
|
|
1378
|
+
}
|
|
1379
|
+
]
|
|
1380
|
+
};
|
|
1381
|
+
}
|
|
1382
|
+
return { valid: true, errors: [] };
|
|
1383
|
+
}
|
|
1384
|
+
};
|
|
1385
|
+
function refinement(type, predicate, message) {
|
|
1386
|
+
return new RefinementType(type, predicate, message);
|
|
1387
|
+
}
|
|
1388
|
+
var ReferenceType = class {
|
|
1389
|
+
constructor(targetType, options) {
|
|
1390
|
+
this._kind = "reference";
|
|
1391
|
+
this._targetType = targetType;
|
|
1392
|
+
this.options = options;
|
|
1393
|
+
this.name = `reference<${targetType.name}>`;
|
|
1394
|
+
}
|
|
1395
|
+
create(snapshot, env) {
|
|
1396
|
+
if (snapshot === void 0) {
|
|
1397
|
+
throw new Error("[jotai-state-tree] Reference requires an identifier");
|
|
1398
|
+
}
|
|
1399
|
+
const self = this;
|
|
1400
|
+
let resolved = null;
|
|
1401
|
+
if (this.options?.get) {
|
|
1402
|
+
const result = this.options.get(snapshot, null);
|
|
1403
|
+
if (result) return result;
|
|
1404
|
+
}
|
|
1405
|
+
const node = new StateTreeNode(this, snapshot, env);
|
|
1406
|
+
node.identifierValue = snapshot;
|
|
1407
|
+
const proxy = new Proxy({}, {
|
|
1408
|
+
get(target, prop) {
|
|
1409
|
+
if (!resolved) {
|
|
1410
|
+
const targetNode = resolveIdentifier(self._targetType.name, snapshot);
|
|
1411
|
+
if (!targetNode) {
|
|
1412
|
+
throw new Error(
|
|
1413
|
+
`[jotai-state-tree] Failed to resolve reference '${snapshot}' to type '${self._targetType.name}'`
|
|
1414
|
+
);
|
|
1415
|
+
}
|
|
1416
|
+
resolved = targetNode.getInstance();
|
|
1417
|
+
}
|
|
1418
|
+
if (prop === $treenode) {
|
|
1419
|
+
return node;
|
|
1420
|
+
}
|
|
1421
|
+
return resolved[prop];
|
|
1422
|
+
},
|
|
1423
|
+
set(target, prop, value) {
|
|
1424
|
+
if (!resolved) {
|
|
1425
|
+
const targetNode = resolveIdentifier(self._targetType.name, snapshot);
|
|
1426
|
+
if (!targetNode) {
|
|
1427
|
+
throw new Error(
|
|
1428
|
+
`[jotai-state-tree] Failed to resolve reference '${snapshot}' to type '${self._targetType.name}'`
|
|
1429
|
+
);
|
|
1430
|
+
}
|
|
1431
|
+
resolved = targetNode.getInstance();
|
|
1432
|
+
}
|
|
1433
|
+
resolved[prop] = value;
|
|
1434
|
+
return true;
|
|
1435
|
+
},
|
|
1436
|
+
has(target, prop) {
|
|
1437
|
+
if (!resolved) {
|
|
1438
|
+
const targetNode = resolveIdentifier(self._targetType.name, snapshot);
|
|
1439
|
+
if (targetNode) {
|
|
1440
|
+
resolved = targetNode.getInstance();
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
return resolved ? prop in resolved : false;
|
|
1444
|
+
}
|
|
1445
|
+
});
|
|
1446
|
+
node.setInstance(proxy);
|
|
1447
|
+
return proxy;
|
|
1448
|
+
}
|
|
1449
|
+
is(value) {
|
|
1450
|
+
return this._targetType.is(value);
|
|
1451
|
+
}
|
|
1452
|
+
validate(value, context) {
|
|
1453
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
1454
|
+
return { valid: true, errors: [] };
|
|
1455
|
+
}
|
|
1456
|
+
return {
|
|
1457
|
+
valid: false,
|
|
1458
|
+
errors: [
|
|
1459
|
+
{
|
|
1460
|
+
context,
|
|
1461
|
+
value,
|
|
1462
|
+
message: "Reference must be a string or number identifier"
|
|
1463
|
+
}
|
|
1464
|
+
]
|
|
1465
|
+
};
|
|
1466
|
+
}
|
|
1467
|
+
};
|
|
1468
|
+
function reference(targetType, options) {
|
|
1469
|
+
return new ReferenceType(targetType, options);
|
|
1470
|
+
}
|
|
1471
|
+
var SafeReferenceType = class {
|
|
1472
|
+
constructor(targetType, options) {
|
|
1473
|
+
this._kind = "safeReference";
|
|
1474
|
+
this._targetType = targetType;
|
|
1475
|
+
this.options = options;
|
|
1476
|
+
this.name = `safeReference<${targetType.name}>`;
|
|
1477
|
+
}
|
|
1478
|
+
create(snapshot, env) {
|
|
1479
|
+
if (snapshot === void 0) {
|
|
1480
|
+
return void 0;
|
|
1481
|
+
}
|
|
1482
|
+
const targetNode = resolveIdentifier(this._targetType.name, snapshot);
|
|
1483
|
+
if (!targetNode) {
|
|
1484
|
+
if (this.options?.onInvalidated) {
|
|
1485
|
+
return void 0;
|
|
1486
|
+
}
|
|
1487
|
+
return void 0;
|
|
1488
|
+
}
|
|
1489
|
+
return targetNode.getInstance();
|
|
1490
|
+
}
|
|
1491
|
+
is(value) {
|
|
1492
|
+
return value === void 0 || this._targetType.is(value);
|
|
1493
|
+
}
|
|
1494
|
+
validate(value, context) {
|
|
1495
|
+
if (value === void 0) {
|
|
1496
|
+
return { valid: true, errors: [] };
|
|
1497
|
+
}
|
|
1498
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
1499
|
+
return { valid: true, errors: [] };
|
|
1500
|
+
}
|
|
1501
|
+
return {
|
|
1502
|
+
valid: false,
|
|
1503
|
+
errors: [
|
|
1504
|
+
{
|
|
1505
|
+
context,
|
|
1506
|
+
value,
|
|
1507
|
+
message: "Safe reference must be a string, number, or undefined"
|
|
1508
|
+
}
|
|
1509
|
+
]
|
|
1510
|
+
};
|
|
1511
|
+
}
|
|
1512
|
+
};
|
|
1513
|
+
function safeReference(targetType, options) {
|
|
1514
|
+
return new SafeReferenceType(targetType, options);
|
|
1515
|
+
}
|
|
1516
|
+
function snapshotProcessor(type, processors) {
|
|
1517
|
+
return {
|
|
1518
|
+
name: `snapshotProcessor<${type.name}>`,
|
|
1519
|
+
_kind: "simple",
|
|
1520
|
+
_C: void 0,
|
|
1521
|
+
_S: void 0,
|
|
1522
|
+
_T: void 0,
|
|
1523
|
+
create(snapshot, env) {
|
|
1524
|
+
const processed = processors.preProcessor ? processors.preProcessor(snapshot) : snapshot;
|
|
1525
|
+
return type.create(processed, env);
|
|
1526
|
+
},
|
|
1527
|
+
is(value) {
|
|
1528
|
+
return type.is(value);
|
|
1529
|
+
},
|
|
1530
|
+
validate(value, context) {
|
|
1531
|
+
return type.validate(value, context);
|
|
1532
|
+
}
|
|
1533
|
+
};
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
// src/registry.ts
|
|
1537
|
+
init_tree();
|
|
1538
|
+
var modelRegistry = /* @__PURE__ */ new Map();
|
|
1539
|
+
var pendingResolutions = /* @__PURE__ */ new Map();
|
|
1540
|
+
var registrationListeners = /* @__PURE__ */ new Set();
|
|
1541
|
+
function registerModel(name, type, metadata) {
|
|
1542
|
+
if (modelRegistry.has(name)) {
|
|
1543
|
+
throw new Error(
|
|
1544
|
+
`[jotai-state-tree] Model "${name}" is already registered. Use unregisterModel() first if you want to replace it.`
|
|
1545
|
+
);
|
|
1546
|
+
}
|
|
1547
|
+
modelRegistry.set(name, { type, metadata });
|
|
1548
|
+
const pending = pendingResolutions.get(name);
|
|
1549
|
+
if (pending) {
|
|
1550
|
+
pending.forEach(({ resolve }) => resolve(type));
|
|
1551
|
+
pendingResolutions.delete(name);
|
|
1552
|
+
}
|
|
1553
|
+
registrationListeners.forEach((listener) => listener(name, type));
|
|
1554
|
+
}
|
|
1555
|
+
function unregisterModel(name) {
|
|
1556
|
+
return modelRegistry.delete(name);
|
|
1557
|
+
}
|
|
1558
|
+
function isModelRegistered(name) {
|
|
1559
|
+
return modelRegistry.has(name);
|
|
1560
|
+
}
|
|
1561
|
+
function resolveModel(name) {
|
|
1562
|
+
const entry = modelRegistry.get(name);
|
|
1563
|
+
if (!entry) {
|
|
1564
|
+
throw new Error(
|
|
1565
|
+
`[jotai-state-tree] Model "${name}" is not registered. Make sure to call registerModel("${name}", YourModelType) before resolving.`
|
|
1566
|
+
);
|
|
1567
|
+
}
|
|
1568
|
+
return entry.type;
|
|
1569
|
+
}
|
|
1570
|
+
function tryResolveModel(name) {
|
|
1571
|
+
return modelRegistry.get(name)?.type;
|
|
1572
|
+
}
|
|
1573
|
+
function resolveModelAsync(name, timeout = 3e4) {
|
|
1574
|
+
const entry = modelRegistry.get(name);
|
|
1575
|
+
if (entry) {
|
|
1576
|
+
return Promise.resolve(entry.type);
|
|
1577
|
+
}
|
|
1578
|
+
return new Promise((resolve, reject) => {
|
|
1579
|
+
const timeoutId = setTimeout(() => {
|
|
1580
|
+
const pending = pendingResolutions.get(name);
|
|
1581
|
+
if (pending) {
|
|
1582
|
+
const index = pending.findIndex((p) => p.resolve === resolve);
|
|
1583
|
+
if (index >= 0) {
|
|
1584
|
+
pending.splice(index, 1);
|
|
1585
|
+
if (pending.length === 0) {
|
|
1586
|
+
pendingResolutions.delete(name);
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
reject(
|
|
1591
|
+
new Error(
|
|
1592
|
+
`[jotai-state-tree] Timeout waiting for model "${name}" to be registered`
|
|
1593
|
+
)
|
|
1594
|
+
);
|
|
1595
|
+
}, timeout);
|
|
1596
|
+
const wrappedResolve = (type) => {
|
|
1597
|
+
clearTimeout(timeoutId);
|
|
1598
|
+
resolve(type);
|
|
1599
|
+
};
|
|
1600
|
+
const wrappedReject = (error) => {
|
|
1601
|
+
clearTimeout(timeoutId);
|
|
1602
|
+
reject(error);
|
|
1603
|
+
};
|
|
1604
|
+
if (!pendingResolutions.has(name)) {
|
|
1605
|
+
pendingResolutions.set(name, []);
|
|
1606
|
+
}
|
|
1607
|
+
pendingResolutions.get(name).push({
|
|
1608
|
+
resolve: wrappedResolve,
|
|
1609
|
+
reject: wrappedReject
|
|
1610
|
+
});
|
|
1611
|
+
});
|
|
1612
|
+
}
|
|
1613
|
+
function getModelMetadata(name) {
|
|
1614
|
+
return modelRegistry.get(name)?.metadata;
|
|
1615
|
+
}
|
|
1616
|
+
function getRegisteredModelNames() {
|
|
1617
|
+
return Array.from(modelRegistry.keys());
|
|
1618
|
+
}
|
|
1619
|
+
function onModelRegistered(listener) {
|
|
1620
|
+
registrationListeners.add(listener);
|
|
1621
|
+
return () => {
|
|
1622
|
+
registrationListeners.delete(listener);
|
|
1623
|
+
};
|
|
1624
|
+
}
|
|
1625
|
+
function clearModelRegistry() {
|
|
1626
|
+
modelRegistry.clear();
|
|
1627
|
+
pendingResolutions.forEach((pending, name) => {
|
|
1628
|
+
pending.forEach(({ reject }) => {
|
|
1629
|
+
reject(
|
|
1630
|
+
new Error(
|
|
1631
|
+
`[jotai-state-tree] Model registry was cleared while waiting for "${name}"`
|
|
1632
|
+
)
|
|
1633
|
+
);
|
|
1634
|
+
});
|
|
1635
|
+
});
|
|
1636
|
+
pendingResolutions.clear();
|
|
1637
|
+
}
|
|
1638
|
+
var LateModelType = class {
|
|
1639
|
+
constructor(modelName) {
|
|
1640
|
+
this._kind = "lateModel";
|
|
1641
|
+
this._modelName = modelName;
|
|
1642
|
+
this.name = `lateModel("${modelName}")`;
|
|
1643
|
+
}
|
|
1644
|
+
getType() {
|
|
1645
|
+
if (!this._resolvedType) {
|
|
1646
|
+
this._resolvedType = resolveModel(this._modelName);
|
|
1647
|
+
}
|
|
1648
|
+
return this._resolvedType;
|
|
1649
|
+
}
|
|
1650
|
+
create(snapshot, env) {
|
|
1651
|
+
return this.getType().create(snapshot, env);
|
|
1652
|
+
}
|
|
1653
|
+
is(value) {
|
|
1654
|
+
return this.getType().is(value);
|
|
1655
|
+
}
|
|
1656
|
+
validate(value, context) {
|
|
1657
|
+
return this.getType().validate(value, context);
|
|
1658
|
+
}
|
|
1659
|
+
};
|
|
1660
|
+
function lateModel(modelName) {
|
|
1661
|
+
return new LateModelType(modelName);
|
|
1662
|
+
}
|
|
1663
|
+
var DynamicReferenceType = class {
|
|
1664
|
+
constructor(modelName, options = {}) {
|
|
1665
|
+
this._kind = "dynamicReference";
|
|
1666
|
+
this._modelName = modelName;
|
|
1667
|
+
this._options = options;
|
|
1668
|
+
this.name = `dynamicReference("${modelName}")`;
|
|
1669
|
+
}
|
|
1670
|
+
create(snapshot, env) {
|
|
1671
|
+
if (snapshot === void 0 || snapshot === null) {
|
|
1672
|
+
throw new Error(
|
|
1673
|
+
`[jotai-state-tree] Cannot create dynamicReference with undefined/null identifier`
|
|
1674
|
+
);
|
|
1675
|
+
}
|
|
1676
|
+
const self = this;
|
|
1677
|
+
const referenceProxy = new Proxy({}, {
|
|
1678
|
+
get(_target, prop) {
|
|
1679
|
+
const resolved = self.resolveReference(snapshot, null);
|
|
1680
|
+
if (!resolved) {
|
|
1681
|
+
if (self._options.onInvalidated) {
|
|
1682
|
+
const fallback = self._options.onInvalidated(snapshot, null);
|
|
1683
|
+
if (fallback) {
|
|
1684
|
+
return fallback[prop];
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
throw new Error(
|
|
1688
|
+
`[jotai-state-tree] Failed to resolve dynamicReference("${self._modelName}") with identifier "${snapshot}"`
|
|
1689
|
+
);
|
|
1690
|
+
}
|
|
1691
|
+
return resolved[prop];
|
|
1692
|
+
},
|
|
1693
|
+
has(_target, prop) {
|
|
1694
|
+
const resolved = self.resolveReference(snapshot, null);
|
|
1695
|
+
if (!resolved) return false;
|
|
1696
|
+
return prop in resolved;
|
|
1697
|
+
},
|
|
1698
|
+
ownKeys(_target) {
|
|
1699
|
+
const resolved = self.resolveReference(snapshot, null);
|
|
1700
|
+
if (!resolved) return [];
|
|
1701
|
+
return Reflect.ownKeys(resolved);
|
|
1702
|
+
},
|
|
1703
|
+
getOwnPropertyDescriptor(_target, prop) {
|
|
1704
|
+
const resolved = self.resolveReference(snapshot, null);
|
|
1705
|
+
if (!resolved) return void 0;
|
|
1706
|
+
return Object.getOwnPropertyDescriptor(resolved, prop);
|
|
1707
|
+
}
|
|
1708
|
+
});
|
|
1709
|
+
return referenceProxy;
|
|
1710
|
+
}
|
|
1711
|
+
resolveReference(identifier2, parent) {
|
|
1712
|
+
if (this._options.get) {
|
|
1713
|
+
return this._options.get(identifier2, parent);
|
|
1714
|
+
}
|
|
1715
|
+
try {
|
|
1716
|
+
const targetType = tryResolveModel(this._modelName);
|
|
1717
|
+
if (!targetType) {
|
|
1718
|
+
return void 0;
|
|
1719
|
+
}
|
|
1720
|
+
return resolveIdentifier(this._modelName, identifier2);
|
|
1721
|
+
} catch {
|
|
1722
|
+
return void 0;
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
is(value) {
|
|
1726
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
1727
|
+
return true;
|
|
1728
|
+
}
|
|
1729
|
+
const targetType = tryResolveModel(this._modelName);
|
|
1730
|
+
if (targetType) {
|
|
1731
|
+
return targetType.is(value);
|
|
1732
|
+
}
|
|
1733
|
+
return false;
|
|
1734
|
+
}
|
|
1735
|
+
validate(value, context) {
|
|
1736
|
+
if (value === void 0 || value === null) {
|
|
1737
|
+
return {
|
|
1738
|
+
valid: false,
|
|
1739
|
+
errors: [
|
|
1740
|
+
{
|
|
1741
|
+
context,
|
|
1742
|
+
value,
|
|
1743
|
+
message: "Reference identifier cannot be undefined or null"
|
|
1744
|
+
}
|
|
1745
|
+
]
|
|
1746
|
+
};
|
|
1747
|
+
}
|
|
1748
|
+
if (typeof value !== "string" && typeof value !== "number") {
|
|
1749
|
+
return {
|
|
1750
|
+
valid: false,
|
|
1751
|
+
errors: [
|
|
1752
|
+
{
|
|
1753
|
+
context,
|
|
1754
|
+
value,
|
|
1755
|
+
message: "Reference identifier must be a string or number"
|
|
1756
|
+
}
|
|
1757
|
+
]
|
|
1758
|
+
};
|
|
1759
|
+
}
|
|
1760
|
+
return { valid: true, errors: [] };
|
|
1761
|
+
}
|
|
1762
|
+
};
|
|
1763
|
+
function dynamicReference(modelName, options = {}) {
|
|
1764
|
+
return new DynamicReferenceType(modelName, options);
|
|
1765
|
+
}
|
|
1766
|
+
var SafeDynamicReferenceType = class {
|
|
1767
|
+
constructor(modelName, options = {}) {
|
|
1768
|
+
this._kind = "safeDynamicReference";
|
|
1769
|
+
this._modelName = modelName;
|
|
1770
|
+
this._options = options;
|
|
1771
|
+
this.name = `safeDynamicReference("${modelName}")`;
|
|
1772
|
+
}
|
|
1773
|
+
create(snapshot, env) {
|
|
1774
|
+
if (snapshot === void 0 || snapshot === null) {
|
|
1775
|
+
return void 0;
|
|
1776
|
+
}
|
|
1777
|
+
try {
|
|
1778
|
+
if (this._options.get) {
|
|
1779
|
+
return this._options.get(snapshot, null);
|
|
1780
|
+
}
|
|
1781
|
+
const targetType = tryResolveModel(this._modelName);
|
|
1782
|
+
if (!targetType) {
|
|
1783
|
+
return void 0;
|
|
1784
|
+
}
|
|
1785
|
+
return resolveIdentifier(this._modelName, snapshot);
|
|
1786
|
+
} catch {
|
|
1787
|
+
if (this._options.onInvalidated) {
|
|
1788
|
+
return this._options.onInvalidated(snapshot, null);
|
|
1789
|
+
}
|
|
1790
|
+
return void 0;
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
is(value) {
|
|
1794
|
+
if (value === void 0) return true;
|
|
1795
|
+
if (typeof value === "string" || typeof value === "number") return true;
|
|
1796
|
+
const targetType = tryResolveModel(this._modelName);
|
|
1797
|
+
if (targetType) {
|
|
1798
|
+
return targetType.is(value);
|
|
1799
|
+
}
|
|
1800
|
+
return false;
|
|
1801
|
+
}
|
|
1802
|
+
validate(value, context) {
|
|
1803
|
+
if (value === void 0 || value === null) {
|
|
1804
|
+
return { valid: true, errors: [] };
|
|
1805
|
+
}
|
|
1806
|
+
if (typeof value !== "string" && typeof value !== "number") {
|
|
1807
|
+
return {
|
|
1808
|
+
valid: false,
|
|
1809
|
+
errors: [
|
|
1810
|
+
{
|
|
1811
|
+
context,
|
|
1812
|
+
value,
|
|
1813
|
+
message: "Reference identifier must be a string, number, or undefined"
|
|
1814
|
+
}
|
|
1815
|
+
]
|
|
1816
|
+
};
|
|
1817
|
+
}
|
|
1818
|
+
return { valid: true, errors: [] };
|
|
1819
|
+
}
|
|
1820
|
+
};
|
|
1821
|
+
function safeDynamicReference(modelName, options = {}) {
|
|
1822
|
+
return new SafeDynamicReferenceType(modelName, options);
|
|
1823
|
+
}
|
|
1824
|
+
|
|
1825
|
+
// src/index.ts
|
|
1826
|
+
init_tree();
|
|
1827
|
+
|
|
1828
|
+
// src/lifecycle.ts
|
|
1829
|
+
init_tree();
|
|
1830
|
+
var middlewareStack = [];
|
|
1831
|
+
function addMiddleware(target, handler, includeHooks = true) {
|
|
1832
|
+
middlewareStack.push(handler);
|
|
1833
|
+
return () => {
|
|
1834
|
+
const index = middlewareStack.indexOf(handler);
|
|
1835
|
+
if (index >= 0) {
|
|
1836
|
+
middlewareStack.splice(index, 1);
|
|
1837
|
+
}
|
|
1838
|
+
};
|
|
1839
|
+
}
|
|
1840
|
+
var actionRecorders = /* @__PURE__ */ new WeakMap();
|
|
1841
|
+
function recordActions(target) {
|
|
1842
|
+
const node = getStateTreeNode(target);
|
|
1843
|
+
const actions = [];
|
|
1844
|
+
const recorder = (action) => {
|
|
1845
|
+
if (node.$isAlive) {
|
|
1846
|
+
actions.push(action);
|
|
1847
|
+
}
|
|
1848
|
+
};
|
|
1849
|
+
let recorders = actionRecorders.get(node);
|
|
1850
|
+
if (!recorders) {
|
|
1851
|
+
recorders = /* @__PURE__ */ new Set();
|
|
1852
|
+
actionRecorders.set(node, recorders);
|
|
1853
|
+
}
|
|
1854
|
+
recorders.add(recorder);
|
|
1855
|
+
return {
|
|
1856
|
+
actions,
|
|
1857
|
+
stop: () => {
|
|
1858
|
+
const currentRecorders = actionRecorders.get(node);
|
|
1859
|
+
if (currentRecorders) {
|
|
1860
|
+
currentRecorders.delete(recorder);
|
|
1861
|
+
if (currentRecorders.size === 0) {
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1864
|
+
},
|
|
1865
|
+
replay: (replayTarget) => {
|
|
1866
|
+
const replayNode = getStateTreeNode(replayTarget);
|
|
1867
|
+
for (const action of actions) {
|
|
1868
|
+
const instance = replayNode.getInstance();
|
|
1869
|
+
if (typeof instance[action.name] === "function") {
|
|
1870
|
+
instance[action.name](...action.args);
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
};
|
|
1875
|
+
}
|
|
1876
|
+
function notifyActionRecorders(node, action) {
|
|
1877
|
+
let current = node;
|
|
1878
|
+
while (current) {
|
|
1879
|
+
const recorders = actionRecorders.get(current);
|
|
1880
|
+
if (recorders) {
|
|
1881
|
+
recorders.forEach((recorder) => recorder(action));
|
|
1882
|
+
}
|
|
1883
|
+
current = current.$parent;
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
registerActionRecorderHook((node, call) => {
|
|
1887
|
+
const action = {
|
|
1888
|
+
name: call.name,
|
|
1889
|
+
path: call.path,
|
|
1890
|
+
args: call.args
|
|
1891
|
+
};
|
|
1892
|
+
notifyActionRecorders(node, action);
|
|
1893
|
+
});
|
|
1894
|
+
var protectedNodes = /* @__PURE__ */ new WeakSet();
|
|
1895
|
+
function protect(target) {
|
|
1896
|
+
const node = getStateTreeNode(target);
|
|
1897
|
+
protectedNodes.add(node);
|
|
1898
|
+
}
|
|
1899
|
+
function unprotect(target) {
|
|
1900
|
+
const node = getStateTreeNode(target);
|
|
1901
|
+
protectedNodes.delete(node);
|
|
1902
|
+
}
|
|
1903
|
+
function isProtected(target) {
|
|
1904
|
+
const node = getStateTreeNode(target);
|
|
1905
|
+
return protectedNodes.has(node);
|
|
1906
|
+
}
|
|
1907
|
+
function applyAction(target, action) {
|
|
1908
|
+
const node = getStateTreeNode(target);
|
|
1909
|
+
let currentNode = node;
|
|
1910
|
+
if (action.path) {
|
|
1911
|
+
const parts = action.path.split("/").filter(Boolean);
|
|
1912
|
+
for (const part of parts) {
|
|
1913
|
+
const child = currentNode.getChild(part);
|
|
1914
|
+
if (!child) {
|
|
1915
|
+
throw new Error(
|
|
1916
|
+
`[jotai-state-tree] Invalid action path: ${action.path}`
|
|
1917
|
+
);
|
|
1918
|
+
}
|
|
1919
|
+
currentNode = child;
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
const instance = currentNode.getInstance();
|
|
1923
|
+
if (typeof instance[action.name] !== "function") {
|
|
1924
|
+
throw new Error(`[jotai-state-tree] Action '${action.name}' not found`);
|
|
1925
|
+
}
|
|
1926
|
+
return instance[action.name](...action.args);
|
|
1927
|
+
}
|
|
1928
|
+
function escapeJsonPath(path) {
|
|
1929
|
+
return path.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
1930
|
+
}
|
|
1931
|
+
function unescapeJsonPath(path) {
|
|
1932
|
+
return path.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
1933
|
+
}
|
|
1934
|
+
function splitJsonPath(path) {
|
|
1935
|
+
return path.split("/").filter(Boolean).map(unescapeJsonPath);
|
|
1936
|
+
}
|
|
1937
|
+
function joinJsonPath(parts) {
|
|
1938
|
+
return parts.map(escapeJsonPath).join("/");
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1941
|
+
// src/compat.ts
|
|
1942
|
+
init_tree();
|
|
1943
|
+
function isType(value) {
|
|
1944
|
+
return value !== null && typeof value === "object" && "_kind" in value && "create" in value && "is" in value;
|
|
1945
|
+
}
|
|
1946
|
+
function isPrimitiveType(type) {
|
|
1947
|
+
return isType(type) && (type._kind === "simple" || type._kind === "literal" || type._kind === "enumeration" || type._kind === "identifier" || type._kind === "identifierNumber");
|
|
1948
|
+
}
|
|
1949
|
+
function getTypeName(type) {
|
|
1950
|
+
return type.name;
|
|
1951
|
+
}
|
|
1952
|
+
function isValidSnapshot(type, value) {
|
|
1953
|
+
try {
|
|
1954
|
+
const result = type.validate(value, []);
|
|
1955
|
+
return result.valid;
|
|
1956
|
+
} catch {
|
|
1957
|
+
return false;
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
function getValidationError(type, value) {
|
|
1961
|
+
const result = type.validate(value, [{ path: "", type, parent: null }]);
|
|
1962
|
+
if (result.valid) return null;
|
|
1963
|
+
return result.errors.map((e) => e.message).join("; ");
|
|
1964
|
+
}
|
|
1965
|
+
function isInstanceOf(value, type) {
|
|
1966
|
+
if (!hasStateTreeNode(value)) return false;
|
|
1967
|
+
const node = getStateTreeNode(value);
|
|
1968
|
+
return node.$type === type || node.$type.name === type.name;
|
|
1969
|
+
}
|
|
1970
|
+
function getOrCreate(type, snapshotOrInstance, env) {
|
|
1971
|
+
if (hasStateTreeNode(snapshotOrInstance)) {
|
|
1972
|
+
return snapshotOrInstance;
|
|
1973
|
+
}
|
|
1974
|
+
return type.create(snapshotOrInstance, env);
|
|
1975
|
+
}
|
|
1976
|
+
function getDebugInfo(target) {
|
|
1977
|
+
const node = getStateTreeNode(target);
|
|
1978
|
+
return {
|
|
1979
|
+
typeName: node.$type.name,
|
|
1980
|
+
path: node.$path,
|
|
1981
|
+
identifier: node.identifierValue ?? null,
|
|
1982
|
+
isAlive: node.$isAlive,
|
|
1983
|
+
snapshot: getSnapshot(target)
|
|
1984
|
+
};
|
|
1985
|
+
}
|
|
1986
|
+
function printTree(target, indent = 0) {
|
|
1987
|
+
const node = getStateTreeNode(target);
|
|
1988
|
+
const prefix = " ".repeat(indent);
|
|
1989
|
+
let output = `${prefix}${node.$type.name}`;
|
|
1990
|
+
if (node.identifierValue !== void 0) {
|
|
1991
|
+
output += ` (${node.identifierValue})`;
|
|
1992
|
+
}
|
|
1993
|
+
output += "\n";
|
|
1994
|
+
for (const [key, child] of node.getChildren()) {
|
|
1995
|
+
const childInstance = child.getInstance();
|
|
1996
|
+
if (childInstance && hasStateTreeNode(childInstance)) {
|
|
1997
|
+
output += `${prefix} ${key}: ${printTree(childInstance, indent + 2)}`;
|
|
1998
|
+
} else {
|
|
1999
|
+
output += `${prefix} ${key}: ${JSON.stringify(child.getValue())}
|
|
2000
|
+
`;
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
return output;
|
|
2004
|
+
}
|
|
2005
|
+
function hasIdentifier(type) {
|
|
2006
|
+
return type.identifierAttribute !== void 0;
|
|
2007
|
+
}
|
|
2008
|
+
function getIdentifierAttribute(type) {
|
|
2009
|
+
return type.identifierAttribute;
|
|
2010
|
+
}
|
|
2011
|
+
function nullable(type) {
|
|
2012
|
+
return {
|
|
2013
|
+
name: `nullable<${type.name}>`,
|
|
2014
|
+
_kind: "maybe",
|
|
2015
|
+
_C: void 0,
|
|
2016
|
+
_S: void 0,
|
|
2017
|
+
_T: void 0,
|
|
2018
|
+
create(snapshot, env) {
|
|
2019
|
+
if (snapshot === null || snapshot === void 0) {
|
|
2020
|
+
return snapshot;
|
|
2021
|
+
}
|
|
2022
|
+
return type.create(snapshot, env);
|
|
2023
|
+
},
|
|
2024
|
+
is(value) {
|
|
2025
|
+
return value === null || value === void 0 || type.is(value);
|
|
2026
|
+
},
|
|
2027
|
+
validate(value, context) {
|
|
2028
|
+
if (value === null || value === void 0) {
|
|
2029
|
+
return { valid: true, errors: [] };
|
|
2030
|
+
}
|
|
2031
|
+
return type.validate(value, context);
|
|
2032
|
+
}
|
|
2033
|
+
};
|
|
2034
|
+
}
|
|
2035
|
+
function cloneFrozen(value) {
|
|
2036
|
+
if (value === null || typeof value !== "object") {
|
|
2037
|
+
return value;
|
|
2038
|
+
}
|
|
2039
|
+
if (Array.isArray(value)) {
|
|
2040
|
+
return value.map(cloneFrozen);
|
|
2041
|
+
}
|
|
2042
|
+
const result = {};
|
|
2043
|
+
for (const [key, val] of Object.entries(value)) {
|
|
2044
|
+
result[key] = cloneFrozen(val);
|
|
2045
|
+
}
|
|
2046
|
+
return result;
|
|
2047
|
+
}
|
|
2048
|
+
function safeCreate(type, snapshot, env) {
|
|
2049
|
+
try {
|
|
2050
|
+
return type.create(snapshot, env);
|
|
2051
|
+
} catch {
|
|
2052
|
+
return void 0;
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
function createWithDefaults(type, snapshot = {}, env) {
|
|
2056
|
+
return type.create(snapshot, env);
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
// src/undo.ts
|
|
2060
|
+
init_tree();
|
|
2061
|
+
var UndoManager = class {
|
|
2062
|
+
constructor(target, options = {}) {
|
|
2063
|
+
this.historyEntries = [];
|
|
2064
|
+
this.currentIndex = -1;
|
|
2065
|
+
this.isUndoing = false;
|
|
2066
|
+
this.isRedoing = false;
|
|
2067
|
+
this.skipRecording = false;
|
|
2068
|
+
this.grouping = false;
|
|
2069
|
+
this.currentGroup = [];
|
|
2070
|
+
this.currentGroupInverse = [];
|
|
2071
|
+
this.disposer = null;
|
|
2072
|
+
this.lastChangeTime = 0;
|
|
2073
|
+
this.target = target;
|
|
2074
|
+
this.options = {
|
|
2075
|
+
maxHistoryLength: options.maxHistoryLength ?? 100,
|
|
2076
|
+
groupByTime: options.groupByTime ?? false,
|
|
2077
|
+
groupingWindow: options.groupingWindow ?? 200
|
|
2078
|
+
};
|
|
2079
|
+
this.disposer = onPatch(target, (patch, reversePatch) => {
|
|
2080
|
+
this.recordPatch(patch, reversePatch);
|
|
2081
|
+
});
|
|
2082
|
+
}
|
|
2083
|
+
get canUndo() {
|
|
2084
|
+
return this.currentIndex >= 0;
|
|
2085
|
+
}
|
|
2086
|
+
get canRedo() {
|
|
2087
|
+
return this.currentIndex < this.historyEntries.length - 1;
|
|
2088
|
+
}
|
|
2089
|
+
get undoLevels() {
|
|
2090
|
+
return this.currentIndex + 1;
|
|
2091
|
+
}
|
|
2092
|
+
get redoLevels() {
|
|
2093
|
+
return this.historyEntries.length - this.currentIndex - 1;
|
|
2094
|
+
}
|
|
2095
|
+
get history() {
|
|
2096
|
+
return [...this.historyEntries];
|
|
2097
|
+
}
|
|
2098
|
+
get historyIndex() {
|
|
2099
|
+
return this.currentIndex;
|
|
2100
|
+
}
|
|
2101
|
+
recordPatch(patch, reversePatch) {
|
|
2102
|
+
if (this.isUndoing || this.isRedoing || this.skipRecording) {
|
|
2103
|
+
return;
|
|
2104
|
+
}
|
|
2105
|
+
const now = Date.now();
|
|
2106
|
+
if (this.grouping) {
|
|
2107
|
+
this.currentGroup.push(reversePatch);
|
|
2108
|
+
this.currentGroupInverse.unshift({ ...patch });
|
|
2109
|
+
return;
|
|
2110
|
+
}
|
|
2111
|
+
if (this.options.groupByTime && this.historyEntries.length > 0 && now - this.lastChangeTime < this.options.groupingWindow && this.currentIndex === this.historyEntries.length - 1) {
|
|
2112
|
+
const lastEntry = this.historyEntries[this.currentIndex];
|
|
2113
|
+
lastEntry.patches.push(reversePatch);
|
|
2114
|
+
lastEntry.inversePatches.unshift({ ...patch });
|
|
2115
|
+
lastEntry.timestamp = now;
|
|
2116
|
+
} else {
|
|
2117
|
+
if (this.currentIndex < this.historyEntries.length - 1) {
|
|
2118
|
+
this.historyEntries.splice(this.currentIndex + 1);
|
|
2119
|
+
}
|
|
2120
|
+
this.historyEntries.push({
|
|
2121
|
+
patches: [reversePatch],
|
|
2122
|
+
inversePatches: [{ ...patch }],
|
|
2123
|
+
timestamp: now
|
|
2124
|
+
});
|
|
2125
|
+
this.currentIndex++;
|
|
2126
|
+
if (this.historyEntries.length > this.options.maxHistoryLength) {
|
|
2127
|
+
const excess = this.historyEntries.length - this.options.maxHistoryLength;
|
|
2128
|
+
this.historyEntries.splice(0, excess);
|
|
2129
|
+
this.currentIndex -= excess;
|
|
2130
|
+
}
|
|
2131
|
+
}
|
|
2132
|
+
this.lastChangeTime = now;
|
|
2133
|
+
}
|
|
2134
|
+
undo() {
|
|
2135
|
+
if (!this.canUndo) {
|
|
2136
|
+
return;
|
|
2137
|
+
}
|
|
2138
|
+
this.isUndoing = true;
|
|
2139
|
+
try {
|
|
2140
|
+
const entry = this.historyEntries[this.currentIndex];
|
|
2141
|
+
for (let i = entry.patches.length - 1; i >= 0; i--) {
|
|
2142
|
+
applyPatch(this.target, entry.patches[i]);
|
|
2143
|
+
}
|
|
2144
|
+
this.currentIndex--;
|
|
2145
|
+
} finally {
|
|
2146
|
+
this.isUndoing = false;
|
|
2147
|
+
}
|
|
2148
|
+
}
|
|
2149
|
+
redo() {
|
|
2150
|
+
if (!this.canRedo) {
|
|
2151
|
+
return;
|
|
2152
|
+
}
|
|
2153
|
+
this.isRedoing = true;
|
|
2154
|
+
try {
|
|
2155
|
+
this.currentIndex++;
|
|
2156
|
+
const entry = this.historyEntries[this.currentIndex];
|
|
2157
|
+
for (const patch of entry.inversePatches) {
|
|
2158
|
+
applyPatch(this.target, patch);
|
|
2159
|
+
}
|
|
2160
|
+
} finally {
|
|
2161
|
+
this.isRedoing = false;
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
clear() {
|
|
2165
|
+
this.historyEntries = [];
|
|
2166
|
+
this.currentIndex = -1;
|
|
2167
|
+
this.currentGroup = [];
|
|
2168
|
+
this.currentGroupInverse = [];
|
|
2169
|
+
this.grouping = false;
|
|
2170
|
+
}
|
|
2171
|
+
startGroup() {
|
|
2172
|
+
this.grouping = true;
|
|
2173
|
+
this.currentGroup = [];
|
|
2174
|
+
this.currentGroupInverse = [];
|
|
2175
|
+
}
|
|
2176
|
+
endGroup() {
|
|
2177
|
+
if (!this.grouping) {
|
|
2178
|
+
return;
|
|
2179
|
+
}
|
|
2180
|
+
this.grouping = false;
|
|
2181
|
+
if (this.currentGroup.length > 0) {
|
|
2182
|
+
if (this.currentIndex < this.historyEntries.length - 1) {
|
|
2183
|
+
this.historyEntries.splice(this.currentIndex + 1);
|
|
2184
|
+
}
|
|
2185
|
+
this.historyEntries.push({
|
|
2186
|
+
patches: this.currentGroup,
|
|
2187
|
+
inversePatches: this.currentGroupInverse,
|
|
2188
|
+
timestamp: Date.now()
|
|
2189
|
+
});
|
|
2190
|
+
this.currentIndex++;
|
|
2191
|
+
if (this.historyEntries.length > this.options.maxHistoryLength) {
|
|
2192
|
+
const excess = this.historyEntries.length - this.options.maxHistoryLength;
|
|
2193
|
+
this.historyEntries.splice(0, excess);
|
|
2194
|
+
this.currentIndex -= excess;
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
this.currentGroup = [];
|
|
2198
|
+
this.currentGroupInverse = [];
|
|
2199
|
+
}
|
|
2200
|
+
withoutUndo(fn) {
|
|
2201
|
+
this.skipRecording = true;
|
|
2202
|
+
try {
|
|
2203
|
+
return fn();
|
|
2204
|
+
} finally {
|
|
2205
|
+
this.skipRecording = false;
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
dispose() {
|
|
2209
|
+
if (this.disposer) {
|
|
2210
|
+
this.disposer();
|
|
2211
|
+
this.disposer = null;
|
|
2212
|
+
}
|
|
2213
|
+
this.clear();
|
|
2214
|
+
}
|
|
2215
|
+
};
|
|
2216
|
+
function createUndoManager(target, options) {
|
|
2217
|
+
return new UndoManager(target, options);
|
|
2218
|
+
}
|
|
2219
|
+
var TimeTravelManager = class {
|
|
2220
|
+
constructor(target, options = {}) {
|
|
2221
|
+
this.snapshots = [];
|
|
2222
|
+
this.index = -1;
|
|
2223
|
+
this.isApplying = false;
|
|
2224
|
+
this.disposer = null;
|
|
2225
|
+
this.target = target;
|
|
2226
|
+
this.maxSnapshots = options.maxSnapshots ?? 50;
|
|
2227
|
+
this.autoRecord = options.autoRecord ?? false;
|
|
2228
|
+
this.record();
|
|
2229
|
+
if (this.autoRecord) {
|
|
2230
|
+
this.disposer = onPatch(target, () => {
|
|
2231
|
+
if (!this.isApplying) {
|
|
2232
|
+
this.record();
|
|
2233
|
+
}
|
|
2234
|
+
});
|
|
2235
|
+
}
|
|
2236
|
+
}
|
|
2237
|
+
get currentIndex() {
|
|
2238
|
+
return this.index;
|
|
2239
|
+
}
|
|
2240
|
+
get snapshotCount() {
|
|
2241
|
+
return this.snapshots.length;
|
|
2242
|
+
}
|
|
2243
|
+
get canGoBack() {
|
|
2244
|
+
return this.index > 0;
|
|
2245
|
+
}
|
|
2246
|
+
get canGoForward() {
|
|
2247
|
+
return this.index < this.snapshots.length - 1;
|
|
2248
|
+
}
|
|
2249
|
+
record() {
|
|
2250
|
+
if (this.index < this.snapshots.length - 1) {
|
|
2251
|
+
this.snapshots.splice(this.index + 1);
|
|
2252
|
+
}
|
|
2253
|
+
this.snapshots.push(getSnapshot(this.target));
|
|
2254
|
+
this.index++;
|
|
2255
|
+
if (this.snapshots.length > this.maxSnapshots) {
|
|
2256
|
+
const excess = this.snapshots.length - this.maxSnapshots;
|
|
2257
|
+
this.snapshots.splice(0, excess);
|
|
2258
|
+
this.index -= excess;
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
goBack() {
|
|
2262
|
+
if (!this.canGoBack) return;
|
|
2263
|
+
this.goTo(this.index - 1);
|
|
2264
|
+
}
|
|
2265
|
+
goForward() {
|
|
2266
|
+
if (!this.canGoForward) return;
|
|
2267
|
+
this.goTo(this.index + 1);
|
|
2268
|
+
}
|
|
2269
|
+
goTo(index) {
|
|
2270
|
+
if (index < 0 || index >= this.snapshots.length) return;
|
|
2271
|
+
this.isApplying = true;
|
|
2272
|
+
try {
|
|
2273
|
+
this.index = index;
|
|
2274
|
+
applySnapshot(this.target, this.snapshots[index]);
|
|
2275
|
+
} finally {
|
|
2276
|
+
this.isApplying = false;
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
getSnapshot(index) {
|
|
2280
|
+
if (index < 0 || index >= this.snapshots.length) {
|
|
2281
|
+
throw new Error(`[jotai-state-tree] Invalid snapshot index: ${index}`);
|
|
2282
|
+
}
|
|
2283
|
+
return this.snapshots[index];
|
|
2284
|
+
}
|
|
2285
|
+
clear() {
|
|
2286
|
+
this.snapshots = [];
|
|
2287
|
+
this.index = -1;
|
|
2288
|
+
this.record();
|
|
2289
|
+
}
|
|
2290
|
+
dispose() {
|
|
2291
|
+
if (this.disposer) {
|
|
2292
|
+
this.disposer();
|
|
2293
|
+
this.disposer = null;
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
2296
|
+
};
|
|
2297
|
+
function createTimeTravelManager(target, options) {
|
|
2298
|
+
return new TimeTravelManager(target, options);
|
|
2299
|
+
}
|
|
2300
|
+
var ActionRecorder = class {
|
|
2301
|
+
constructor(target) {
|
|
2302
|
+
this.recording = false;
|
|
2303
|
+
this.recordedActions = [];
|
|
2304
|
+
this.disposer = null;
|
|
2305
|
+
this.target = target;
|
|
2306
|
+
}
|
|
2307
|
+
get isRecording() {
|
|
2308
|
+
return this.recording;
|
|
2309
|
+
}
|
|
2310
|
+
get actions() {
|
|
2311
|
+
return [...this.recordedActions];
|
|
2312
|
+
}
|
|
2313
|
+
start() {
|
|
2314
|
+
if (this.recording) return;
|
|
2315
|
+
this.recording = true;
|
|
2316
|
+
const { onAction: onAction2 } = (init_tree(), __toCommonJS(tree_exports));
|
|
2317
|
+
this.disposer = onAction2(this.target, (action) => {
|
|
2318
|
+
this.recordedActions.push({
|
|
2319
|
+
...action,
|
|
2320
|
+
timestamp: Date.now()
|
|
2321
|
+
});
|
|
2322
|
+
});
|
|
2323
|
+
}
|
|
2324
|
+
stop() {
|
|
2325
|
+
this.recording = false;
|
|
2326
|
+
if (this.disposer) {
|
|
2327
|
+
this.disposer();
|
|
2328
|
+
this.disposer = null;
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
clear() {
|
|
2332
|
+
this.recordedActions = [];
|
|
2333
|
+
}
|
|
2334
|
+
replay(target) {
|
|
2335
|
+
const node = getStateTreeNode(target);
|
|
2336
|
+
for (const action of this.recordedActions) {
|
|
2337
|
+
let currentNode = node;
|
|
2338
|
+
if (action.path) {
|
|
2339
|
+
const parts = action.path.split("/").filter(Boolean);
|
|
2340
|
+
for (const part of parts) {
|
|
2341
|
+
const child = currentNode.getChild(part);
|
|
2342
|
+
if (!child) {
|
|
2343
|
+
console.warn(`[jotai-state-tree] Could not find path: ${action.path}`);
|
|
2344
|
+
continue;
|
|
2345
|
+
}
|
|
2346
|
+
currentNode = child;
|
|
2347
|
+
}
|
|
2348
|
+
}
|
|
2349
|
+
const instance = currentNode.getInstance();
|
|
2350
|
+
if (typeof instance[action.name] === "function") {
|
|
2351
|
+
instance[action.name](...action.args);
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
export() {
|
|
2356
|
+
return JSON.stringify(this.recordedActions, null, 2);
|
|
2357
|
+
}
|
|
2358
|
+
import(json) {
|
|
2359
|
+
try {
|
|
2360
|
+
const actions = JSON.parse(json);
|
|
2361
|
+
if (Array.isArray(actions)) {
|
|
2362
|
+
this.recordedActions = actions;
|
|
2363
|
+
}
|
|
2364
|
+
} catch (e) {
|
|
2365
|
+
throw new Error(`[jotai-state-tree] Failed to import actions: ${e}`);
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
2368
|
+
dispose() {
|
|
2369
|
+
this.stop();
|
|
2370
|
+
this.clear();
|
|
2371
|
+
}
|
|
2372
|
+
};
|
|
2373
|
+
function createActionRecorder(target) {
|
|
2374
|
+
return new ActionRecorder(target);
|
|
2375
|
+
}
|
|
2376
|
+
|
|
2377
|
+
// src/index.ts
|
|
2378
|
+
var types = {
|
|
2379
|
+
// Primitives
|
|
2380
|
+
string,
|
|
2381
|
+
number,
|
|
2382
|
+
integer,
|
|
2383
|
+
boolean,
|
|
2384
|
+
Date: DatePrimitive,
|
|
2385
|
+
null: nullType,
|
|
2386
|
+
undefined: undefinedType,
|
|
2387
|
+
finite,
|
|
2388
|
+
float,
|
|
2389
|
+
// Identifiers
|
|
2390
|
+
identifier,
|
|
2391
|
+
identifierNumber,
|
|
2392
|
+
// Literals & Enums
|
|
2393
|
+
literal,
|
|
2394
|
+
enumeration,
|
|
2395
|
+
// Frozen
|
|
2396
|
+
frozen,
|
|
2397
|
+
// Custom
|
|
2398
|
+
custom,
|
|
2399
|
+
// Model
|
|
2400
|
+
model,
|
|
2401
|
+
compose,
|
|
2402
|
+
// Collections
|
|
2403
|
+
array,
|
|
2404
|
+
map,
|
|
2405
|
+
// Optionality
|
|
2406
|
+
optional,
|
|
2407
|
+
maybe,
|
|
2408
|
+
maybeNull,
|
|
2409
|
+
// Union & Late
|
|
2410
|
+
union,
|
|
2411
|
+
late,
|
|
2412
|
+
// References
|
|
2413
|
+
reference,
|
|
2414
|
+
safeReference,
|
|
2415
|
+
// Refinement
|
|
2416
|
+
refinement,
|
|
2417
|
+
// Snapshot processing
|
|
2418
|
+
snapshotProcessor,
|
|
2419
|
+
// Registry-based types (for dynamic model registration)
|
|
2420
|
+
lateModel,
|
|
2421
|
+
dynamicReference,
|
|
2422
|
+
safeDynamicReference
|
|
2423
|
+
};
|
|
2424
|
+
function flow(generator) {
|
|
2425
|
+
return function flowAction(...args) {
|
|
2426
|
+
const gen = generator(...args);
|
|
2427
|
+
function step(nextFn) {
|
|
2428
|
+
let result;
|
|
2429
|
+
try {
|
|
2430
|
+
result = nextFn();
|
|
2431
|
+
} catch (e) {
|
|
2432
|
+
return Promise.reject(e);
|
|
2433
|
+
}
|
|
2434
|
+
if (result.done) {
|
|
2435
|
+
return Promise.resolve(result.value);
|
|
2436
|
+
}
|
|
2437
|
+
return Promise.resolve(result.value).then(
|
|
2438
|
+
(value) => step(() => gen.next(value)),
|
|
2439
|
+
(error) => step(() => gen.throw(error))
|
|
2440
|
+
);
|
|
2441
|
+
}
|
|
2442
|
+
return step(() => gen.next(void 0));
|
|
2443
|
+
};
|
|
2444
|
+
}
|
|
2445
|
+
function cast(value) {
|
|
2446
|
+
return value;
|
|
2447
|
+
}
|
|
2448
|
+
function castToSnapshot(value) {
|
|
2449
|
+
return value;
|
|
2450
|
+
}
|
|
2451
|
+
function castToReferenceSnapshot(value) {
|
|
2452
|
+
const { getIdentifier: getIdentifier2 } = (init_tree(), __toCommonJS(tree_exports));
|
|
2453
|
+
return getIdentifier2(value) ?? value;
|
|
2454
|
+
}
|
|
2455
|
+
function isIdentifierType(type) {
|
|
2456
|
+
return type !== null && typeof type === "object" && "_kind" in type && (type._kind === "identifier" || type._kind === "identifierNumber");
|
|
2457
|
+
}
|
|
2458
|
+
function isModelType(type) {
|
|
2459
|
+
return type !== null && typeof type === "object" && "_kind" in type && type._kind === "model";
|
|
2460
|
+
}
|
|
2461
|
+
function isArrayType(type) {
|
|
2462
|
+
return type !== null && typeof type === "object" && "_kind" in type && type._kind === "array";
|
|
2463
|
+
}
|
|
2464
|
+
function isMapType(type) {
|
|
2465
|
+
return type !== null && typeof type === "object" && "_kind" in type && type._kind === "map";
|
|
2466
|
+
}
|
|
2467
|
+
function isReferenceType(type) {
|
|
2468
|
+
return type !== null && typeof type === "object" && "_kind" in type && (type._kind === "reference" || type._kind === "safeReference");
|
|
2469
|
+
}
|
|
2470
|
+
function isUnionType(type) {
|
|
2471
|
+
return type !== null && typeof type === "object" && "_kind" in type && type._kind === "union";
|
|
2472
|
+
}
|
|
2473
|
+
function isOptionalType(type) {
|
|
2474
|
+
return type !== null && typeof type === "object" && "_kind" in type && (type._kind === "optional" || type._kind === "maybe" || type._kind === "maybeNull");
|
|
2475
|
+
}
|
|
2476
|
+
function isLateType(type) {
|
|
2477
|
+
return type !== null && typeof type === "object" && "_kind" in type && type._kind === "late";
|
|
2478
|
+
}
|
|
2479
|
+
function isFrozenType(type) {
|
|
2480
|
+
return type !== null && typeof type === "object" && "_kind" in type && type._kind === "frozen";
|
|
2481
|
+
}
|
|
2482
|
+
function isLiteralType(type) {
|
|
2483
|
+
return type !== null && typeof type === "object" && "_kind" in type && type._kind === "literal";
|
|
2484
|
+
}
|
|
2485
|
+
function typecheck(type, value) {
|
|
2486
|
+
if (!type.is(value)) {
|
|
2487
|
+
throw new Error(`[jotai-state-tree] Value does not match type`);
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2490
|
+
var index_default = types;
|
|
2491
|
+
export {
|
|
2492
|
+
DatePrimitive as Date,
|
|
2493
|
+
addMiddleware,
|
|
2494
|
+
applyAction,
|
|
2495
|
+
applyPatch,
|
|
2496
|
+
applySnapshot,
|
|
2497
|
+
array,
|
|
2498
|
+
boolean,
|
|
2499
|
+
cast,
|
|
2500
|
+
castToReferenceSnapshot,
|
|
2501
|
+
castToSnapshot,
|
|
2502
|
+
cleanupStaleEntries,
|
|
2503
|
+
clearAllRegistries,
|
|
2504
|
+
clearModelRegistry,
|
|
2505
|
+
clone,
|
|
2506
|
+
cloneDeep,
|
|
2507
|
+
cloneFrozen,
|
|
2508
|
+
compose,
|
|
2509
|
+
createActionRecorder,
|
|
2510
|
+
createTimeTravelManager,
|
|
2511
|
+
createUndoManager,
|
|
2512
|
+
createWithDefaults,
|
|
2513
|
+
custom,
|
|
2514
|
+
index_default as default,
|
|
2515
|
+
destroy,
|
|
2516
|
+
detach,
|
|
2517
|
+
dynamicReference,
|
|
2518
|
+
enumeration,
|
|
2519
|
+
escapeJsonPath,
|
|
2520
|
+
findAll,
|
|
2521
|
+
findFirst,
|
|
2522
|
+
finite,
|
|
2523
|
+
float,
|
|
2524
|
+
flow,
|
|
2525
|
+
freeze,
|
|
2526
|
+
frozen,
|
|
2527
|
+
getDebugInfo,
|
|
2528
|
+
getEnv,
|
|
2529
|
+
getGlobalStore,
|
|
2530
|
+
getIdentifier,
|
|
2531
|
+
getIdentifierAttribute,
|
|
2532
|
+
getMembers,
|
|
2533
|
+
getModelMetadata,
|
|
2534
|
+
getOrCreate,
|
|
2535
|
+
getOrCreatePath,
|
|
2536
|
+
getParent,
|
|
2537
|
+
getParentOfType,
|
|
2538
|
+
getPath,
|
|
2539
|
+
getPathParts,
|
|
2540
|
+
getRegisteredModelNames,
|
|
2541
|
+
getRegistryStats,
|
|
2542
|
+
getRelativePath,
|
|
2543
|
+
getRoot,
|
|
2544
|
+
getSnapshot,
|
|
2545
|
+
getTreeStats,
|
|
2546
|
+
getType,
|
|
2547
|
+
getTypeName,
|
|
2548
|
+
getValidationError,
|
|
2549
|
+
hasIdentifier,
|
|
2550
|
+
hasParent,
|
|
2551
|
+
haveSameRoot,
|
|
2552
|
+
identifier,
|
|
2553
|
+
identifierNumber,
|
|
2554
|
+
integer,
|
|
2555
|
+
isAlive,
|
|
2556
|
+
isAncestor,
|
|
2557
|
+
isArrayType,
|
|
2558
|
+
isFrozen,
|
|
2559
|
+
isFrozenType,
|
|
2560
|
+
isIdentifierType,
|
|
2561
|
+
isInstanceOf,
|
|
2562
|
+
isLateType,
|
|
2563
|
+
isLiteralType,
|
|
2564
|
+
isMapType,
|
|
2565
|
+
isModelRegistered,
|
|
2566
|
+
isModelType,
|
|
2567
|
+
isOptionalType,
|
|
2568
|
+
isPrimitiveType,
|
|
2569
|
+
isProtected,
|
|
2570
|
+
isReferenceType,
|
|
2571
|
+
isRoot,
|
|
2572
|
+
isStateTreeNode,
|
|
2573
|
+
isType,
|
|
2574
|
+
isUnionType,
|
|
2575
|
+
isValidReference,
|
|
2576
|
+
isValidSnapshot,
|
|
2577
|
+
joinJsonPath,
|
|
2578
|
+
late,
|
|
2579
|
+
lateModel,
|
|
2580
|
+
literal,
|
|
2581
|
+
map,
|
|
2582
|
+
maybe,
|
|
2583
|
+
maybeNull,
|
|
2584
|
+
model,
|
|
2585
|
+
nullType,
|
|
2586
|
+
nullable,
|
|
2587
|
+
number,
|
|
2588
|
+
onAction,
|
|
2589
|
+
onLifecycleChange,
|
|
2590
|
+
onModelRegistered,
|
|
2591
|
+
onPatch,
|
|
2592
|
+
onSnapshot,
|
|
2593
|
+
optional,
|
|
2594
|
+
printTree,
|
|
2595
|
+
protect,
|
|
2596
|
+
recordActions,
|
|
2597
|
+
recordPatches,
|
|
2598
|
+
reference,
|
|
2599
|
+
refinement,
|
|
2600
|
+
registerModel,
|
|
2601
|
+
resetGlobalStore,
|
|
2602
|
+
resolveIdentifier,
|
|
2603
|
+
resolveModel,
|
|
2604
|
+
resolveModelAsync,
|
|
2605
|
+
resolvePath,
|
|
2606
|
+
safeCreate,
|
|
2607
|
+
safeDynamicReference,
|
|
2608
|
+
safeReference,
|
|
2609
|
+
setGlobalStore,
|
|
2610
|
+
snapshotProcessor,
|
|
2611
|
+
splitJsonPath,
|
|
2612
|
+
string,
|
|
2613
|
+
tryGetParent,
|
|
2614
|
+
tryResolve,
|
|
2615
|
+
tryResolveModel,
|
|
2616
|
+
typecheck,
|
|
2617
|
+
types,
|
|
2618
|
+
undefinedType,
|
|
2619
|
+
unescapeJsonPath,
|
|
2620
|
+
unfreeze,
|
|
2621
|
+
union,
|
|
2622
|
+
unprotect,
|
|
2623
|
+
unregisterModel,
|
|
2624
|
+
walk
|
|
2625
|
+
};
|