@jbrowse/mobx-state-tree 5.10.7 → 5.11.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.
@@ -980,7 +980,7 @@ class BaseNode {
980
980
  if (this._escapedSubpath === undefined) {
981
981
  this._escapedSubpath = !this._subpath ? "" : escapeJsonPath(this._subpath);
982
982
  }
983
- return (this.parent.getEscapedPath(reportObserved) + "/" + this._escapedSubpath);
983
+ return `${this.parent.getEscapedPath(reportObserved)}/${this._escapedSubpath}`;
984
984
  }
985
985
  get isRoot() {
986
986
  return this.parent === null;
@@ -1214,9 +1214,8 @@ class ObjectNode extends BaseNode {
1214
1214
  // uninitialized parent
1215
1215
  // this is done to avoid traversing the whole tree to the root when using
1216
1216
  // the same reference again
1217
- while (parent &&
1218
- parent._observableInstanceState ===
1219
- 0 /* ObservableInstanceLifecycle.UNINITIALIZED */) {
1217
+ while (parent?._observableInstanceState ===
1218
+ 0 /* ObservableInstanceLifecycle.UNINITIALIZED */) {
1220
1219
  parentChain.unshift(parent);
1221
1220
  parent = parent.parent;
1222
1221
  }
@@ -1404,12 +1403,9 @@ class ObjectNode extends BaseNode {
1404
1403
  actionContext = actionContext.parentActionEvent;
1405
1404
  }
1406
1405
  let actionFullPath = "";
1407
- if (actionContext && actionContext.name != null) {
1406
+ if (actionContext?.name != null) {
1408
1407
  // try to use the context, and if it not available use the node one
1409
- const actionPath = (actionContext &&
1410
- actionContext.context &&
1411
- getPath(actionContext.context)) ||
1412
- escapedPath;
1408
+ const actionPath = (actionContext.context && getPath(actionContext.context)) || escapedPath;
1413
1409
  actionFullPath = `${actionPath}.${actionContext.name}()`;
1414
1410
  }
1415
1411
  return `You are trying to read or write to an object that is no longer part of a state tree. (Object type: '${this.type.name}', Path upon death: '${escapedPath}', Subpath: '${subpath}', Action: '${actionFullPath}'). Either detach nodes first, or don't use objects after removing / replacing them in the tree.`;
@@ -1556,9 +1552,10 @@ class ObjectNode extends BaseNode {
1556
1552
  }
1557
1553
  emitPatch(basePatch, source) {
1558
1554
  if (this._internalEventsHasSubscribers("patch" /* InternalEvents.Patch */)) {
1559
- const localizedPatch = extend({}, basePatch, {
1560
- path: source.path.substr(this.path.length) + "/" + basePatch.path // calculate the relative path of the patch
1561
- });
1555
+ const localizedPatch = {
1556
+ ...basePatch,
1557
+ path: `${source.path.substr(this.path.length)}/${basePatch.path}` // calculate the relative path of the patch
1558
+ };
1562
1559
  const [patch, reversePatch] = splitPatch(localizedPatch);
1563
1560
  this._internalEventsEmit("patch" /* InternalEvents.Patch */, patch, reversePatch);
1564
1561
  }
@@ -1887,7 +1884,7 @@ class SimpleType extends BaseType {
1887
1884
  * @returns `true` if the value is a type.
1888
1885
  */
1889
1886
  function isType(value) {
1890
- return typeof value === "object" && value && value.isType === true;
1887
+ return typeof value === "object" && value?.isType === true;
1891
1888
  }
1892
1889
  /**
1893
1890
  * @internal
@@ -2039,8 +2036,8 @@ function createActionTrackingMiddleware2(middlewareHooks) {
2039
2036
  const newCall = {
2040
2037
  ...call,
2041
2038
  // make a shallow copy of the parent action env
2042
- env: parentRunningAction && parentRunningAction.call.env,
2043
- parentCall: parentRunningAction && parentRunningAction.call
2039
+ env: parentRunningAction?.call.env,
2040
+ parentCall: parentRunningAction?.call
2044
2041
  };
2045
2042
  const passesFilter = !middlewareHooks.filter || middlewareHooks.filter(newCall);
2046
2043
  const hooks = passesFilter ? middlewareHooks : undefined;
@@ -2121,8 +2118,7 @@ function serializeArgument(node, actionName, index, arg) {
2121
2118
  return serializeTheUnserializable(`[function]`);
2122
2119
  }
2123
2120
  if (typeof arg === "object" && !isPlainObject(arg) && !isArray(arg)) {
2124
- return serializeTheUnserializable(`[object ${(arg && arg.constructor && arg.constructor.name) ||
2125
- "Complex Object"}]`);
2121
+ return serializeTheUnserializable(`[object ${arg?.constructor?.name || "Complex Object"}]`);
2126
2122
  }
2127
2123
  try {
2128
2124
  // Check if serializable, cycle free etc...
@@ -2131,7 +2127,7 @@ function serializeArgument(node, actionName, index, arg) {
2131
2127
  return arg;
2132
2128
  }
2133
2129
  catch (e) {
2134
- return serializeTheUnserializable("" + e);
2130
+ return serializeTheUnserializable(`${e}`);
2135
2131
  }
2136
2132
  }
2137
2133
  function deserializeArgument(adm, value) {
@@ -2491,7 +2487,7 @@ function runMiddleWares(node, baseCall, originalFn) {
2491
2487
  let result = null;
2492
2488
  function runNextMiddleware(call) {
2493
2489
  const middleware = middlewares.getNextMiddleware();
2494
- const handler = middleware && middleware.handler;
2490
+ const handler = middleware?.handler;
2495
2491
  if (!handler) {
2496
2492
  return mobx.action(originalFn)(...call.args);
2497
2493
  }
@@ -2599,7 +2595,7 @@ function safeStringify(value) {
2599
2595
  */
2600
2596
  function prettyPrintValue(value) {
2601
2597
  return typeof value === "function"
2602
- ? `<function${value.name ? " " + value.name : ""}>`
2598
+ ? `<function${value.name ? ` ${value.name}` : ""}>`
2603
2599
  : isStateTreeNode(value)
2604
2600
  ? `<${value}>`
2605
2601
  : `\`${safeStringify(value)}\``;
@@ -2623,16 +2619,13 @@ function toErrorString(error) {
2623
2619
  ? "value"
2624
2620
  : "snapshot";
2625
2621
  const isSnapshotCompatible = type && isStateTreeNode(value) && type.is(getStateTreeNode(value).snapshot);
2626
- return (`${pathPrefix}${currentTypename} ${shortenPrintValue(prettyPrintValue(value))} is not assignable ${type ? `to type: \`${type.name}\`` : ``}` +
2627
- (error.message ? ` (${error.message})` : "") +
2628
- (type
2629
- ? isPrimitiveType(type) || isPrimitive(value)
2630
- ? `.`
2631
- : `, expected an instance of \`${type.name}\` or a snapshot like \`${shortenPrintValue(type.describe())}\` instead.` +
2632
- (isSnapshotCompatible
2633
- ? " (Note that a snapshot of the provided value is compatible with the targeted type)"
2634
- : "")
2635
- : `.`));
2622
+ return `${pathPrefix}${currentTypename} ${shortenPrintValue(prettyPrintValue(value))} is not assignable ${type ? `to type: \`${type.name}\`` : ``}${error.message ? ` (${error.message})` : ""}${type
2623
+ ? isPrimitiveType(type) || isPrimitive(value)
2624
+ ? `.`
2625
+ : `, expected an instance of \`${type.name}\` or a snapshot like \`${shortenPrintValue(type.describe())}\` instead.${isSnapshotCompatible
2626
+ ? " (Note that a snapshot of the provided value is compatible with the targeted type)"
2627
+ : ""}`
2628
+ : `.`}`;
2636
2629
  }
2637
2630
  /**
2638
2631
  * @internal
@@ -2721,7 +2714,7 @@ function validationErrorsToString(type, value, errors) {
2721
2714
  if (errors.length === 0) {
2722
2715
  return undefined;
2723
2716
  }
2724
- return (`Error while converting ${shortenPrintValue(prettyPrintValue(value))} to \`${type.name}\`:\n\n ` + formatValidationErrorLines(errors).join("\n "));
2717
+ return `Error while converting ${shortenPrintValue(prettyPrintValue(value))} to \`${type.name}\`:\n\n ${formatValidationErrorLines(errors).join("\n ")}`;
2725
2718
  }
2726
2719
 
2727
2720
  let identifierCacheId = 0;
@@ -2753,7 +2746,7 @@ class IdentifierCache {
2753
2746
  this.cache.set(identifier, mobx.observable.array([], mobxShallow));
2754
2747
  }
2755
2748
  const set = this.cache.get(identifier);
2756
- if (set.indexOf(node) !== -1) {
2749
+ if (set.includes(node)) {
2757
2750
  throw fail(`Already registered`);
2758
2751
  }
2759
2752
  set.push(node);
@@ -2786,12 +2779,12 @@ class IdentifierCache {
2786
2779
  // The slash is added here so we only match children of the splitNode. In version 5.1.8 and
2787
2780
  // earlier there was no trailing slash, so non children that started with the same path string
2788
2781
  // were being matched incorrectly.
2789
- const basePath = splitNode.path + "/";
2782
+ const basePath = `${splitNode.path}/`;
2790
2783
  mobx.entries(this.cache).forEach(([id, nodes]) => {
2791
2784
  let modified = false;
2792
2785
  for (let i = nodes.length - 1; i >= 0; i--) {
2793
2786
  const node = nodes[i];
2794
- if (node === splitNode || node.path.indexOf(basePath) === 0) {
2787
+ if (node === splitNode || node.path.startsWith(basePath)) {
2795
2788
  newCache.addNodeToCache(node, false); // no need to update lastUpdated since it is a whole new cache
2796
2789
  nodes.splice(i, 1);
2797
2790
  // remove empty sets from cache
@@ -2889,7 +2882,7 @@ var NodeLifeCycle;
2889
2882
  * @returns true if the value is a state tree node.
2890
2883
  */
2891
2884
  function isStateTreeNode(value) {
2892
- return !!(value && value.$treenode);
2885
+ return !!value?.$treenode;
2893
2886
  }
2894
2887
  /**
2895
2888
  * @internal
@@ -2914,7 +2907,7 @@ function getStateTreeNode(value) {
2914
2907
  * @hidden
2915
2908
  */
2916
2909
  function getStateTreeNodeSafe(value) {
2917
- return (value && value.$treenode) || null;
2910
+ return value?.$treenode || null;
2918
2911
  }
2919
2912
  /**
2920
2913
  * @internal
@@ -3041,7 +3034,7 @@ const DEPRECATION_MESSAGE = "See https://github.com/mobxjs/mobx-state-tree/issue
3041
3034
  * @returns {Promise}
3042
3035
  */
3043
3036
  function process$1(asyncAction) {
3044
- deprecated("process", "`process()` has been renamed to `flow()`. " + DEPRECATION_MESSAGE);
3037
+ deprecated("process", `\`process()\` has been renamed to \`flow()\`. ${DEPRECATION_MESSAGE}`);
3045
3038
  return flow(asyncAction);
3046
3039
  }
3047
3040
 
@@ -3069,7 +3062,7 @@ Object.freeze(mobxShallow);
3069
3062
  * @hidden
3070
3063
  */
3071
3064
  function fail(message = "Illegal state") {
3072
- return new Error("[mobx-state-tree] " + message);
3065
+ return new Error(`[mobx-state-tree] ${message}`);
3073
3066
  }
3074
3067
  /**
3075
3068
  * @internal
@@ -3117,19 +3110,6 @@ function asArray(val) {
3117
3110
  }
3118
3111
  return [val];
3119
3112
  }
3120
- /**
3121
- * @internal
3122
- * @hidden
3123
- */
3124
- function extend(a, ...b) {
3125
- for (let i = 0; i < b.length; i++) {
3126
- const current = b[i];
3127
- for (const key in current) {
3128
- a[key] = current[key];
3129
- }
3130
- }
3131
- return a;
3132
- }
3133
3113
  /**
3134
3114
  * @internal
3135
3115
  * @hidden
@@ -3263,7 +3243,7 @@ class EventHandler {
3263
3243
  };
3264
3244
  }
3265
3245
  has(fn) {
3266
- return this.handlers.indexOf(fn) >= 0;
3246
+ return this.handlers.includes(fn);
3267
3247
  }
3268
3248
  unregister(fn) {
3269
3249
  if (this.emitting) {
@@ -3312,8 +3292,7 @@ class EventHandler {
3312
3292
  class EventHandlers {
3313
3293
  eventHandlers;
3314
3294
  hasSubscribers(event) {
3315
- const handler = this.eventHandlers && this.eventHandlers[event];
3316
- return !!handler && handler.hasSubscribers;
3295
+ return this.eventHandlers?.[event]?.hasSubscribers ?? false;
3317
3296
  }
3318
3297
  register(event, fn, atTheBeginning = false) {
3319
3298
  if (!this.eventHandlers) {
@@ -3326,11 +3305,10 @@ class EventHandlers {
3326
3305
  return handler.register(fn, atTheBeginning);
3327
3306
  }
3328
3307
  has(event, fn) {
3329
- const handler = this.eventHandlers && this.eventHandlers[event];
3330
- return !!handler && handler.has(fn);
3308
+ return this.eventHandlers?.[event]?.has(fn) ?? false;
3331
3309
  }
3332
3310
  unregister(event, fn) {
3333
- const handler = this.eventHandlers && this.eventHandlers[event];
3311
+ const handler = this.eventHandlers?.[event];
3334
3312
  if (handler) {
3335
3313
  handler.unregister(fn);
3336
3314
  }
@@ -3344,19 +3322,12 @@ class EventHandlers {
3344
3322
  this.eventHandlers = undefined;
3345
3323
  }
3346
3324
  emit(event, ...args) {
3347
- const handler = this.eventHandlers && this.eventHandlers[event];
3325
+ const handler = this.eventHandlers?.[event];
3348
3326
  if (handler) {
3349
3327
  handler.emit(...args);
3350
3328
  }
3351
3329
  }
3352
3330
  }
3353
- /**
3354
- * @internal
3355
- * @hidden
3356
- */
3357
- function stringStartsWith(str, beginning) {
3358
- return str.indexOf(beginning) === 0;
3359
- }
3360
3331
  /**
3361
3332
  * @internal
3362
3333
  * @hidden
@@ -3368,7 +3339,7 @@ const deprecated = function (id, message) {
3368
3339
  }
3369
3340
  // warn if hasn't been warned before
3370
3341
  if (deprecated.ids && !deprecated.ids.hasOwnProperty(id)) {
3371
- warnError("Deprecation warning: " + message);
3342
+ warnError(`Deprecation warning: ${message}`);
3372
3343
  }
3373
3344
  // mark as warned to avoid duplicate warn message
3374
3345
  if (deprecated.ids) {
@@ -3383,15 +3354,27 @@ deprecated.ids = {};
3383
3354
  function warnError(msg) {
3384
3355
  console.warn(new Error(`[mobx-state-tree] ${msg}`));
3385
3356
  }
3357
+ let _typeChecking;
3358
+ /**
3359
+ * Forces full run-time type-checking on or off, overriding the dev-mode and
3360
+ * `ENABLE_TYPE_CHECK` env-var defaults. Pass `true` to get better error messages
3361
+ * in production builds without relying on an environment variable, `false` to
3362
+ * force it off, or `undefined` to restore the default behavior.
3363
+ */
3364
+ function setTypeChecking(enabled) {
3365
+ _typeChecking = enabled;
3366
+ }
3386
3367
  /**
3387
3368
  * @internal
3388
3369
  * @hidden
3389
3370
  */
3390
3371
  function isTypeCheckingEnabled() {
3391
- return (devMode() ||
3392
- (typeof process !== "undefined" &&
3393
- process.env &&
3394
- process.env.ENABLE_TYPE_CHECK === "true"));
3372
+ // an explicit setTypeChecking() override (incl. `false`) wins over the
3373
+ // dev-mode / env-var default, hence ?? rather than ||
3374
+ return (_typeChecking ??
3375
+ (devMode() ||
3376
+ (typeof process !== "undefined" &&
3377
+ process.env?.ENABLE_TYPE_CHECK === "true")));
3395
3378
  }
3396
3379
  let _devMode = process.env.NODE_ENV !== "production";
3397
3380
  /**
@@ -3625,7 +3608,7 @@ function createFlowSpawner(name, generator) {
3625
3608
  // TODO: support more type of values? See https://github.com/tj/co/blob/249bbdc72da24ae44076afd716349d2089b31c4c/index.js#L100
3626
3609
  if (!ret.value || typeof ret.value.then !== "function") {
3627
3610
  // istanbul ignore next
3628
- throw fail("Only promises can be yielded to `async`, got: " + ret);
3611
+ throw fail(`Only promises can be yielded to \`async\`, got: ${ret}`);
3629
3612
  }
3630
3613
  return ret.value.then(onFulfilled, onRejected);
3631
3614
  }
@@ -3682,22 +3665,13 @@ function invertPatch(patch) {
3682
3665
  };
3683
3666
  }
3684
3667
  }
3685
- /**
3686
- * Simple simple check to check it is a number.
3687
- */
3688
- function isNumber(x) {
3689
- return typeof x === "number";
3690
- }
3691
3668
  /**
3692
3669
  * Escape slashes and backslashes.
3693
3670
  *
3694
3671
  * http://tools.ietf.org/html/rfc6901
3695
3672
  */
3696
3673
  function escapeJsonPath(path) {
3697
- if (isNumber(path) === true) {
3698
- return "" + path;
3699
- }
3700
- if (path.indexOf("/") === -1 && path.indexOf("~") === -1) {
3674
+ if (!path.includes("/") && !path.includes("~")) {
3701
3675
  return path;
3702
3676
  }
3703
3677
  return path.replace(/~/g, "~0").replace(/\//g, "~1");
@@ -3726,7 +3700,7 @@ function joinJsonPath(path) {
3726
3700
  }
3727
3701
  else {
3728
3702
  // absolute
3729
- return "/" + getPathStr(path);
3703
+ return `/${getPathStr(path)}`;
3730
3704
  }
3731
3705
  }
3732
3706
  /**
@@ -3741,9 +3715,9 @@ function splitJsonPath(path) {
3741
3715
  const valid = path === "" ||
3742
3716
  path === "." ||
3743
3717
  path === ".." ||
3744
- stringStartsWith(path, "/") ||
3745
- stringStartsWith(path, "./") ||
3746
- stringStartsWith(path, "../");
3718
+ path.startsWith("/") ||
3719
+ path.startsWith("./") ||
3720
+ path.startsWith("../");
3747
3721
  if (!valid) {
3748
3722
  throw fail(`a json path must be either rooted, empty or relative, but got '${path}'`);
3749
3723
  }
@@ -3951,16 +3925,16 @@ class MSTMap extends mobx.ObservableMap {
3951
3925
  }
3952
3926
  get(key) {
3953
3927
  // maybe this is over-enthousiastic? normalize numeric keys to strings
3954
- return super.get("" + key);
3928
+ return super.get(`${key}`);
3955
3929
  }
3956
3930
  has(key) {
3957
- return super.has("" + key);
3931
+ return super.has(`${key}`);
3958
3932
  }
3959
3933
  delete(key) {
3960
- return super.delete("" + key);
3934
+ return super.delete(`${key}`);
3961
3935
  }
3962
3936
  set(key, value) {
3963
- return super.set("" + key, value);
3937
+ return super.set(`${key}`, value);
3964
3938
  }
3965
3939
  put(value) {
3966
3940
  if (!value) {
@@ -4085,9 +4059,9 @@ class MapType extends ComplexType {
4085
4059
  return mobx.values(node.storedValue);
4086
4060
  }
4087
4061
  getChildNode(node, key) {
4088
- const childNode = node.storedValue.get("" + key);
4062
+ const childNode = node.storedValue.get(`${key}`);
4089
4063
  if (!childNode) {
4090
- throw fail("Not a child " + key);
4064
+ throw fail(`Not a child ${key}`);
4091
4065
  }
4092
4066
  return childNode;
4093
4067
  }
@@ -4195,7 +4169,7 @@ class MapType extends ComplexType {
4195
4169
  // Don't use target.replace, as it will throw away all existing items first
4196
4170
  for (const key in snapshot) {
4197
4171
  target.set(key, snapshot[key]);
4198
- currentKeys["" + key] = true;
4172
+ currentKeys[`${key}`] = true;
4199
4173
  }
4200
4174
  }
4201
4175
  Object.keys(currentKeys).forEach(key => {
@@ -4295,7 +4269,7 @@ class ArrayType extends ComplexType {
4295
4269
  const subType = objNode.type._subType;
4296
4270
  const result = {};
4297
4271
  snapshot.forEach((item, index) => {
4298
- const subpath = "" + index;
4272
+ const subpath = `${index}`;
4299
4273
  result[subpath] = subType.instantiate(objNode, subpath, undefined, item);
4300
4274
  });
4301
4275
  return result;
@@ -4329,11 +4303,11 @@ class ArrayType extends ComplexType {
4329
4303
  if (index < node.storedValue.length) {
4330
4304
  return node.storedValue[index];
4331
4305
  }
4332
- throw fail("Not a child: " + key);
4306
+ throw fail(`Not a child: ${key}`);
4333
4307
  }
4334
4308
  willChange(change) {
4335
4309
  const node = getStateTreeNode(change.object);
4336
- node.assertWritable({ subpath: "" + change.index });
4310
+ node.assertWritable({ subpath: `${change.index}` });
4337
4311
  const subType = node.type._subType;
4338
4312
  const childNodes = node.getChildren();
4339
4313
  switch (change.type) {
@@ -4359,7 +4333,7 @@ class ArrayType extends ComplexType {
4359
4333
  change.added = addedNodes;
4360
4334
  // update paths of remaining items
4361
4335
  for (let i = index + removedCount; i < childNodes.length; i++) {
4362
- childNodes[i].setParent(node, "" + (i + added.length - removedCount));
4336
+ childNodes[i].setParent(node, `${i + added.length - removedCount}`);
4363
4337
  }
4364
4338
  }
4365
4339
  break;
@@ -4382,7 +4356,7 @@ class ArrayType extends ComplexType {
4382
4356
  case "update":
4383
4357
  return void node.emitPatch({
4384
4358
  op: "replace",
4385
- path: "" + change.index,
4359
+ path: `${change.index}`,
4386
4360
  value: change.newValue.snapshot,
4387
4361
  oldValue: change.oldValue ? change.oldValue.snapshot : undefined
4388
4362
  }, node);
@@ -4390,15 +4364,15 @@ class ArrayType extends ComplexType {
4390
4364
  for (let i = change.removedCount - 1; i >= 0; i--) {
4391
4365
  node.emitPatch({
4392
4366
  op: "remove",
4393
- path: "" + (change.index + i),
4367
+ path: `${change.index + i}`,
4394
4368
  oldValue: change.removed[i].snapshot
4395
4369
  }, node);
4396
4370
  }
4397
4371
  for (let i = 0; i < change.addedCount; i++) {
4398
4372
  node.emitPatch({
4399
4373
  op: "add",
4400
- path: "" + (change.index + i),
4401
- value: node.getChildNode("" + (change.index + i)).snapshot,
4374
+ path: `${change.index + i}`,
4375
+ value: node.getChildNode(`${change.index + i}`).snapshot,
4402
4376
  oldValue: undefined
4403
4377
  }, node);
4404
4378
  }
@@ -4433,7 +4407,7 @@ class ArrayType extends ComplexType {
4433
4407
  return typeCheckFailure(context, value, "Value is not an array");
4434
4408
  }
4435
4409
  for (let i = 0; i < value.length; i++) {
4436
- getContextForPath(context, "" + i, this._subType);
4410
+ getContextForPath(context, `${i}`, this._subType);
4437
4411
  const errors = this._subType.validate(value[i], context);
4438
4412
  popContext(context);
4439
4413
  if (errors.length > 0) {
@@ -4484,7 +4458,7 @@ function reconcileArrayChildren(parent, childType, oldNodes, newValues, newPaths
4484
4458
  const hasNewNode = i <= newValues.length - 1;
4485
4459
  const oldNode = oldNodes[i];
4486
4460
  let newValue = hasNewNode ? newValues[i] : undefined;
4487
- const newPath = "" + newPaths[i];
4461
+ const newPath = `${newPaths[i]}`;
4488
4462
  // for some reason, instead of newValue we got a node, fallback to the storedValue
4489
4463
  // TODO: https://github.com/mobxjs/mobx-state-tree/issues/340#issuecomment-325581681
4490
4464
  if (isNode(newValue)) {
@@ -4920,18 +4894,18 @@ class ModelType extends ComplexType {
4920
4894
  }
4921
4895
  getChildNode(node, key) {
4922
4896
  if (!(key in this.properties)) {
4923
- throw fail("Not a value property: " + key);
4897
+ throw fail(`Not a value property: ${key}`);
4924
4898
  }
4925
4899
  const adm = mobx._getAdministration(node.storedValue, key);
4926
4900
  const childNode = adm.raw?.();
4927
4901
  if (!childNode) {
4928
- throw fail("Node not available for property " + key);
4902
+ throw fail(`Node not available for property ${key}`);
4929
4903
  }
4930
4904
  return childNode;
4931
4905
  }
4932
4906
  getSnapshot(node, applyPostProcess = true) {
4933
4907
  const res = {};
4934
- this.forAllProps((name, _type) => {
4908
+ this.forAllProps((name, type) => {
4935
4909
  try {
4936
4910
  // TODO: FIXME, make sure the observable ref is used!
4937
4911
  const atom = mobx.getAtom(node.storedValue, name);
@@ -4940,7 +4914,11 @@ class ModelType extends ComplexType {
4940
4914
  catch (_e) {
4941
4915
  throw fail(`${name} property is declared twice`);
4942
4916
  }
4943
- res[name] = this.getChildNode(node, name).snapshot;
4917
+ const snapshot = this.getChildNode(node, name).snapshot;
4918
+ // strip-default optionals omit their key when equal to the default
4919
+ if (!shouldStripChildFromSnapshot(type, snapshot)) {
4920
+ res[name] = snapshot;
4921
+ }
4944
4922
  });
4945
4923
  if (applyPostProcess) {
4946
4924
  return this.applySnapshotPostProcessor(res);
@@ -4950,7 +4928,13 @@ class ModelType extends ComplexType {
4950
4928
  processInitialSnapshot(childNodes) {
4951
4929
  const processed = {};
4952
4930
  Object.keys(childNodes).forEach(key => {
4953
- processed[key] = childNodes[key].getSnapshot();
4931
+ const snapshot = childNodes[key].getSnapshot();
4932
+ // strip-default optionals omit their key when equal to the default; this
4933
+ // mirrors getSnapshot for nodes serialized before they become observable
4934
+ // instances (e.g. array/map children that were never accessed)
4935
+ if (!shouldStripChildFromSnapshot(this.properties[key], snapshot)) {
4936
+ processed[key] = snapshot;
4937
+ }
4954
4938
  });
4955
4939
  return this.applySnapshotPostProcessor(processed);
4956
4940
  }
@@ -5003,11 +4987,9 @@ class ModelType extends ComplexType {
5003
4987
  }
5004
4988
  describe() {
5005
4989
  // optimization: cache
5006
- return ("{ " +
5007
- this.propertyNames
5008
- .map(key => key + ": " + this.properties[key].describe())
5009
- .join("; ") +
5010
- " }");
4990
+ return `{ ${this.propertyNames
4991
+ .map(key => `${key}: ${this.properties[key].describe()}`)
4992
+ .join("; ")} }`;
5011
4993
  }
5012
4994
  getDefaultSnapshot() {
5013
4995
  return EMPTY_OBJECT;
@@ -5052,7 +5034,7 @@ function compose(...args) {
5052
5034
  }
5053
5035
  return args
5054
5036
  .reduce((prev, cur) => prev.cloneAndEnhance({
5055
- name: prev.name + "_" + cur.name,
5037
+ name: `${prev.name}_${cur.name}`,
5056
5038
  properties: cur.properties,
5057
5039
  initializers: cur.initializers,
5058
5040
  preProcessor: (snapshot) => cur.applySnapshotPreProcessor(prev.applySnapshotPreProcessor(snapshot)),
@@ -5219,7 +5201,7 @@ function getPrimitiveFactoryFromValue(value) {
5219
5201
  return DatePrimitive;
5220
5202
  }
5221
5203
  }
5222
- throw fail("Cannot determine primitive type from value " + value);
5204
+ throw fail(`Cannot determine primitive type from value ${value}`);
5223
5205
  }
5224
5206
  /**
5225
5207
  * Returns if a given value represents a primitive type.
@@ -5395,7 +5377,7 @@ function enumeration(name, options) {
5395
5377
  assertIsString(option, i + 1);
5396
5378
  });
5397
5379
  }
5398
- const type = union(...realOptions.map(option => literal("" + option)));
5380
+ const type = union(...realOptions.map(option => literal(`${option}`)));
5399
5381
  if (typeof name === "string") {
5400
5382
  type.name = name;
5401
5383
  }
@@ -5453,7 +5435,7 @@ class Union extends BaseType {
5453
5435
  return this._types.some(subType => subType.isAssignableFrom(type));
5454
5436
  }
5455
5437
  describe() {
5456
- return ("(" + this._types.map(factory => factory.describe()).join(" | ") + ")");
5438
+ return `(${this._types.map(factory => factory.describe()).join(" | ")})`;
5457
5439
  }
5458
5440
  instantiate(parent, subpath, environment, initialValue) {
5459
5441
  const type = this.determineType(initialValue, undefined);
@@ -5495,8 +5477,7 @@ class Union extends BaseType {
5495
5477
  if (errors.length === 0) {
5496
5478
  return baseWithDiscriminator;
5497
5479
  }
5498
- return (`${baseWithDiscriminator}:\n ` +
5499
- formatValidationErrorLines(errors).join("\n "));
5480
+ return `${baseWithDiscriminator}:\n ${formatValidationErrorLines(errors).join("\n ")}`;
5500
5481
  }
5501
5482
  _findCandidateByTypeDiscriminator(discriminator) {
5502
5483
  let found;
@@ -5726,7 +5707,7 @@ function union(optionsOrType, ...otherTypes) {
5726
5707
  const types = isType(optionsOrType)
5727
5708
  ? [optionsOrType, ...otherTypes]
5728
5709
  : otherTypes;
5729
- const name = "(" + types.map(type => type.name).join(" | ") + ")";
5710
+ const name = `(${types.map(type => type.name).join(" | ")})`;
5730
5711
  // check all options
5731
5712
  if (devMode()) {
5732
5713
  if (options) {
@@ -5793,17 +5774,17 @@ class OptionalValue extends BaseType {
5793
5774
  this.optionalValues = optionalValues;
5794
5775
  }
5795
5776
  describe() {
5796
- return this._subtype.describe() + "?";
5777
+ return `${this._subtype.describe()}?`;
5797
5778
  }
5798
5779
  instantiate(parent, subpath, environment, initialValue) {
5799
- if (this.optionalValues.indexOf(initialValue) >= 0) {
5780
+ if (this.optionalValues.includes(initialValue)) {
5800
5781
  const defaultInstanceOrSnapshot = this.getDefaultInstanceOrSnapshot();
5801
5782
  return this._subtype.instantiate(parent, subpath, environment, defaultInstanceOrSnapshot);
5802
5783
  }
5803
5784
  return this._subtype.instantiate(parent, subpath, environment, initialValue);
5804
5785
  }
5805
5786
  reconcile(current, newValue, parent, subpath) {
5806
- return this._subtype.reconcile(current, this.optionalValues.indexOf(newValue) < 0 && this._subtype.is(newValue)
5787
+ return this._subtype.reconcile(current, !this.optionalValues.includes(newValue) && this._subtype.is(newValue)
5807
5788
  ? newValue
5808
5789
  : this.getDefaultInstanceOrSnapshot(), parent, subpath);
5809
5790
  }
@@ -5820,7 +5801,7 @@ class OptionalValue extends BaseType {
5820
5801
  }
5821
5802
  isValidSnapshot(value, context) {
5822
5803
  // defaulted values can be skipped
5823
- if (this.optionalValues.indexOf(value) >= 0) {
5804
+ if (this.optionalValues.includes(value)) {
5824
5805
  return typeCheckSuccess();
5825
5806
  }
5826
5807
  // bounce validation to the sub-type
@@ -5907,6 +5888,72 @@ const undefinedAsOptionalValues = [undefined];
5907
5888
  function isOptionalType(type) {
5908
5889
  return isType(type) && (type.flags & TypeFlags.Optional) > 0;
5909
5890
  }
5891
+ /**
5892
+ * Compare a child snapshot to a stripped-default's reference snapshot. Mirrors
5893
+ * the legacy hand-rolled comparison: identity for primitives, structural for
5894
+ * objects/arrays.
5895
+ */
5896
+ function defaultSnapshotEquals(a, b) {
5897
+ if (a === b) {
5898
+ return true;
5899
+ }
5900
+ if (typeof a === "object" &&
5901
+ a !== null &&
5902
+ typeof b === "object" &&
5903
+ b !== null) {
5904
+ return JSON.stringify(a) === JSON.stringify(b);
5905
+ }
5906
+ return false;
5907
+ }
5908
+ /**
5909
+ * An optional type that additionally omits its key from a parent model's
5910
+ * snapshot when the value equals the (snapshotted) default. The comparison is
5911
+ * against the default *snapshot* — i.e. the subtype is instantiated with the
5912
+ * default once and its post-processed snapshot is cached — so a default whose
5913
+ * normalized form gains fields (e.g. a fileLocation gaining `locationType`)
5914
+ * still strips correctly.
5915
+ *
5916
+ * @hidden
5917
+ * @internal
5918
+ */
5919
+ class StripDefaultValue extends OptionalValue {
5920
+ _defaultSnapshot;
5921
+ shouldStripFromSnapshot(snapshot) {
5922
+ if (!this._defaultSnapshot) {
5923
+ // instantiate the subtype detached with the default and read the node's
5924
+ // snapshot, which normalizes (fills model defaults, applies the subtype's
5925
+ // own postProcess). Cached on the (singleton) type after first use.
5926
+ const node = this.getSubTypes().instantiate(null, "", undefined, this.getDefaultInstanceOrSnapshot());
5927
+ this._defaultSnapshot = { value: node.snapshot };
5928
+ }
5929
+ return defaultSnapshotEquals(snapshot, this._defaultSnapshot.value);
5930
+ }
5931
+ }
5932
+ /**
5933
+ * Whether `type` is a strip-default optional whose current child `snapshot`
5934
+ * equals its default and should therefore be omitted from the parent model's
5935
+ * snapshot. Used by `ModelType.getSnapshot`.
5936
+ *
5937
+ * @hidden
5938
+ * @internal
5939
+ */
5940
+ function shouldStripChildFromSnapshot(type, snapshot) {
5941
+ return (type instanceof StripDefaultValue && type.shouldStripFromSnapshot(snapshot));
5942
+ }
5943
+ /**
5944
+ * `types.stripDefault` - Like `types.optional`, but the property is omitted from
5945
+ * a parent model's snapshot entirely when its value equals the default (instead
5946
+ * of being serialized with the default value). Lets a model produce minimal
5947
+ * snapshots without a bespoke `postProcessSnapshot`.
5948
+ *
5949
+ * @param type
5950
+ * @param defaultValueOrFunction
5951
+ * @returns
5952
+ */
5953
+ function stripDefault(type, defaultValueOrFunction) {
5954
+ checkOptionalPreconditions(type, defaultValueOrFunction);
5955
+ return new StripDefaultValue(type, defaultValueOrFunction, undefinedAsOptionalValues);
5956
+ }
5910
5957
 
5911
5958
  const optionalUndefinedType = optional(undefinedType, undefined);
5912
5959
  const optionalNullType = optional(nullType, null);
@@ -6021,8 +6068,7 @@ function late(nameOrType, maybeType) {
6021
6068
  // checks that the type is actually a late type
6022
6069
  if (devMode()) {
6023
6070
  if (!(typeof type === "function" && type.length === 0)) {
6024
- throw fail("Invalid late type, expected a function with zero arguments that returns a type, got: " +
6025
- type);
6071
+ throw fail(`Invalid late type, expected a function with zero arguments that returns a type, got: ${type}`);
6026
6072
  }
6027
6073
  }
6028
6074
  return new Late(name, type);
@@ -6235,8 +6281,7 @@ class StoredReference {
6235
6281
  const normalizedId = normalizeIdentifier(this.identifier);
6236
6282
  const root = node.root;
6237
6283
  const lastCacheModification = root.identifierCache.getLastCacheModificationPerId(normalizedId);
6238
- if (!this.resolvedReference ||
6239
- this.resolvedReference.lastCacheModification !== lastCacheModification) {
6284
+ if (this.resolvedReference?.lastCacheModification !== lastCacheModification) {
6240
6285
  const { targetType } = this;
6241
6286
  // reference was initialized with the identifier of the target
6242
6287
  const target = root.identifierCache.resolve(targetType, normalizedId);
@@ -6245,7 +6290,7 @@ class StoredReference {
6245
6290
  }
6246
6291
  this.resolvedReference = {
6247
6292
  node: target,
6248
- lastCacheModification: lastCacheModification
6293
+ lastCacheModification
6249
6294
  };
6250
6295
  }
6251
6296
  }
@@ -6293,7 +6338,7 @@ class BaseReferenceType extends SimpleType {
6293
6338
  // since it is a scalar value (immutable-ish) and we need to change it
6294
6339
  // from the parent
6295
6340
  const storedRefParentNode = storedRefNode.parent;
6296
- if (!storedRefParentNode || !storedRefParentNode.isAlive) {
6341
+ if (!storedRefParentNode?.isAlive) {
6297
6342
  return;
6298
6343
  }
6299
6344
  const storedRefParentValue = storedRefParentNode.storedValue;
@@ -6365,7 +6410,7 @@ class BaseReferenceType extends SimpleType {
6365
6410
  }
6366
6411
  // make sure the target node is actually there and initialized
6367
6412
  const storedRefParentNode = storedRefNode.parent;
6368
- const storedRefParentValue = storedRefParentNode && storedRefParentNode.storedValue;
6413
+ const storedRefParentValue = storedRefParentNode?.storedValue;
6369
6414
  if (storedRefParentNode &&
6370
6415
  storedRefParentNode.isAlive &&
6371
6416
  storedRefParentValue) {
@@ -6679,7 +6724,7 @@ function isIdentifierType(type) {
6679
6724
  * @hidden
6680
6725
  */
6681
6726
  function normalizeIdentifier(id) {
6682
- return "" + id;
6727
+ return `${id}`;
6683
6728
  }
6684
6729
  /**
6685
6730
  * @internal
@@ -6775,7 +6820,7 @@ class CustomType extends SimpleType {
6775
6820
  instantiate(parent, subpath, environment, initialValue) {
6776
6821
  const valueToStore = this.options.isTargetType(initialValue)
6777
6822
  ? initialValue
6778
- : this.options.fromSnapshot(initialValue, parent && parent.root.environment);
6823
+ : this.options.fromSnapshot(initialValue, parent?.root.environment);
6779
6824
  return createScalarNode(this, parent, subpath, environment, valueToStore);
6780
6825
  }
6781
6826
  reconcile(current, value, parent, subpath) {
@@ -6926,6 +6971,7 @@ const types = {
6926
6971
  safeReference,
6927
6972
  union,
6928
6973
  optional,
6974
+ stripDefault,
6929
6975
  literal,
6930
6976
  maybe,
6931
6977
  maybeNull,
@@ -7019,6 +7065,7 @@ exports.resolvePath = resolvePath;
7019
7065
  exports.setDevMode = setDevMode;
7020
7066
  exports.setLivelinessChecking = setLivelinessChecking;
7021
7067
  exports.setLivelynessChecking = setLivelynessChecking;
7068
+ exports.setTypeChecking = setTypeChecking;
7022
7069
  exports.splitJsonPath = splitJsonPath;
7023
7070
  exports.t = types;
7024
7071
  exports.toGenerator = toGenerator;