@jbrowse/mobx-state-tree 6.2.0 → 6.3.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/dist/index.d.ts CHANGED
@@ -1800,10 +1800,16 @@ declare const DatePrimitive: IType<number | Date, number, Date>;
1800
1800
  /**
1801
1801
  * Returns if a given value represents a primitive type.
1802
1802
  *
1803
+ * Returns a plain `boolean`, not a `type is IT` predicate: with the parameter
1804
+ * typed as `IT`, narrowing to `IT` was a no-op in the positive branch while
1805
+ * collapsing the negative one to `never`, so `if (!isX(t)) { t.name }` failed
1806
+ * to compile. Guards with a distinct narrowing target (`isArrayType`,
1807
+ * `isMapType`, `isModelType`) keep their predicate.
1808
+ *
1803
1809
  * @param type
1804
1810
  * @returns
1805
1811
  */
1806
- declare function isPrimitiveType<IT extends ISimpleType<string> | ISimpleType<number> | ISimpleType<boolean> | typeof DatePrimitive>(type: IT): type is IT;
1812
+ declare function isPrimitiveType<IT extends ISimpleType<string> | ISimpleType<number> | ISimpleType<boolean> | typeof DatePrimitive>(type: IT): boolean;
1807
1813
 
1808
1814
  /**
1809
1815
  * `types.literal` - The literal type will return a type that will match only the exact given type.
@@ -1825,20 +1831,32 @@ declare function literal<S extends Primitives>(value: S): ISimpleType<S>;
1825
1831
  /**
1826
1832
  * Returns if a given value represents a literal type.
1827
1833
  *
1834
+ * Returns a plain `boolean`, not a `type is IT` predicate: with the parameter
1835
+ * typed as `IT`, narrowing to `IT` was a no-op in the positive branch while
1836
+ * collapsing the negative one to `never`, so `if (!isX(t)) { t.name }` failed
1837
+ * to compile. Guards with a distinct narrowing target (`isArrayType`,
1838
+ * `isMapType`, `isModelType`) keep their predicate.
1839
+ *
1828
1840
  * @param type
1829
1841
  * @returns
1830
1842
  */
1831
- declare function isLiteralType<IT extends ISimpleType<any>>(type: IT): type is IT;
1843
+ declare function isLiteralType<IT extends ISimpleType<any>>(type: IT): boolean;
1832
1844
 
1833
1845
  declare function refinement<IT extends IAnyType>(name: string, type: IT, predicate: (snapshot: IT["CreationType"]) => boolean, message?: string | ((v: IT["CreationType"]) => string)): IT;
1834
1846
  declare function refinement<IT extends IAnyType>(type: IT, predicate: (snapshot: IT["CreationType"]) => boolean, message?: string | ((v: IT["CreationType"]) => string)): IT;
1835
1847
  /**
1836
1848
  * Returns if a given value is a refinement type.
1837
1849
  *
1850
+ * Returns a plain `boolean`, not a `type is IT` predicate: with the parameter
1851
+ * typed as `IT`, narrowing to `IT` was a no-op in the positive branch while
1852
+ * collapsing the negative one to `never`, so `if (!isX(t)) { t.name }` failed
1853
+ * to compile. Guards with a distinct narrowing target (`isArrayType`,
1854
+ * `isMapType`, `isModelType`) keep their predicate.
1855
+ *
1838
1856
  * @param type
1839
1857
  * @returns
1840
1858
  */
1841
- declare function isRefinementType<IT extends IAnyType>(type: IT): type is IT;
1859
+ declare function isRefinementType<IT extends IAnyType>(type: IT): boolean;
1842
1860
 
1843
1861
  /** @hidden */
1844
1862
  type UnionStringArray<T extends readonly string[]> = T[number];
@@ -1895,10 +1913,16 @@ declare function union(dispatchOrType: UnionOptions | IAnyType, ...otherTypes: I
1895
1913
  /**
1896
1914
  * Returns if a given value represents a union type.
1897
1915
  *
1916
+ * Returns a plain `boolean`, not a `type is IT` predicate: with the parameter
1917
+ * typed as `IT`, narrowing to `IT` was a no-op in the positive branch while
1918
+ * collapsing the negative one to `never`, so `if (!isX(t)) { t.name }` failed
1919
+ * to compile. Guards with a distinct narrowing target (`isArrayType`,
1920
+ * `isMapType`, `isModelType`) keep their predicate.
1921
+ *
1898
1922
  * @param type
1899
1923
  * @returns
1900
1924
  */
1901
- declare function isUnionType<IT extends IAnyType>(type: IT): type is IT;
1925
+ declare function isUnionType<IT extends IAnyType>(type: IT): boolean;
1902
1926
  /**
1903
1927
  * Returns the member types of a union.
1904
1928
  *
@@ -1928,11 +1952,17 @@ declare function optional<IT extends IAnyType, OptionalVals extends ValidOptiona
1928
1952
  /**
1929
1953
  * Returns if a value represents an optional type.
1930
1954
  *
1955
+ * Returns a plain `boolean`, not a `type is IT` predicate: with the parameter
1956
+ * typed as `IT`, narrowing to `IT` was a no-op in the positive branch while
1957
+ * collapsing the negative one to `never`, so `if (!isX(t)) { t.name }` failed
1958
+ * to compile. Guards with a distinct narrowing target (`isArrayType`,
1959
+ * `isMapType`, `isModelType`) keep their predicate.
1960
+ *
1931
1961
  * @template IT
1932
1962
  * @param type
1933
1963
  * @returns
1934
1964
  */
1935
- declare function isOptionalType<IT extends IAnyType>(type: IT): type is IT;
1965
+ declare function isOptionalType<IT extends IAnyType>(type: IT): boolean;
1936
1966
  /**
1937
1967
  * `types.stripDefault` - Like `types.optional`, but the property is omitted from
1938
1968
  * a parent model's snapshot entirely when its value equals the default (instead
@@ -1976,10 +2006,16 @@ declare function late<T extends IAnyType>(name: string, type: () => T): T;
1976
2006
  /**
1977
2007
  * Returns if a given value represents a late type.
1978
2008
  *
2009
+ * Returns a plain `boolean`, not a `type is IT` predicate: with the parameter
2010
+ * typed as `IT`, narrowing to `IT` was a no-op in the positive branch while
2011
+ * collapsing the negative one to `never`, so `if (!isX(t)) { t.name }` failed
2012
+ * to compile. Guards with a distinct narrowing target (`isArrayType`,
2013
+ * `isMapType`, `isModelType`) keep their predicate.
2014
+ *
1979
2015
  * @param type
1980
2016
  * @returns
1981
2017
  */
1982
- declare function isLateType<IT extends IAnyType>(type: IT): type is IT;
2018
+ declare function isLateType<IT extends IAnyType>(type: IT): boolean;
1983
2019
 
1984
2020
  interface LazyOptions<T extends IType<any, any, any>, U> {
1985
2021
  loadType: () => Promise<T>;
@@ -1993,10 +2029,16 @@ declare function frozen<T = any>(): IType<T, T, T>;
1993
2029
  /**
1994
2030
  * Returns if a given value represents a frozen type.
1995
2031
  *
2032
+ * Returns a plain `boolean`, not a `type is IT` predicate: with the parameter
2033
+ * typed as `IT`, narrowing to `IT` was a no-op in the positive branch while
2034
+ * collapsing the negative one to `never`, so `if (!isX(t)) { t.name }` failed
2035
+ * to compile. Guards with a distinct narrowing target (`isArrayType`,
2036
+ * `isMapType`, `isModelType`) keep their predicate.
2037
+ *
1996
2038
  * @param type
1997
2039
  * @returns
1998
2040
  */
1999
- declare function isFrozenType<IT extends IType<T | any, T, T>, T = any>(type: IT): type is IT;
2041
+ declare function isFrozenType<IT extends IType<T | any, T, T>, T = any>(type: IT): boolean;
2000
2042
 
2001
2043
  type OnReferenceInvalidatedEvent<STN extends IAnyStateTreeNode> = {
2002
2044
  parent: IAnyStateTreeNode;
@@ -2028,10 +2070,16 @@ declare function reference<IT extends IAnyComplexType>(subType: IT, options?: Re
2028
2070
  /**
2029
2071
  * Returns if a given value represents a reference type.
2030
2072
  *
2073
+ * Returns a plain `boolean`, not a `type is IT` predicate: with the parameter
2074
+ * typed as `IT`, narrowing to `IT` was a no-op in the positive branch while
2075
+ * collapsing the negative one to `never`, so `if (!isX(t)) { t.name }` failed
2076
+ * to compile. Guards with a distinct narrowing target (`isArrayType`,
2077
+ * `isMapType`, `isModelType`) keep their predicate.
2078
+ *
2031
2079
  * @param type
2032
2080
  * @returns
2033
2081
  */
2034
- declare function isReferenceType<IT extends IReferenceType<any>>(type: IT): type is IT;
2082
+ declare function isReferenceType<IT extends IReferenceType<any>>(type: IT): boolean;
2035
2083
  declare function safeReference<IT extends IAnyComplexType>(subType: IT, options: (ReferenceOptionsGetSet<IT> | object) & {
2036
2084
  acceptsUndefined: false;
2037
2085
  onInvalidated?: OnReferenceInvalidated<ReferenceT<IT>>;
@@ -2076,10 +2124,16 @@ declare const identifierNumber: ISimpleType<number>;
2076
2124
  /**
2077
2125
  * Returns if a given value represents an identifier type.
2078
2126
  *
2127
+ * Returns a plain `boolean`, not a `type is IT` predicate: with the parameter
2128
+ * typed as `IT`, narrowing to `IT` was a no-op in the positive branch while
2129
+ * collapsing the negative one to `never`, so `if (!isX(t)) { t.name }` failed
2130
+ * to compile. Guards with a distinct narrowing target (`isArrayType`,
2131
+ * `isMapType`, `isModelType`) keep their predicate.
2132
+ *
2079
2133
  * @param type
2080
2134
  * @returns
2081
2135
  */
2082
- declare function isIdentifierType<IT extends typeof identifier | typeof identifierNumber>(type: IT): type is IT;
2136
+ declare function isIdentifierType<IT extends typeof identifier | typeof identifierNumber>(type: IT): boolean;
2083
2137
  /**
2084
2138
  * Valid types for identifiers.
2085
2139
  */
@@ -482,30 +482,20 @@ function getIdentifier(target) {
482
482
  return getStateTreeNode(target).identifier;
483
483
  }
484
484
  /**
485
- * Tests if a reference is valid (pointing to an existing node and optionally if alive) and returns such reference if the check passes,
486
- * else it returns undefined.
487
- *
488
- * @param getter Function to access the reference.
489
- * @param checkIfAlive true to also make sure the referenced node is alive (default), false to skip this check.
490
- * @returns
485
+ * Resolves a reference getter to the referenced node, or `undefined` when the
486
+ * reference is empty, dangling, or (with `checkIfAlive`) points at a dead node.
487
+ * Backs both {@link tryReference} and {@link isValidReference}.
491
488
  */
492
- function tryReference(getter, checkIfAlive = true) {
489
+ function resolveReference(getter, checkIfAlive) {
493
490
  try {
494
491
  const node = getter();
495
492
  if (node === undefined || node === null) {
496
493
  return undefined;
497
494
  }
498
- else if (isStateTreeNode(node)) {
499
- if (!checkIfAlive) {
500
- return node;
501
- }
502
- else {
503
- return isAlive(node) ? node : undefined;
504
- }
505
- }
506
- else {
495
+ if (!isStateTreeNode(node)) {
507
496
  throw fail("The reference to be checked is not one of node, null or undefined");
508
497
  }
498
+ return !checkIfAlive || isAlive(node) ? node : undefined;
509
499
  }
510
500
  catch (e) {
511
501
  if (e instanceof InvalidReferenceError) {
@@ -514,6 +504,17 @@ function tryReference(getter, checkIfAlive = true) {
514
504
  throw e;
515
505
  }
516
506
  }
507
+ /**
508
+ * Tests if a reference is valid (pointing to an existing node and optionally if alive) and returns such reference if the check passes,
509
+ * else it returns undefined.
510
+ *
511
+ * @param getter Function to access the reference.
512
+ * @param checkIfAlive true to also make sure the referenced node is alive (default), false to skip this check.
513
+ * @returns
514
+ */
515
+ function tryReference(getter, checkIfAlive = true) {
516
+ return resolveReference(getter, checkIfAlive);
517
+ }
517
518
  /**
518
519
  * Tests if a reference is valid (pointing to an existing node and optionally if alive) and returns if the check passes or not.
519
520
  *
@@ -522,24 +523,7 @@ function tryReference(getter, checkIfAlive = true) {
522
523
  * @returns
523
524
  */
524
525
  function isValidReference(getter, checkIfAlive = true) {
525
- try {
526
- const node = getter();
527
- if (node === undefined || node === null) {
528
- return false;
529
- }
530
- else if (isStateTreeNode(node)) {
531
- return checkIfAlive ? isAlive(node) : true;
532
- }
533
- else {
534
- throw fail("The reference to be checked is not one of node, null or undefined");
535
- }
536
- }
537
- catch (e) {
538
- if (e instanceof InvalidReferenceError) {
539
- return false;
540
- }
541
- throw e;
542
- }
526
+ return resolveReference(getter, checkIfAlive) !== undefined;
543
527
  }
544
528
  /**
545
529
  * Try to resolve a given path relative to a given node.
@@ -1961,7 +1945,6 @@ function assertIsType(type, argNumber) {
1961
1945
  assertArg(type, isType, "mobx-state-tree type", argNumber);
1962
1946
  }
1963
1947
 
1964
- const runningActions = new Map();
1965
1948
  /**
1966
1949
  * Note: Consider migrating to `createActionTrackingMiddleware2`, it is easier to use.
1967
1950
  *
@@ -1977,6 +1960,12 @@ const runningActions = new Map();
1977
1960
  * @returns
1978
1961
  */
1979
1962
  function createActionTrackingMiddleware(hooks) {
1963
+ // per middleware, not per module: the entries hold the `context` this
1964
+ // middleware's own onStart returned, so two middlewares on one tree would
1965
+ // otherwise overwrite each other's context and then delete the shared entry —
1966
+ // whichever saw `flow_return` second dereferenced `undefined`.
1967
+ // createActionTrackingMiddleware2 scopes its map the same way.
1968
+ const runningActions = new Map();
1980
1969
  return function actionTrackingMiddleware(call, next, _abort) {
1981
1970
  switch (call.type) {
1982
1971
  case "action": {
@@ -2699,6 +2688,8 @@ function shortenPrintValue(valueInString) {
2699
2688
  }
2700
2689
  function toErrorString(error) {
2701
2690
  const { value } = error;
2691
+ // every context entry carries a type: they are built by getContextForPath and
2692
+ // by typecheck's initial `[{ path: "", type }]`
2702
2693
  const type = error.context[error.context.length - 1].type;
2703
2694
  const fullPath = error.context
2704
2695
  .map(({ path }) => path)
@@ -2710,14 +2701,21 @@ function toErrorString(error) {
2710
2701
  : isPrimitive(value)
2711
2702
  ? "value"
2712
2703
  : "snapshot";
2713
- const isSnapshotCompatible = type && isStateTreeNode(value) && type.is(getStateTreeNode(value).snapshot);
2714
- return `${pathPrefix}${currentTypename} ${shortenPrintValue(prettyPrintValue(value))} is not assignable ${type ? `to type: \`${type.name}\`` : ``}${error.message ? ` (${error.message})` : ""}${type
2715
- ? isPrimitiveType(type) || isPrimitive(value)
2716
- ? `.`
2717
- : `, expected an instance of \`${type.name}\` or a snapshot like \`${shortenPrintValue(type.describe())}\` instead.${isSnapshotCompatible
2718
- ? " (Note that a snapshot of the provided value is compatible with the targeted type)"
2719
- : ""}`
2720
- : `.`}`;
2704
+ let expectation;
2705
+ if (isPrimitiveType(type) || isPrimitive(value)) {
2706
+ expectation = ".";
2707
+ }
2708
+ else {
2709
+ // `isPrimitiveType` is declared `(type: IT) => type is IT`, so its negative
2710
+ // branch narrows to `never` rather than to "some non-primitive type"; the
2711
+ // annotation restores the type it actually has here.
2712
+ const complexType = type;
2713
+ const isSnapshotCompatible = isStateTreeNode(value) && complexType.is(getStateTreeNode(value).snapshot);
2714
+ expectation = `, expected an instance of \`${complexType.name}\` or a snapshot like \`${shortenPrintValue(complexType.describe())}\` instead.${isSnapshotCompatible
2715
+ ? " (Note that a snapshot of the provided value is compatible with the targeted type)"
2716
+ : ""}`;
2717
+ }
2718
+ return `${pathPrefix}${currentTypename} ${shortenPrintValue(prettyPrintValue(value))} is not assignable to type: \`${type.name}\`${error.message ? ` (${error.message})` : ""}${expectation}`;
2721
2719
  }
2722
2720
  /**
2723
2721
  * @internal
@@ -3546,6 +3544,8 @@ function createFlowSpawner(name, generator) {
3546
3544
  const spawner = function flowSpawner(...flowArgs) {
3547
3545
  // Implementation based on https://github.com/tj/co/blob/master/index.js
3548
3546
  const runId = getNextActionId();
3547
+ // no `!`: the guard below is the point, and asserting non-null first made it
3548
+ // dead to the checker while leaving it live at runtime
3549
3549
  const parentContext = getCurrentActionContext();
3550
3550
  if (!parentContext) {
3551
3551
  throw fail("a mst flow must always have a parent context");
@@ -3814,8 +3814,10 @@ class SnapshotProcessor extends BaseType {
3814
3814
  return sn;
3815
3815
  }
3816
3816
  _fixNode(node) {
3817
- // the node has to use these methods rather than the original type ones
3818
- proxyNodeTypeMethods(node.type, this, "create");
3817
+ // the node's type is the *inner* type, so `getType(instance).create(...)`
3818
+ // would bypass the processors — point it at ours instead
3819
+ const nodeType = node.type;
3820
+ nodeType.create = this.create.bind(this);
3819
3821
  if (node instanceof ObjectNode) {
3820
3822
  node.hasSnapshotPostProcessor = !!this._processors.postProcessor;
3821
3823
  }
@@ -3884,11 +3886,6 @@ class SnapshotProcessor extends BaseType {
3884
3886
  return this._subtype.isMatchingSnapshotId(current, processedSn);
3885
3887
  }
3886
3888
  }
3887
- function proxyNodeTypeMethods(nodeType, snapshotProcessorType, ...methods) {
3888
- for (const method of methods) {
3889
- nodeType[method] = snapshotProcessorType[method].bind(snapshotProcessorType);
3890
- }
3891
- }
3892
3889
  /**
3893
3890
  * `types.snapshotProcessor` - Runs a pre/post snapshot processor before/after serializing a given type.
3894
3891
  *
@@ -3939,6 +3936,41 @@ function snapshotProcessor(type, processors, name) {
3939
3936
  return new SnapshotProcessor(type, processors, name);
3940
3937
  }
3941
3938
 
3939
+ /**
3940
+ * Append `hooks` to a collection type's initializer list. `EMPTY_ARRAY` is the
3941
+ * shared default, so a type that never calls `.hooks()` allocates nothing.
3942
+ *
3943
+ * @internal
3944
+ * @hidden
3945
+ */
3946
+ function appendHookInitializer(current, hooks) {
3947
+ return current.length > 0 ? [...current, hooks] : [hooks];
3948
+ }
3949
+ /**
3950
+ * Install every hook the type's initializers produce onto `instance` as an MST
3951
+ * action, mirroring how a model's `.actions()` members are attached.
3952
+ *
3953
+ * @internal
3954
+ * @hidden
3955
+ */
3956
+ function installHookInitializers(hookInitializers, instance) {
3957
+ const addProp = !devMode() ? addHiddenFinalProp : addHiddenWritableProp;
3958
+ for (const initializer of hookInitializers) {
3959
+ const hooks = initializer(instance);
3960
+ for (const name of Object.keys(hooks)) {
3961
+ const hook = hooks[name];
3962
+ addProp(instance, name, createActionInvoker(instance, name, hook));
3963
+ }
3964
+ }
3965
+ }
3966
+ /**
3967
+ * The empty initializer list every collection type starts with.
3968
+ *
3969
+ * @internal
3970
+ * @hidden
3971
+ */
3972
+ const NO_HOOK_INITIALIZERS = EMPTY_ARRAY;
3973
+
3942
3974
  const needsIdentifierError = `Map.put can only be used to store complex values that have an identifier type attribute`;
3943
3975
  function tryCollectModelTypes(type, modelTypes) {
3944
3976
  const subtypes = type.getSubTypes();
@@ -4035,24 +4067,21 @@ class MSTMap extends mobx.ObservableMap {
4035
4067
  */
4036
4068
  class MapType extends ComplexType {
4037
4069
  _subType;
4070
+ hookInitializers;
4038
4071
  identifierMode = MapIdentifierMode.UNKNOWN;
4039
4072
  mapIdentifierAttribute = undefined;
4040
4073
  flags = TypeFlags.Map;
4041
- hookInitializers = [];
4042
- constructor(_subType, hookInitializers = []) {
4074
+ constructor(_subType, hookInitializers = NO_HOOK_INITIALIZERS) {
4043
4075
  super();
4044
4076
  this._subType = _subType;
4045
- this._determineIdentifierMode();
4046
4077
  this.hookInitializers = hookInitializers;
4078
+ this._determineIdentifierMode();
4047
4079
  }
4048
4080
  computeName() {
4049
4081
  return `Map<string, ${this._subType.name}>`;
4050
4082
  }
4051
4083
  hooks(hooks) {
4052
- const hookInitializers = this.hookInitializers.length > 0
4053
- ? this.hookInitializers.concat(hooks)
4054
- : [hooks];
4055
- return new MapType(this._subType, hookInitializers);
4084
+ return new MapType(this._subType, appendHookInitializer(this.hookInitializers, hooks));
4056
4085
  }
4057
4086
  instantiate(parent, subpath, environment, initialValue) {
4058
4087
  this._determineIdentifierMode();
@@ -4095,15 +4124,7 @@ class MapType extends ComplexType {
4095
4124
  }
4096
4125
  finalizeNewInstance(node, instance) {
4097
4126
  mobx._interceptReads(instance, node.unbox);
4098
- const type = node.type;
4099
- type.hookInitializers.forEach(initializer => {
4100
- const hooks = initializer(instance);
4101
- Object.keys(hooks).forEach(name => {
4102
- const hook = hooks[name];
4103
- const actionInvoker = createActionInvoker(instance, name, hook);
4104
- (!devMode() ? addHiddenFinalProp : addHiddenWritableProp)(instance, name, actionInvoker);
4105
- });
4106
- });
4127
+ installHookInitializers(node.type.hookInitializers, instance);
4107
4128
  mobx.intercept(instance, this.willChange);
4108
4129
  mobx.observe(instance, this.didChange);
4109
4130
  }
@@ -4304,9 +4325,9 @@ function isMapType(type) {
4304
4325
  */
4305
4326
  class ArrayType extends ComplexType {
4306
4327
  _subType;
4328
+ hookInitializers;
4307
4329
  flags = TypeFlags.Array;
4308
- hookInitializers = [];
4309
- constructor(_subType, hookInitializers = []) {
4330
+ constructor(_subType, hookInitializers = NO_HOOK_INITIALIZERS) {
4310
4331
  super();
4311
4332
  this._subType = _subType;
4312
4333
  this.hookInitializers = hookInitializers;
@@ -4315,10 +4336,7 @@ class ArrayType extends ComplexType {
4315
4336
  return `${this._subType.name}[]`;
4316
4337
  }
4317
4338
  hooks(hooks) {
4318
- const hookInitializers = this.hookInitializers.length > 0
4319
- ? this.hookInitializers.concat(hooks)
4320
- : [hooks];
4321
- return new ArrayType(this._subType, hookInitializers);
4339
+ return new ArrayType(this._subType, appendHookInitializer(this.hookInitializers, hooks));
4322
4340
  }
4323
4341
  instantiate(parent, subpath, environment, initialValue) {
4324
4342
  return createObjectNode(this, parent, subpath, environment, initialValue);
@@ -4338,15 +4356,7 @@ class ArrayType extends ComplexType {
4338
4356
  }
4339
4357
  finalizeNewInstance(node, instance) {
4340
4358
  mobx._getAdministration(instance).dehancer = node.unbox;
4341
- const type = node.type;
4342
- type.hookInitializers.forEach(initializer => {
4343
- const hooks = initializer(instance);
4344
- Object.keys(hooks).forEach(name => {
4345
- const hook = hooks[name];
4346
- const actionInvoker = createActionInvoker(instance, name, hook);
4347
- (!devMode() ? addHiddenFinalProp : addHiddenWritableProp)(instance, name, actionInvoker);
4348
- });
4349
- });
4359
+ installHookInitializers(node.type.hookInitializers, instance);
4350
4360
  mobx.intercept(instance, this.willChange);
4351
4361
  mobx.observe(instance, this.didChange);
4352
4362
  }
@@ -4722,8 +4732,7 @@ function getPropObservables(storedValue) {
4722
4732
  function objectTypeToString() {
4723
4733
  return getStateTreeNode(this).toString();
4724
4734
  }
4725
- const defaultObjectOptions = {
4726
- name: "AnonymousModel"};
4735
+ const ANONYMOUS_MODEL_NAME = "AnonymousModel";
4727
4736
  /**
4728
4737
  * A plain loop rather than `forAllProps`, which allocated a closure and made an
4729
4738
  * indirect call per property. This runs once per `types.model()` over every
@@ -4809,7 +4818,7 @@ class ModelType extends ComplexType {
4809
4818
  // `??`, not `||`: `types.model("", {})` names the model "". The old
4810
4819
  // `Object.assign(this, defaults, opts)` below overwrote the `||` fallback
4811
4820
  // with opts.name afterwards, so that only worked by accident.
4812
- super(opts.name ?? defaultObjectOptions.name);
4821
+ super(opts.name ?? ANONYMOUS_MODEL_NAME);
4813
4822
  // Every field is assigned here, unconditionally and in a fixed order,
4814
4823
  // rather than by `Object.assign(this, defaultObjectOptions, opts)`. `opts`
4815
4824
  // carries a different key set at each of the three call sites — `model()`,
@@ -4949,19 +4958,7 @@ class ModelType extends ComplexType {
4949
4958
  }
4950
4959
  extend(fn) {
4951
4960
  const initializer = (self) => {
4952
- const { actions, views, state, ...rest } = fn(self);
4953
- for (const key in rest) {
4954
- throw fail(`The \`extend\` function should return an object with a subset of the fields 'actions', 'views' and 'state'. Found invalid key '${key}'`);
4955
- }
4956
- if (state) {
4957
- this.instantiateVolatileState(self, state);
4958
- }
4959
- if (views) {
4960
- this.instantiateViews(self, views);
4961
- }
4962
- if (actions) {
4963
- this.instantiateActions(self, actions);
4964
- }
4961
+ this.applyExtension(self, fn(self), "The `extend` function");
4965
4962
  return self;
4966
4963
  };
4967
4964
  return this.cloneAndEnhance({ initializers: [initializer] });
@@ -4982,9 +4979,17 @@ class ModelType extends ComplexType {
4982
4979
  * are permitted (see extendInstance, which runs this in an action context).
4983
4980
  */
4984
4981
  applyExtensionToInstance(self, extension) {
4982
+ this.applyExtension(self, extension, "extendInstance");
4983
+ }
4984
+ /**
4985
+ * Materializes an `{ actions, views, state }` bundle onto an instance. Shared
4986
+ * by `.extend()` (at creation time) and `applyExtensionToInstance` (on a live
4987
+ * instance); `subject` only names the caller in the invalid-key error.
4988
+ */
4989
+ applyExtension(self, extension, subject) {
4985
4990
  const { actions, views, state, ...rest } = extension;
4986
4991
  for (const key in rest) {
4987
- throw fail(`extendInstance should return an object with a subset of the fields 'actions', 'views' and 'state'. Found invalid key '${key}'`);
4992
+ throw fail(`${subject} should return an object with a subset of the fields 'actions', 'views' and 'state'. Found invalid key '${key}'`);
4988
4993
  }
4989
4994
  if (state) {
4990
4995
  this.instantiateVolatileState(self, state);
@@ -5274,7 +5279,7 @@ function model(...args) {
5274
5279
  if (devMode() && typeof args[0] !== "string" && args[1]) {
5275
5280
  throw fail("Model creation failed. First argument must be a string when two arguments are provided");
5276
5281
  }
5277
- const name = typeof args[0] === "string" ? args.shift() : "AnonymousModel";
5282
+ const name = typeof args[0] === "string" ? args.shift() : ANONYMOUS_MODEL_NAME;
5278
5283
  const properties = args.shift() || {};
5279
5284
  return new ModelType({ name, properties });
5280
5285
  }
@@ -5288,7 +5293,7 @@ function model(...args) {
5288
5293
  function compose(...args) {
5289
5294
  // TODO: just join the base type names if no name is provided
5290
5295
  const hasTypename = typeof args[0] === "string";
5291
- const typeName = hasTypename ? args[0] : "AnonymousModel";
5296
+ const typeName = hasTypename ? args[0] : ANONYMOUS_MODEL_NAME;
5292
5297
  if (hasTypename) {
5293
5298
  args.shift();
5294
5299
  }
@@ -5514,6 +5519,12 @@ function getPrimitiveFactoryFromValue(value) {
5514
5519
  /**
5515
5520
  * Returns if a given value represents a primitive type.
5516
5521
  *
5522
+ * Returns a plain `boolean`, not a `type is IT` predicate: with the parameter
5523
+ * typed as `IT`, narrowing to `IT` was a no-op in the positive branch while
5524
+ * collapsing the negative one to `never`, so `if (!isX(t)) { t.name }` failed
5525
+ * to compile. Guards with a distinct narrowing target (`isArrayType`,
5526
+ * `isMapType`, `isModelType`) keep their predicate.
5527
+ *
5517
5528
  * @param type
5518
5529
  * @returns
5519
5530
  */
@@ -5578,6 +5589,12 @@ function literal(value) {
5578
5589
  /**
5579
5590
  * Returns if a given value represents a literal type.
5580
5591
  *
5592
+ * Returns a plain `boolean`, not a `type is IT` predicate: with the parameter
5593
+ * typed as `IT`, narrowing to `IT` was a no-op in the positive branch while
5594
+ * collapsing the negative one to `never`, so `if (!isX(t)) { t.name }` failed
5595
+ * to compile. Guards with a distinct narrowing target (`isArrayType`,
5596
+ * `isMapType`, `isModelType`) keep their predicate.
5597
+ *
5581
5598
  * @param type
5582
5599
  * @returns
5583
5600
  */
@@ -5657,6 +5674,12 @@ function refinement(...args) {
5657
5674
  /**
5658
5675
  * Returns if a given value is a refinement type.
5659
5676
  *
5677
+ * Returns a plain `boolean`, not a `type is IT` predicate: with the parameter
5678
+ * typed as `IT`, narrowing to `IT` was a no-op in the positive branch while
5679
+ * collapsing the negative one to `never`, so `if (!isX(t)) { t.name }` failed
5680
+ * to compile. Guards with a distinct narrowing target (`isArrayType`,
5681
+ * `isMapType`, `isModelType`) keep their predicate.
5682
+ *
5660
5683
  * @param type
5661
5684
  * @returns
5662
5685
  */
@@ -5994,7 +6017,8 @@ class Union extends BaseType {
5994
6017
  // - A failure is the definitive, scoped error only when every member is
5995
6018
  // discriminated; otherwise a catch-all could still accept the value, so
5996
6019
  // fall through to full validation.
5997
- if (isPlainObject(value) && !isStateTreeNode(value)) {
6020
+ const isSnapshotObject = isPlainObject(value) && !isStateTreeNode(value);
6021
+ if (isSnapshotObject) {
5998
6022
  const discriminator = value.type;
5999
6023
  if (typeof discriminator === "string") {
6000
6024
  const candidate = this._findCandidateByTypeDiscriminator(discriminator);
@@ -6010,7 +6034,7 @@ class Union extends BaseType {
6010
6034
  // for plain-object snapshots, prefer union members whose literal-typed
6011
6035
  // discriminator properties match the value (e.g. {type: "MsaView"})
6012
6036
  // so error output is scoped to the intended branch instead of every member
6013
- const candidates = isPlainObject(value) && !isStateTreeNode(value)
6037
+ const candidates = isSnapshotObject
6014
6038
  ? this._types.filter(t => this.snapshotLooksLikeType(value, t))
6015
6039
  : [];
6016
6040
  const typesToValidate = candidates.length > 0 ? candidates : this._types;
@@ -6080,6 +6104,12 @@ function union(...args) {
6080
6104
  /**
6081
6105
  * Returns if a given value represents a union type.
6082
6106
  *
6107
+ * Returns a plain `boolean`, not a `type is IT` predicate: with the parameter
6108
+ * typed as `IT`, narrowing to `IT` was a no-op in the positive branch while
6109
+ * collapsing the negative one to `never`, so `if (!isX(t)) { t.name }` failed
6110
+ * to compile. Guards with a distinct narrowing target (`isArrayType`,
6111
+ * `isMapType`, `isModelType`) keep their predicate.
6112
+ *
6083
6113
  * @param type
6084
6114
  * @returns
6085
6115
  */
@@ -6258,6 +6288,12 @@ const undefinedAsOptionalValues = [undefined];
6258
6288
  /**
6259
6289
  * Returns if a value represents an optional type.
6260
6290
  *
6291
+ * Returns a plain `boolean`, not a `type is IT` predicate: with the parameter
6292
+ * typed as `IT`, narrowing to `IT` was a no-op in the positive branch while
6293
+ * collapsing the negative one to `never`, so `if (!isX(t)) { t.name }` failed
6294
+ * to compile. Guards with a distinct narrowing target (`isArrayType`,
6295
+ * `isMapType`, `isModelType`) keep their predicate.
6296
+ *
6261
6297
  * @template IT
6262
6298
  * @param type
6263
6299
  * @returns
@@ -6504,6 +6540,12 @@ function late(nameOrType, maybeType) {
6504
6540
  /**
6505
6541
  * Returns if a given value represents a late type.
6506
6542
  *
6543
+ * Returns a plain `boolean`, not a `type is IT` predicate: with the parameter
6544
+ * typed as `IT`, narrowing to `IT` was a no-op in the positive branch while
6545
+ * collapsing the negative one to `never`, so `if (!isX(t)) { t.name }` failed
6546
+ * to compile. Guards with a distinct narrowing target (`isArrayType`,
6547
+ * `isMapType`, `isModelType`) keep their predicate.
6548
+ *
6507
6549
  * @param type
6508
6550
  * @returns
6509
6551
  */
@@ -6672,6 +6714,12 @@ function frozen(arg) {
6672
6714
  /**
6673
6715
  * Returns if a given value represents a frozen type.
6674
6716
  *
6717
+ * Returns a plain `boolean`, not a `type is IT` predicate: with the parameter
6718
+ * typed as `IT`, narrowing to `IT` was a no-op in the positive branch while
6719
+ * collapsing the negative one to `never`, so `if (!isX(t)) { t.name }` failed
6720
+ * to compile. Guards with a distinct narrowing target (`isArrayType`,
6721
+ * `isMapType`, `isModelType`) keep their predicate.
6722
+ *
6675
6723
  * @param type
6676
6724
  * @returns
6677
6725
  */
@@ -6902,9 +6950,6 @@ class BaseReferenceType extends SimpleType {
6902
6950
  * @hidden
6903
6951
  */
6904
6952
  class IdentifierReferenceType extends BaseReferenceType {
6905
- constructor(targetType, onInvalidated) {
6906
- super(targetType, onInvalidated);
6907
- }
6908
6953
  getValue(storedRefNode) {
6909
6954
  if (!storedRefNode.isAlive) {
6910
6955
  return undefined;
@@ -7020,6 +7065,12 @@ function reference(subType, options) {
7020
7065
  /**
7021
7066
  * Returns if a given value represents a reference type.
7022
7067
  *
7068
+ * Returns a plain `boolean`, not a `type is IT` predicate: with the parameter
7069
+ * typed as `IT`, narrowing to `IT` was a no-op in the positive branch while
7070
+ * collapsing the negative one to `never`, so `if (!isX(t)) { t.name }` failed
7071
+ * to compile. Guards with a distinct narrowing target (`isArrayType`,
7072
+ * `isMapType`, `isModelType`) keep their predicate.
7073
+ *
7023
7074
  * @param type
7024
7075
  * @returns
7025
7076
  */
@@ -7152,6 +7203,12 @@ const identifierNumber = new IdentifierNumberType();
7152
7203
  /**
7153
7204
  * Returns if a given value represents an identifier type.
7154
7205
  *
7206
+ * Returns a plain `boolean`, not a `type is IT` predicate: with the parameter
7207
+ * typed as `IT`, narrowing to `IT` was a no-op in the positive branch while
7208
+ * collapsing the negative one to `never`, so `if (!isX(t)) { t.name }` failed
7209
+ * to compile. Guards with a distinct narrowing target (`isArrayType`,
7210
+ * `isMapType`, `isModelType`) keep their predicate.
7211
+ *
7155
7212
  * @param type
7156
7213
  * @returns
7157
7214
  */