@jbrowse/mobx-state-tree 5.10.8 → 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.
package/dist/index.d.ts CHANGED
@@ -1921,6 +1921,17 @@ declare function optional<IT extends IAnyType, OptionalVals extends ValidOptiona
1921
1921
  * @returns
1922
1922
  */
1923
1923
  declare function isOptionalType<IT extends IAnyType>(type: IT): type is IT;
1924
+ /**
1925
+ * `types.stripDefault` - Like `types.optional`, but the property is omitted from
1926
+ * a parent model's snapshot entirely when its value equals the default (instead
1927
+ * of being serialized with the default value). Lets a model produce minimal
1928
+ * snapshots without a bespoke `postProcessSnapshot`.
1929
+ *
1930
+ * @param type
1931
+ * @param defaultValueOrFunction
1932
+ * @returns
1933
+ */
1934
+ declare function stripDefault<IT extends IAnyType>(type: IT, defaultValueOrFunction: OptionalDefaultValueOrFunction<IT>): IOptionalIType<IT, [undefined]>;
1924
1935
 
1925
1936
  /** @hidden */
1926
1937
  interface IMaybeIType<IT extends IAnyType, C, O> extends IType<IT["CreationType"] | C, IT["SnapshotType"] | O, IT["TypeWithoutSTN"] | O> {
@@ -2149,6 +2160,7 @@ declare const types: {
2149
2160
  safeReference: typeof safeReference;
2150
2161
  union: typeof union;
2151
2162
  optional: typeof optional;
2163
+ stripDefault: typeof stripDefault;
2152
2164
  literal: typeof literal;
2153
2165
  maybe: typeof maybe;
2154
2166
  maybeNull: typeof maybeNull;
@@ -4905,7 +4905,7 @@ class ModelType extends ComplexType {
4905
4905
  }
4906
4906
  getSnapshot(node, applyPostProcess = true) {
4907
4907
  const res = {};
4908
- this.forAllProps((name, _type) => {
4908
+ this.forAllProps((name, type) => {
4909
4909
  try {
4910
4910
  // TODO: FIXME, make sure the observable ref is used!
4911
4911
  const atom = mobx.getAtom(node.storedValue, name);
@@ -4914,7 +4914,11 @@ class ModelType extends ComplexType {
4914
4914
  catch (_e) {
4915
4915
  throw fail(`${name} property is declared twice`);
4916
4916
  }
4917
- 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
+ }
4918
4922
  });
4919
4923
  if (applyPostProcess) {
4920
4924
  return this.applySnapshotPostProcessor(res);
@@ -4924,7 +4928,13 @@ class ModelType extends ComplexType {
4924
4928
  processInitialSnapshot(childNodes) {
4925
4929
  const processed = {};
4926
4930
  Object.keys(childNodes).forEach(key => {
4927
- 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
+ }
4928
4938
  });
4929
4939
  return this.applySnapshotPostProcessor(processed);
4930
4940
  }
@@ -5878,6 +5888,72 @@ const undefinedAsOptionalValues = [undefined];
5878
5888
  function isOptionalType(type) {
5879
5889
  return isType(type) && (type.flags & TypeFlags.Optional) > 0;
5880
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
+ }
5881
5957
 
5882
5958
  const optionalUndefinedType = optional(undefinedType, undefined);
5883
5959
  const optionalNullType = optional(nullType, null);
@@ -6895,6 +6971,7 @@ const types = {
6895
6971
  safeReference,
6896
6972
  union,
6897
6973
  optional,
6974
+ stripDefault,
6898
6975
  literal,
6899
6976
  maybe,
6900
6977
  maybeNull,