@jbrowse/mobx-state-tree 6.3.0 → 6.4.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.
@@ -270,6 +270,8 @@ function unprotect(target) {
270
270
  * Returns true if the object is in protected mode, @see protect
271
271
  */
272
272
  function isProtected(target) {
273
+ // check all arguments
274
+ assertIsStateTreeNode(target, 1);
273
275
  return getStateTreeNode(target).isProtected;
274
276
  }
275
277
  /**
@@ -301,6 +303,27 @@ function getSnapshot(target, applyPostProcess = true) {
301
303
  }
302
304
  return freeze(node.type.getSnapshot(node, false));
303
305
  }
306
+ function findParentAtDepth(node, depth) {
307
+ let remaining = depth;
308
+ let parent = node.parent;
309
+ while (parent) {
310
+ if (--remaining === 0) {
311
+ return parent;
312
+ }
313
+ parent = parent.parent;
314
+ }
315
+ return null;
316
+ }
317
+ function findParentOfType(node, type) {
318
+ let parent = node.parent;
319
+ while (parent) {
320
+ if (type.is(parent.storedValue)) {
321
+ return parent;
322
+ }
323
+ parent = parent.parent;
324
+ }
325
+ return null;
326
+ }
304
327
  /**
305
328
  * Given a model instance, returns `true` if the object has a parent, that is, is part of another object, map or array.
306
329
  *
@@ -312,14 +335,7 @@ function hasParent(target, depth = 1) {
312
335
  // check all arguments
313
336
  assertIsStateTreeNode(target, 1);
314
337
  assertIsNumber(depth, 2, 0);
315
- let parent = getStateTreeNode(target).parent;
316
- while (parent) {
317
- if (--depth === 0) {
318
- return true;
319
- }
320
- parent = parent.parent;
321
- }
322
- return false;
338
+ return findParentAtDepth(getStateTreeNode(target), depth) !== null;
323
339
  }
324
340
  /**
325
341
  * Returns the immediate parent of this object, or throws.
@@ -338,15 +354,11 @@ function getParent(target, depth = 1) {
338
354
  // check all arguments
339
355
  assertIsStateTreeNode(target, 1);
340
356
  assertIsNumber(depth, 2, 0);
341
- let d = depth;
342
- let parent = getStateTreeNode(target).parent;
343
- while (parent) {
344
- if (--d === 0) {
345
- return parent.storedValue;
346
- }
347
- parent = parent.parent;
357
+ const parent = findParentAtDepth(getStateTreeNode(target), depth);
358
+ if (!parent) {
359
+ throw fail(`Failed to find the parent of ${getStateTreeNode(target)} at depth ${depth}`);
348
360
  }
349
- throw fail(`Failed to find the parent of ${getStateTreeNode(target)} at depth ${depth}`);
361
+ return parent.storedValue;
350
362
  }
351
363
  /**
352
364
  * Given a model instance, returns `true` if the object has a parent of given type, that is, is part of another object, map or array
@@ -359,14 +371,7 @@ function hasParentOfType(target, type) {
359
371
  // check all arguments
360
372
  assertIsStateTreeNode(target, 1);
361
373
  assertIsType(type, 2);
362
- let parent = getStateTreeNode(target).parent;
363
- while (parent) {
364
- if (type.is(parent.storedValue)) {
365
- return true;
366
- }
367
- parent = parent.parent;
368
- }
369
- return false;
374
+ return findParentOfType(getStateTreeNode(target), type) !== null;
370
375
  }
371
376
  /**
372
377
  * Returns the target's parent of a given type, or throws.
@@ -379,14 +384,11 @@ function getParentOfType(target, type) {
379
384
  // check all arguments
380
385
  assertIsStateTreeNode(target, 1);
381
386
  assertIsType(type, 2);
382
- let parent = getStateTreeNode(target).parent;
383
- while (parent) {
384
- if (type.is(parent.storedValue)) {
385
- return parent.storedValue;
386
- }
387
- parent = parent.parent;
387
+ const parent = findParentOfType(getStateTreeNode(target), type);
388
+ if (!parent) {
389
+ throw fail(`Failed to find the parent of ${getStateTreeNode(target)} of a given type`);
388
390
  }
389
- throw fail(`Failed to find the parent of ${getStateTreeNode(target)} of a given type`);
391
+ return parent.storedValue;
390
392
  }
391
393
  /**
392
394
  * Given an object in a model tree, returns the root object of that tree.
@@ -1195,11 +1197,11 @@ class ObjectNode extends BaseNode {
1195
1197
  this.identifier = normalizeIdentifier(id);
1196
1198
  this.unnormalizedIdentifier = id;
1197
1199
  }
1198
- if (!parent) {
1199
- this.identifierCache.addNodeToCache(this);
1200
- }
1201
- else {
1202
- parent.root.identifierCache.addNodeToCache(this);
1200
+ // addNodeToCache no-ops without an identifier attribute, and reaching the
1201
+ // root to ask it is a walk up the whole parent chain
1202
+ if (this.identifierAttribute) {
1203
+ const cache = parent ? parent.root.identifierCache : this.identifierCache;
1204
+ cache.addNodeToCache(this);
1203
1205
  }
1204
1206
  }
1205
1207
  createObservableInstanceIfNeeded(fireHooks = true) {
@@ -1347,15 +1349,9 @@ class ObjectNode extends BaseNode {
1347
1349
  typeof this.storedValue === "object" &&
1348
1350
  this.storedValue[name];
1349
1351
  if (typeof fn === "function") {
1350
- // we check for it to allow old mobx peer dependencies that don't have the method to work (even when still bugged)
1351
- if (_allowStateChangesInsideComputed) {
1352
- _allowStateChangesInsideComputed(() => {
1353
- fn.apply(this.storedValue);
1354
- });
1355
- }
1356
- else {
1352
+ _allowStateChangesInsideComputed(() => {
1357
1353
  fn.apply(this.storedValue);
1358
- }
1354
+ });
1359
1355
  }
1360
1356
  }
1361
1357
  _snapshotUponDeath;
@@ -1735,8 +1731,8 @@ var TypeFlags;
1735
1731
  TypeFlags[TypeFlags["Float"] = 4194304] = "Float";
1736
1732
  })(TypeFlags || (TypeFlags = {}));
1737
1733
  /**
1738
- * @internal
1739
- * @hidden
1734
+ * The value `getSubTypes()` returns when a type cannot report its subtype,
1735
+ * which is distinct from reporting that it has none (`null`).
1740
1736
  */
1741
1737
  const cannotDetermineSubtype = "cannotDetermine";
1742
1738
  /**
@@ -1788,6 +1784,9 @@ class BaseType {
1788
1784
  // istanbul ignore next
1789
1785
  throw fail("unimplemented method");
1790
1786
  }
1787
+ describe() {
1788
+ return this.name;
1789
+ }
1791
1790
  isAssignableFrom(type) {
1792
1791
  return type === this;
1793
1792
  }
@@ -1933,7 +1932,7 @@ class SimpleType extends BaseType {
1933
1932
  * @returns `true` if the value is a type.
1934
1933
  */
1935
1934
  function isType(value) {
1936
- return typeof value === "object" && value?.isType === true;
1935
+ return (typeof value === "object" && value?.isType === true);
1937
1936
  }
1938
1937
  /**
1939
1938
  * @internal
@@ -2668,10 +2667,6 @@ function safeStringify(value) {
2668
2667
  return `<Unserializable: ${e}>`;
2669
2668
  }
2670
2669
  }
2671
- /**
2672
- * @internal
2673
- * @hidden
2674
- */
2675
2670
  function prettyPrintValue(value) {
2676
2671
  return typeof value === "function"
2677
2672
  ? `<function${value.name ? ` ${value.name}` : ""}>`
@@ -2704,12 +2699,8 @@ function toErrorString(error) {
2704
2699
  expectation = ".";
2705
2700
  }
2706
2701
  else {
2707
- // `isPrimitiveType` is declared `(type: IT) => type is IT`, so its negative
2708
- // branch narrows to `never` rather than to "some non-primitive type"; the
2709
- // annotation restores the type it actually has here.
2710
- const complexType = type;
2711
- const isSnapshotCompatible = isStateTreeNode(value) && complexType.is(getStateTreeNode(value).snapshot);
2712
- expectation = `, expected an instance of \`${complexType.name}\` or a snapshot like \`${shortenPrintValue(complexType.describe())}\` instead.${isSnapshotCompatible
2702
+ const isSnapshotCompatible = isStateTreeNode(value) && type.is(getStateTreeNode(value).snapshot);
2703
+ expectation = `, expected an instance of \`${type.name}\` or a snapshot like \`${shortenPrintValue(type.describe())}\` instead.${isSnapshotCompatible
2713
2704
  ? " (Note that a snapshot of the provided value is compatible with the targeted type)"
2714
2705
  : ""}`;
2715
2706
  }
@@ -2990,7 +2981,7 @@ function getStateTreeNode(value) {
2990
2981
  * @hidden
2991
2982
  */
2992
2983
  function getStateTreeNodeSafe(value) {
2993
- return value?.$treenode || null;
2984
+ return value?.["$treenode"] || null;
2994
2985
  }
2995
2986
  /**
2996
2987
  * @internal
@@ -3302,9 +3293,6 @@ class EventHandler {
3302
3293
  this.handlers.splice(index, 1);
3303
3294
  }
3304
3295
  }
3305
- clear() {
3306
- this.handlers.length = 0;
3307
- }
3308
3296
  emit(...args) {
3309
3297
  const handlers = this.handlers;
3310
3298
  // 0 and 1 handlers are by far the common cases (a patch/snapshot listener, a
@@ -3449,21 +3437,6 @@ function assertIsString(value, argNumber, canBeEmpty = true) {
3449
3437
  assertArg(value, s => s !== "", "not empty string", argNumber);
3450
3438
  }
3451
3439
  }
3452
- /**
3453
- * @internal
3454
- * @hidden
3455
- */
3456
- function setImmediateWithFallback(fn) {
3457
- if (typeof queueMicrotask === "function") {
3458
- queueMicrotask(fn);
3459
- }
3460
- else if (typeof setImmediate === "function") {
3461
- setImmediate(fn);
3462
- }
3463
- else {
3464
- setTimeout(fn, 1);
3465
- }
3466
- }
3467
3440
 
3468
3441
  /**
3469
3442
  * See [asynchronous actions](concepts/async-actions.md).
@@ -3534,10 +3507,6 @@ function toGeneratorFunction(p) {
3534
3507
  function* toGenerator(p) {
3535
3508
  return (yield p);
3536
3509
  }
3537
- /**
3538
- * @internal
3539
- * @hidden
3540
- */
3541
3510
  function createFlowSpawner(name, generator) {
3542
3511
  const spawner = function flowSpawner(...flowArgs) {
3543
3512
  // Implementation based on https://github.com/tj/co/blob/master/index.js
@@ -3595,7 +3564,7 @@ function createFlowSpawner(name, generator) {
3595
3564
  }
3596
3565
  catch (e) {
3597
3566
  // prettier-ignore
3598
- setImmediateWithFallback(() => {
3567
+ queueMicrotask(() => {
3599
3568
  wrap((_r) => { reject(e); }, "flow_throw", e);
3600
3569
  });
3601
3570
  return;
@@ -3611,7 +3580,7 @@ function createFlowSpawner(name, generator) {
3611
3580
  }
3612
3581
  catch (e) {
3613
3582
  // prettier-ignore
3614
- setImmediateWithFallback(() => {
3583
+ queueMicrotask(() => {
3615
3584
  wrap((_r) => { reject(e); }, "flow_throw", e);
3616
3585
  });
3617
3586
  return;
@@ -3621,7 +3590,7 @@ function createFlowSpawner(name, generator) {
3621
3590
  function next(ret) {
3622
3591
  if (ret.done) {
3623
3592
  // prettier-ignore
3624
- setImmediateWithFallback(() => {
3593
+ queueMicrotask(() => {
3625
3594
  wrap((r) => { resolve(r); }, "flow_return", ret.value);
3626
3595
  });
3627
3596
  return;
@@ -3649,10 +3618,6 @@ function splitPatch(patch) {
3649
3618
  }
3650
3619
  return [stripPatch(patch), invertPatch(patch)];
3651
3620
  }
3652
- /**
3653
- * @internal
3654
- * @hidden
3655
- */
3656
3621
  function stripPatch(patch) {
3657
3622
  // strips `oldvalue` information from the patch, so that it becomes a patch conform the json-patch spec
3658
3623
  // this removes the ability to undo the patch
@@ -3999,13 +3964,6 @@ var MapIdentifierMode;
3999
3964
  MapIdentifierMode[MapIdentifierMode["NO"] = 2] = "NO";
4000
3965
  })(MapIdentifierMode || (MapIdentifierMode = {}));
4001
3966
  class MSTMap extends ObservableMap {
4002
- constructor(initialData, name) {
4003
- // mobx's default (deep) enhancer. The old `observable.ref.enhancer` arg
4004
- // read undefined ever since mobx 6 renamed the field to `options_.enhancer`,
4005
- // so deep has been the effective behavior all along; mobx 7 dropped
4006
- // `observable.ref` entirely.
4007
- super(initialData, undefined, name);
4008
- }
4009
3967
  get(key) {
4010
3968
  // maybe this is over-enthousiastic? normalize numeric keys to strings
4011
3969
  return super.get(`${key}`);
@@ -4118,7 +4076,8 @@ class MapType extends ComplexType {
4118
4076
  return result;
4119
4077
  }
4120
4078
  createNewInstance(childNodes) {
4121
- return new MSTMap(childNodes, this.name);
4079
+ // undefined is mobx's enhancer argument, left at its deep default
4080
+ return new MSTMap(childNodes, undefined, this.name);
4122
4081
  }
4123
4082
  finalizeNewInstance(node, instance) {
4124
4083
  _interceptReads(instance, node.unbox);
@@ -4126,9 +4085,6 @@ class MapType extends ComplexType {
4126
4085
  intercept(instance, this.willChange);
4127
4086
  observe(instance, this.didChange);
4128
4087
  }
4129
- describe() {
4130
- return this.name;
4131
- }
4132
4088
  getChildren(node) {
4133
4089
  // return (node.storedValue as ObservableMap<any>).values()
4134
4090
  return values(node.storedValue);
@@ -4305,6 +4261,7 @@ MapType.prototype.applySnapshot = action(MapType.prototype.applySnapshot);
4305
4261
  * @returns
4306
4262
  */
4307
4263
  function map(subtype) {
4264
+ assertIsType(subtype, 1);
4308
4265
  return new MapType(subtype);
4309
4266
  }
4310
4267
  /**
@@ -4358,9 +4315,6 @@ class ArrayType extends ComplexType {
4358
4315
  intercept(instance, this.willChange);
4359
4316
  observe(instance, this.didChange);
4360
4317
  }
4361
- describe() {
4362
- return this.name;
4363
- }
4364
4318
  getChildren(node) {
4365
4319
  return node.storedValue.slice();
4366
4320
  }
@@ -4732,8 +4686,8 @@ function objectTypeToString() {
4732
4686
  }
4733
4687
  const ANONYMOUS_MODEL_NAME = "AnonymousModel";
4734
4688
  /**
4735
- * A plain loop rather than `forAllProps`, which allocated a closure and made an
4736
- * indirect call per property. This runs once per `types.model()` over every
4689
+ * A plain loop rather than a callback per property, which allocated a closure
4690
+ * and made an indirect call. This runs once per `types.model()` over every
4737
4691
  * declared property, and jbrowse builds a ~40-slot schema per track.
4738
4692
  */
4739
4693
  function findIdentifierAttribute(properties, propertyNames) {
@@ -4931,12 +4885,6 @@ class ModelType extends ComplexType {
4931
4885
  (!devMode() ? addHiddenFinalProp : addHiddenWritableProp)(self, name, actionInvoker);
4932
4886
  });
4933
4887
  }
4934
- named = name => {
4935
- return this.cloneAndEnhance({ name });
4936
- };
4937
- props = properties => {
4938
- return this.cloneAndEnhance({ properties });
4939
- };
4940
4888
  volatile(fn) {
4941
4889
  if (typeof fn !== "function") {
4942
4890
  throw fail(`You passed an ${typeof fn} to volatile state as an argument, when function is expected`);
@@ -5019,28 +4967,6 @@ class ModelType extends ComplexType {
5019
4967
  }
5020
4968
  });
5021
4969
  }
5022
- preProcessSnapshot = preProcessor => {
5023
- const currentPreprocessor = this.preProcessor;
5024
- if (!currentPreprocessor) {
5025
- return this.cloneAndEnhance({ preProcessor });
5026
- }
5027
- else {
5028
- return this.cloneAndEnhance({
5029
- preProcessor: snapshot => currentPreprocessor(preProcessor(snapshot))
5030
- });
5031
- }
5032
- };
5033
- postProcessSnapshot = postProcessor => {
5034
- const currentPostprocessor = this.postProcessor;
5035
- if (!currentPostprocessor) {
5036
- return this.cloneAndEnhance({ postProcessor });
5037
- }
5038
- else {
5039
- return this.cloneAndEnhance({
5040
- postProcessor: snapshot => postProcessor(currentPostprocessor(snapshot))
5041
- });
5042
- }
5043
- };
5044
4970
  instantiate(parent, subpath, environment, initialValue) {
5045
4971
  const value = isStateTreeNode(initialValue)
5046
4972
  ? initialValue
@@ -5051,10 +4977,11 @@ class ModelType extends ComplexType {
5051
4977
  }
5052
4978
  initializeChildNodes(objNode, initialSnapshot = {}) {
5053
4979
  const type = objNode.type;
4980
+ const properties = type.properties;
5054
4981
  const result = {};
5055
- type.forAllProps((name, childType) => {
5056
- result[name] = childType.instantiate(objNode, name, undefined, initialSnapshot[name]);
5057
- });
4982
+ for (const name of type.propertyNames) {
4983
+ result[name] = properties[name].instantiate(objNode, name, undefined, initialSnapshot[name]);
4984
+ }
5058
4985
  return result;
5059
4986
  }
5060
4987
  createNewInstance(childNodes) {
@@ -5073,9 +5000,9 @@ class ModelType extends ComplexType {
5073
5000
  }
5074
5001
  }
5075
5002
  else {
5076
- this.forAllProps(name => {
5003
+ for (const name of this.propertyNames) {
5077
5004
  _interceptReads(instance, name, node.unbox);
5078
- });
5005
+ }
5079
5006
  }
5080
5007
  this.initializers.reduce((self, fn) => fn(self), instance);
5081
5008
  // views, actions and volatile share the instance namespace with properties,
@@ -5086,12 +5013,12 @@ class ModelType extends ComplexType {
5086
5013
  // function/value stops being observable at all. The flag is only set on
5087
5014
  // success so a broken type keeps throwing on every create.
5088
5015
  if (!this.duplicateKeysChecked) {
5089
- this.forAllProps(name => {
5016
+ for (const name of this.propertyNames) {
5090
5017
  if (isComputedProp(instance, name) ||
5091
5018
  !isObservableProp(instance, name)) {
5092
5019
  throw fail(`${name} property is declared twice`);
5093
5020
  }
5094
- });
5021
+ }
5095
5022
  this.duplicateKeysChecked = true;
5096
5023
  }
5097
5024
  intercept(instance, this.willChange);
@@ -5144,24 +5071,16 @@ class ModelType extends ComplexType {
5144
5071
  }
5145
5072
  return res;
5146
5073
  }
5147
- /**
5148
- * Same as {@link getChildNode} but for a key already known to be a declared
5149
- * property (callers iterating `propertyNames`), so the membership guard is
5150
- * skipped.
5151
- */
5152
- getPropertyNode(node, key) {
5074
+ getChildNode(node, key) {
5075
+ if (!(key in this.properties)) {
5076
+ throw fail(`Not a value property: ${key}`);
5077
+ }
5153
5078
  const childNode = getPropObservable(node.storedValue, key).raw();
5154
5079
  if (!childNode) {
5155
5080
  throw fail(`Node not available for property ${key}`);
5156
5081
  }
5157
5082
  return childNode;
5158
5083
  }
5159
- getChildNode(node, key) {
5160
- if (!(key in this.properties)) {
5161
- throw fail(`Not a value property: ${key}`);
5162
- }
5163
- return this.getPropertyNode(node, key);
5164
- }
5165
5084
  getSnapshot(node, applyPostProcess = true) {
5166
5085
  const res = {};
5167
5086
  const storedValue = node.storedValue;
@@ -5213,9 +5132,9 @@ class ModelType extends ComplexType {
5213
5132
  applySnapshot(node, snapshot) {
5214
5133
  typecheckInternal(this, snapshot);
5215
5134
  const preProcessedSnapshot = this.applySnapshotPreProcessor(snapshot);
5216
- this.forAllProps(name => {
5135
+ for (const name of this.propertyNames) {
5217
5136
  node.storedValue[name] = preProcessedSnapshot[name];
5218
- });
5137
+ }
5219
5138
  }
5220
5139
  applySnapshotPreProcessor(snapshot) {
5221
5140
  const processor = this.preProcessor;
@@ -5248,12 +5167,6 @@ class ModelType extends ComplexType {
5248
5167
  }
5249
5168
  return typeCheckSuccess();
5250
5169
  }
5251
- forAllProps(fn) {
5252
- const properties = this.properties;
5253
- for (const key of this.propertyNames) {
5254
- fn(key, properties[key]);
5255
- }
5256
- }
5257
5170
  describe() {
5258
5171
  // optimization: cache
5259
5172
  return `{ ${this.propertyNames
@@ -5268,6 +5181,38 @@ class ModelType extends ComplexType {
5268
5181
  }
5269
5182
  }
5270
5183
  ModelType.prototype.applySnapshot = action(ModelType.prototype.applySnapshot);
5184
+ // Chain steps shared by every model type; see the field declarations in the
5185
+ // class for why they are not own slots.
5186
+ Object.assign(ModelType.prototype, {
5187
+ named(name) {
5188
+ return this.cloneAndEnhance({ name });
5189
+ },
5190
+ props(properties) {
5191
+ return this.cloneAndEnhance({ properties });
5192
+ },
5193
+ preProcessSnapshot(preProcessor) {
5194
+ const currentPreprocessor = this.preProcessor;
5195
+ if (!currentPreprocessor) {
5196
+ return this.cloneAndEnhance({ preProcessor });
5197
+ }
5198
+ else {
5199
+ return this.cloneAndEnhance({
5200
+ preProcessor: snapshot => currentPreprocessor(preProcessor(snapshot))
5201
+ });
5202
+ }
5203
+ },
5204
+ postProcessSnapshot(postProcessor) {
5205
+ const currentPostprocessor = this.postProcessor;
5206
+ if (!currentPostprocessor) {
5207
+ return this.cloneAndEnhance({ postProcessor });
5208
+ }
5209
+ else {
5210
+ return this.cloneAndEnhance({
5211
+ postProcessor: snapshot => postProcessor(currentPostprocessor(snapshot))
5212
+ });
5213
+ }
5214
+ }
5215
+ });
5271
5216
  /**
5272
5217
  * `types.model` - Creates a new model type by providing a name, properties, volatile state and actions.
5273
5218
  *
@@ -5378,9 +5323,6 @@ class CoreType extends SimpleType {
5378
5323
  this.checker = checker;
5379
5324
  this.initializer = initializer;
5380
5325
  }
5381
- describe() {
5382
- return this.name;
5383
- }
5384
5326
  instantiate(parent, subpath, environment, initialValue) {
5385
5327
  return createScalarNode(this, parent, subpath, environment, initialValue);
5386
5328
  }
@@ -5547,15 +5489,15 @@ class Literal extends SimpleType {
5547
5489
  value;
5548
5490
  flags = TypeFlags.Literal;
5549
5491
  constructor(value) {
5550
- super(JSON.stringify(value));
5492
+ super();
5551
5493
  this.value = value;
5552
5494
  }
5495
+ computeName() {
5496
+ return JSON.stringify(this.value);
5497
+ }
5553
5498
  instantiate(parent, subpath, environment, initialValue) {
5554
5499
  return createScalarNode(this, parent, subpath, environment, initialValue);
5555
5500
  }
5556
- describe() {
5557
- return JSON.stringify(this.value);
5558
- }
5559
5501
  isValidSnapshot(value, context) {
5560
5502
  if (isPrimitive(value) && value === this.value) {
5561
5503
  return typeCheckSuccess();
@@ -5613,9 +5555,6 @@ class Refinement extends BaseType {
5613
5555
  this._predicate = _predicate;
5614
5556
  this._message = _message;
5615
5557
  }
5616
- describe() {
5617
- return this.name;
5618
- }
5619
5558
  instantiate(parent, subpath, environment, initialValue) {
5620
5559
  // create the child type
5621
5560
  return this._subtype.instantiate(parent, subpath, environment, initialValue);
@@ -5747,6 +5686,16 @@ function resolveModelType(type) {
5747
5686
  }
5748
5687
  return undefined;
5749
5688
  }
5689
+ // The quick-match paths below already know a type carries TypeFlags.Literal,
5690
+ // but `is()` still routes through BaseType.validate — a context array, an entry
5691
+ // object and a `$treenode` probe per property, per candidate member. A real
5692
+ // `Literal` stores its primitive, and its isValidSnapshot is exactly value
5693
+ // equality against it, so compare directly. The `instanceof` gate is load
5694
+ // bearing: wrappers (optional, refinement, snapshotProcessor, late, union)
5695
+ // inherit the Literal flag from what they wrap and must keep the full check.
5696
+ function matchesLiteral(type, value) {
5697
+ return type instanceof Literal ? type.value === value : type.is(value);
5698
+ }
5750
5699
  /**
5751
5700
  * @internal
5752
5701
  * @hidden
@@ -5864,10 +5813,10 @@ class Union extends BaseType {
5864
5813
  if (!model) {
5865
5814
  continue;
5866
5815
  }
5867
- const typeProp = model.properties.type;
5816
+ const typeProp = model.properties["type"];
5868
5817
  if (!typeProp ||
5869
5818
  !(typeProp.flags & TypeFlags.Literal) ||
5870
- !typeProp.is(discriminator)) {
5819
+ !matchesLiteral(typeProp, discriminator)) {
5871
5820
  continue;
5872
5821
  }
5873
5822
  if (found) {
@@ -5887,7 +5836,7 @@ class Union extends BaseType {
5887
5836
  this._allMembersDiscriminated = this._types.every(t => {
5888
5837
  const model = resolveModelType(t);
5889
5838
  const typeProp = model &&
5890
- model.properties.type;
5839
+ model.properties["type"];
5891
5840
  return !!typeProp && (typeProp.flags & TypeFlags.Literal) !== 0;
5892
5841
  });
5893
5842
  }
@@ -5961,7 +5910,7 @@ class Union extends BaseType {
5961
5910
  }
5962
5911
  // for literals, check exact value match
5963
5912
  if (flags & TypeFlags.Literal) {
5964
- if (type.is(value)) {
5913
+ if (matchesLiteral(type, value)) {
5965
5914
  return type;
5966
5915
  }
5967
5916
  }
@@ -5993,7 +5942,7 @@ class Union extends BaseType {
5993
5942
  // for literal types, verify the value matches exactly
5994
5943
  // this is critical for discriminated unions
5995
5944
  if (flags & TypeFlags.Literal) {
5996
- if (!propType.is(propValue)) {
5945
+ if (!matchesLiteral(propType, propValue)) {
5997
5946
  return false;
5998
5947
  }
5999
5948
  }
@@ -6069,6 +6018,22 @@ Object.assign(Union.prototype, {
6069
6018
  _discriminatorCache: undefined,
6070
6019
  _allMembersDiscriminated: undefined
6071
6020
  });
6021
+ const unionInternRoot = {};
6022
+ function internUnion(types) {
6023
+ let node = unionInternRoot;
6024
+ for (const type of types) {
6025
+ const level = (node.next ??= new WeakMap());
6026
+ const existing = level.get(type);
6027
+ if (existing) {
6028
+ node = existing;
6029
+ }
6030
+ else {
6031
+ node = {};
6032
+ level.set(type, node);
6033
+ }
6034
+ }
6035
+ return (node.union ??= new Union(types));
6036
+ }
6072
6037
  /**
6073
6038
  * `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`.
6074
6039
  *
@@ -6097,7 +6062,7 @@ function union(...args) {
6097
6062
  assertIsType(type, options ? i + 2 : i + 1);
6098
6063
  });
6099
6064
  }
6100
- return new Union(types, options);
6065
+ return options === undefined ? internUnion(types) : new Union(types, options);
6101
6066
  }
6102
6067
  /**
6103
6068
  * Returns if a given value represents a union type.
@@ -6292,13 +6257,35 @@ const undefinedAsOptionalValues = [undefined];
6292
6257
  * to compile. Guards with a distinct narrowing target (`isArrayType`,
6293
6258
  * `isMapType`, `isModelType`) keep their predicate.
6294
6259
  *
6295
- * @template IT
6296
6260
  * @param type
6297
6261
  * @returns
6298
6262
  */
6299
6263
  function isOptionalType(type) {
6300
6264
  return isType(type) && (type.flags & TypeFlags.Optional) > 0;
6301
6265
  }
6266
+ function isRecord(value) {
6267
+ return typeof value === "object" && value !== null;
6268
+ }
6269
+ /**
6270
+ * The identifier attribute of the model a stripDefault ultimately wraps, or
6271
+ * `null` when there is none. Drills through the single-subtype wrappers the way
6272
+ * `resolveModelType` in union.ts does — that one is module-private there, and
6273
+ * this file may not reach into it.
6274
+ *
6275
+ * `null` is also the answer for an unresolved `types.late`, which only costs the
6276
+ * short-circuit, never correctness: the full structural walk still runs.
6277
+ */
6278
+ function resolveIdentifierAttribute(type) {
6279
+ let current = type;
6280
+ for (let depth = 0; current && depth < 20; depth++) {
6281
+ if (current instanceof ModelType) {
6282
+ return current.identifierAttribute ? current.identifierAttribute : null;
6283
+ }
6284
+ const wrapper = current;
6285
+ current = wrapper._subtype ?? wrapper.getSubType?.(false);
6286
+ }
6287
+ return null;
6288
+ }
6302
6289
  /**
6303
6290
  * Compare a child snapshot to a stripped-default's reference snapshot: identity
6304
6291
  * for primitives, structural for objects/arrays.
@@ -6377,6 +6364,22 @@ function defaultSnapshotEquals(a, b) {
6377
6364
  * @internal
6378
6365
  */
6379
6366
  class StripDefaultValue extends OptionalValue {
6367
+ equalsDefault(snapshot, defaultSnapshot) {
6368
+ let identifierAttribute = this._identifierAttribute;
6369
+ if (identifierAttribute === undefined) {
6370
+ identifierAttribute = resolveIdentifierAttribute(this.getSubTypes());
6371
+ this._identifierAttribute = identifierAttribute;
6372
+ }
6373
+ // an identified model's snapshot normally has the same shape as the default
6374
+ // and differs only here, so answering from one key beats walking every key
6375
+ // (including nested objects) until the walk reaches it
6376
+ return identifierAttribute !== null &&
6377
+ isRecord(snapshot) &&
6378
+ isRecord(defaultSnapshot) &&
6379
+ snapshot[identifierAttribute] !== defaultSnapshot[identifierAttribute]
6380
+ ? false
6381
+ : defaultSnapshotEquals(snapshot, defaultSnapshot);
6382
+ }
6380
6383
  shouldStripFromSnapshot(snapshot) {
6381
6384
  if (!this._defaultSnapshot) {
6382
6385
  // instantiate the subtype detached with the default and read the node's
@@ -6385,11 +6388,35 @@ class StripDefaultValue extends OptionalValue {
6385
6388
  const node = this.getSubTypes().instantiate(null, "", undefined, this.getDefaultInstanceOrSnapshot());
6386
6389
  this._defaultSnapshot = { value: node.snapshot };
6387
6390
  }
6388
- return defaultSnapshotEquals(snapshot, this._defaultSnapshot.value);
6391
+ const defaultSnapshot = this._defaultSnapshot.value;
6392
+ let result;
6393
+ if (isRecord(snapshot)) {
6394
+ // a child node's snapshot is a keepAlive computed, so a stable reference
6395
+ // means unchanged content: the same object always gets the same answer
6396
+ let cache = this._equalsDefaultCache;
6397
+ if (!cache) {
6398
+ cache = new WeakMap();
6399
+ this._equalsDefaultCache = cache;
6400
+ }
6401
+ const cached = cache.get(snapshot);
6402
+ if (cached === undefined) {
6403
+ result = this.equalsDefault(snapshot, defaultSnapshot);
6404
+ cache.set(snapshot, result);
6405
+ }
6406
+ else {
6407
+ result = cached;
6408
+ }
6409
+ }
6410
+ else {
6411
+ result = defaultSnapshotEquals(snapshot, defaultSnapshot);
6412
+ }
6413
+ return result;
6389
6414
  }
6390
6415
  }
6391
6416
  Object.assign(StripDefaultValue.prototype, {
6392
- _defaultSnapshot: undefined
6417
+ _defaultSnapshot: undefined,
6418
+ _identifierAttribute: undefined,
6419
+ _equalsDefaultCache: undefined
6393
6420
  });
6394
6421
  /**
6395
6422
  * Whether `type` is a strip-default optional whose current child `snapshot`
@@ -6808,9 +6835,6 @@ class BaseReferenceType extends SimpleType {
6808
6835
  computeName() {
6809
6836
  return `reference(${this.targetType.name})`;
6810
6837
  }
6811
- describe() {
6812
- return this.name;
6813
- }
6814
6838
  isAssignableFrom(type) {
6815
6839
  return this.targetType.isAssignableFrom(type);
6816
6840
  }
@@ -7147,9 +7171,6 @@ class IdentifierType extends BaseIdentifierType {
7147
7171
  constructor() {
7148
7172
  super(`identifier`, "string");
7149
7173
  }
7150
- describe() {
7151
- return `identifier`;
7152
- }
7153
7174
  }
7154
7175
  /**
7155
7176
  * @internal
@@ -7159,12 +7180,6 @@ class IdentifierNumberType extends BaseIdentifierType {
7159
7180
  constructor() {
7160
7181
  super("identifierNumber", "number");
7161
7182
  }
7162
- getSnapshot(node) {
7163
- return node.storedValue;
7164
- }
7165
- describe() {
7166
- return `identifierNumber`;
7167
- }
7168
7183
  }
7169
7184
  /**
7170
7185
  * `types.identifier` - Identifiers are used to make references, lifecycle events and reconciling works.
@@ -7295,9 +7310,6 @@ class CustomType extends SimpleType {
7295
7310
  super(options.name);
7296
7311
  this.options = options;
7297
7312
  }
7298
- describe() {
7299
- return this.name;
7300
- }
7301
7313
  isValidSnapshot(value, context) {
7302
7314
  if (this.options.isTargetType(value)) {
7303
7315
  return typeCheckSuccess();
@@ -7501,5 +7513,5 @@ const types = {
7501
7513
  resilient
7502
7514
  };
7503
7515
 
7504
- export { addDisposer, addMiddleware, applyAction, applyPatch, applySnapshot, cast, castFlowReturn, castToReferenceSnapshot, castToSnapshot, clone, createActionTrackingMiddleware, createActionTrackingMiddleware2, decorate, destroy, detach, escapeJsonPath, extendInstance, flow, getChildType, getEnv, getIdentifier, getLivelinessChecking, getMembers, getNodeId, getParent, getParentOfType, getPath, getPathParts, getPropertyMembers, getRelativePath, getRoot, getRunningActionContext, getSnapshot, getType, getUnionSubtypes, hasParent, hasParentOfType, isActionContextChildOf, isActionContextThisOrChildOf, isAlive, isArrayType, isFrozenType, isIdentifierType, isLateType, isLiteralType, isMapType, isModelType, isOptionalType, isPrimitiveType, isProtected, isReferenceType, isRefinementType, isRoot, isStateTreeNode, isType, isUnionType, isValidReference, joinJsonPath, onAction, onPatch, onSnapshot, protect, recordActions, recordPatches, resolveIdentifier, resolvePath, setDevMode, setLivelinessChecking, setLivelynessChecking, setTypeChecking, splitJsonPath, types as t, toGenerator, toGeneratorFunction, tryReference, tryResolve, typecheck, types, unescapeJsonPath, unprotect, walk };
7516
+ export { addDisposer, addMiddleware, applyAction, applyPatch, applySnapshot, cannotDetermineSubtype, cast, castFlowReturn, castToReferenceSnapshot, castToSnapshot, clone, createActionTrackingMiddleware, createActionTrackingMiddleware2, decorate, destroy, detach, escapeJsonPath, extendInstance, flow, getChildType, getEnv, getIdentifier, getLivelinessChecking, getMembers, getNodeId, getParent, getParentOfType, getPath, getPathParts, getPropertyMembers, getRelativePath, getRoot, getRunningActionContext, getSnapshot, getType, getUnionSubtypes, hasParent, hasParentOfType, isActionContextChildOf, isActionContextThisOrChildOf, isAlive, isArrayType, isFrozenType, isIdentifierType, isLateType, isLiteralType, isMapType, isModelType, isOptionalType, isPrimitiveType, isProtected, isReferenceType, isRefinementType, isRoot, isStateTreeNode, isType, isUnionType, isValidReference, joinJsonPath, onAction, onPatch, onSnapshot, protect, recordActions, recordPatches, resolveIdentifier, resolvePath, setDevMode, setLivelinessChecking, setLivelynessChecking, setTypeChecking, splitJsonPath, types as t, toGenerator, toGeneratorFunction, tryReference, tryResolve, typecheck, types, unescapeJsonPath, unprotect, walk };
7505
7517
  //# sourceMappingURL=mobx-state-tree.mjs.map