isaacscript-common 6.23.0 → 7.0.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.
@@ -2,7 +2,7 @@
2
2
  * A function that creates the default value for your `DefaultMap`. For example, if it was a
3
3
  * `DefaultMap` containing maps, the factory function would be: `() => new Map()`
4
4
  */
5
- export declare type FactoryFunction<V, Args extends unknown[]> = (...extraArgs: Args) => V;
5
+ export declare type FactoryFunction<V, Args extends unknown[]> = (...args: Args) => V;
6
6
  /**
7
7
  * `DefaultMap` is a data structure that makes working with default values easier.
8
8
  *
@@ -95,12 +95,12 @@ export declare class DefaultMap<Key, Value, Args extends unknown[] = []> extends
95
95
  * If the key exists, this will return the same thing as the normal `Map.get` method. Otherwise,
96
96
  * it will set a default value for the provided key, and then return the default value.
97
97
  */
98
- getAndSetDefault(key: Key, ...extraArgs: Args): Value;
98
+ getAndSetDefault(key: Key, ...args: Args): Value;
99
99
  /**
100
100
  * Returns the default value to be used for a new key. (If a factory function was provided during
101
101
  * instantiation, this will execute the factory function.)
102
102
  */
103
- getDefaultValue(...extraArgs: Args): Value;
103
+ getDefaultValue(...args: Args): Value;
104
104
  /**
105
105
  * Helper method for cloning the map. Returns either the default value or a reference to the
106
106
  * factory function.
@@ -1 +1 @@
1
- {"version":3,"file":"DefaultMap.d.ts","sourceRoot":"","sources":["../../src/classes/DefaultMap.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,oBAAY,eAAe,CAAC,CAAC,EAAE,IAAI,SAAS,OAAO,EAAE,IAAI,CACvD,GAAG,SAAS,EAAE,IAAI,KACf,CAAC,CAAC;AAEP;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+EG;AACH,qBAAa,UAAU,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,SAAS,OAAO,EAAE,GAAG,EAAE,CAAE,SAAQ,GAAG,CAC1E,GAAG,EACH,KAAK,CACN;IACC,OAAO,CAAC,YAAY,CAAoB;IACxC,OAAO,CAAC,mBAAmB,CAA2C;IAEtE;;;OAGG;gBAED,6BAA6B,EAAE,KAAK,GAAG,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,EACnE,gBAAgB,CAAC,EAAE,QAAQ,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAqB3C;;;OAGG;IACH,gBAAgB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,SAAS,EAAE,IAAI,GAAG,KAAK;IAWrD;;;OAGG;IACH,eAAe,CAAC,GAAG,SAAS,EAAE,IAAI,GAAG,KAAK;IAY1C;;;OAGG;IACH,iBAAiB,IAAI,KAAK,GAAG,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC;CAW1D"}
1
+ {"version":3,"file":"DefaultMap.d.ts","sourceRoot":"","sources":["../../src/classes/DefaultMap.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,oBAAY,eAAe,CAAC,CAAC,EAAE,IAAI,SAAS,OAAO,EAAE,IAAI,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,CAAC,CAAC;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+EG;AACH,qBAAa,UAAU,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,SAAS,OAAO,EAAE,GAAG,EAAE,CAAE,SAAQ,GAAG,CAC1E,GAAG,EACH,KAAK,CACN;IACC,OAAO,CAAC,YAAY,CAAoB;IACxC,OAAO,CAAC,mBAAmB,CAA2C;IAEtE;;;OAGG;gBAED,6BAA6B,EAAE,KAAK,GAAG,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,EACnE,gBAAgB,CAAC,EAAE,QAAQ,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAqB3C;;;OAGG;IACH,gBAAgB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,IAAI,GAAG,KAAK;IAWhD;;;OAGG;IACH,eAAe,CAAC,GAAG,IAAI,EAAE,IAAI,GAAG,KAAK;IAYrC;;;OAGG;IACH,iBAAiB,IAAI,KAAK,GAAG,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC;CAW1D"}
@@ -3,6 +3,7 @@ local __TS__Class = ____lualib.__TS__Class
3
3
  local Map = ____lualib.Map
4
4
  local __TS__ClassExtends = ____lualib.__TS__ClassExtends
5
5
  local __TS__TypeOf = ____lualib.__TS__TypeOf
6
+ local __TS__New = ____lualib.__TS__New
6
7
  local ____exports = {}
7
8
  local ____types = require("functions.types")
8
9
  local isFunction = ____types.isFunction
@@ -131,4 +132,40 @@ function DefaultMap.prototype.getConstructorArg(self)
131
132
  end
132
133
  error("A DefaultMap was incorrectly instantiated.")
133
134
  end
135
+ local function test(self)
136
+ local myDefaultMapBoolean = __TS__New(____exports.DefaultMap, false)
137
+ local myDefaultMapBooleanFactory = __TS__New(
138
+ ____exports.DefaultMap,
139
+ function() return false end
140
+ )
141
+ local myDefaultMapBooleanWithoutParams = __TS__New(____exports.DefaultMap, false)
142
+ local myDefaultMapNumber = __TS__New(____exports.DefaultMap, 123)
143
+ local myDefaultMapNumberFactory = __TS__New(
144
+ ____exports.DefaultMap,
145
+ function() return 123 end
146
+ )
147
+ local myDefaultMapNumberWithoutParams = __TS__New(____exports.DefaultMap, 123)
148
+ local myDefaultMapString = __TS__New(____exports.DefaultMap, "foo")
149
+ local myDefaultMapStringFactory = __TS__New(
150
+ ____exports.DefaultMap,
151
+ function() return "foo" end
152
+ )
153
+ local myDefaultMapStringWithoutParams = __TS__New(____exports.DefaultMap, "foo")
154
+ local myDefaultMapArray = __TS__New(
155
+ ____exports.DefaultMap,
156
+ function() return {} end
157
+ )
158
+ local myDefaultMapArrayWithoutParams = __TS__New(
159
+ ____exports.DefaultMap,
160
+ function() return {} end
161
+ )
162
+ local myDefaultMapMap = __TS__New(
163
+ ____exports.DefaultMap,
164
+ function() return __TS__New(Map) end
165
+ )
166
+ local myDefaultMapMapWithoutParams = __TS__New(
167
+ ____exports.DefaultMap,
168
+ function() return __TS__New(Map) end
169
+ )
170
+ end
134
171
  return ____exports
@@ -39,7 +39,7 @@ export declare function enableAllInputsExceptFor(key: string, blacklist: Set<But
39
39
  * that multiple mod features can work in tandem.
40
40
  * @param whitelist A set of ButtonActions to allow.
41
41
  */
42
- export declare function disableAllInputsExceptFor(key: string, whitelist: Set<ButtonAction>): void;
42
+ export declare function disableAllInputsExceptFor(key: string, whitelist: Set<ButtonAction> | ReadonlySet<ButtonAction>): void;
43
43
  /**
44
44
  * Helper function to disable only the inputs used for moving the character (or moving the cursor in
45
45
  * the UI). This is useful because `EntityPlayer.ControlsEnabled` can be changed by the game under
@@ -1 +1 @@
1
- {"version":3,"file":"disableInputs.d.ts","sourceRoot":"","sources":["../../src/features/disableInputs.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EAGb,MAAM,8BAA8B,CAAC;AAuBtC,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAoBhD;AA+CD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAKjD;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAKlD;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,WAAW,CAAC,YAAY,CAAC,GACvD,IAAI,CAKN;AAED;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,GAAG,CAAC,YAAY,CAAC,GAC3B,IAAI,CAKN;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAGvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAGvD"}
1
+ {"version":3,"file":"disableInputs.d.ts","sourceRoot":"","sources":["../../src/features/disableInputs.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EAGb,MAAM,8BAA8B,CAAC;AAiBtC,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAoBhD;AA+CD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAKjD;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAKlD;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,WAAW,CAAC,YAAY,CAAC,GACvD,IAAI,CAKN;AAED;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,WAAW,CAAC,YAAY,CAAC,GACvD,IAAI,CAKN;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAGvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAGvD"}
@@ -60,12 +60,7 @@ end
60
60
  local FEATURE_NAME = "runInNFrames"
61
61
  v = {run = {queuedGameFunctionTuples = {}, queuedRenderFunctionTuples = {}, intervalGameFunctionTuples = {}, intervalRenderFunctionTuples = {}}}
62
62
  function ____exports.runInNFramesInit(self, mod)
63
- saveDataManager(
64
- nil,
65
- FEATURE_NAME,
66
- v,
67
- function() return false end
68
- )
63
+ saveDataManager(nil, FEATURE_NAME, v, false)
69
64
  mod:AddCallback(ModCallback.POST_UPDATE, postUpdate)
70
65
  mod:AddCallback(ModCallback.POST_RENDER, postRender)
71
66
  end
@@ -17,12 +17,7 @@ end
17
17
  local FEATURE_NAME = "runNextRoom"
18
18
  v = {run = {queuedFunctions = {}}}
19
19
  function ____exports.runNextRoomInit(self, mod)
20
- saveDataManager(
21
- nil,
22
- FEATURE_NAME,
23
- v,
24
- function() return false end
25
- )
20
+ saveDataManager(nil, FEATURE_NAME, v, false)
26
21
  mod:AddCallbackCustom(ModCallbackCustom.POST_NEW_ROOM_REORDERED, postNewRoomReordered)
27
22
  end
28
23
  --- Supply a function to run on the next `POST_NEW_ROOM` callback.
@@ -92,7 +92,7 @@ import { SaveData } from "../../interfaces/SaveData";
92
92
  export declare function saveDataManager<Persistent, Run, Level>(key: string, // This is the overload for the standard case with serializable data.
93
93
  v: SaveData<Persistent, Run, Level>, conditionalFunc?: () => boolean): void;
94
94
  export declare function saveDataManager(key: string, // This is the overload for the case when saving data is disabled.
95
- v: SaveData<unknown, unknown, unknown>, conditionalFunc: false): void;
95
+ v: SaveData, conditionalFunc: false): void;
96
96
  /**
97
97
  * The save data manager will automatically load variables from disk at the appropriate times (i.e.
98
98
  * when a new run is started). Use this function to explicitly force the save data manager to load
@@ -1 +1 @@
1
- {"version":3,"file":"exports.d.ts","sourceRoot":"","sources":["../../../src/features/saveDataManager/exports.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAarD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyFG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,GAAG,EAAE,KAAK,EACpD,GAAG,EAAE,MAAM,EAAE,qEAAqE;AAClF,CAAC,EAAE,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE,KAAK,CAAC,EACnC,eAAe,CAAC,EAAE,MAAM,OAAO,GAC9B,IAAI,CAAC;AACR,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,EAAE,kEAAkE;AAC/E,CAAC,EAAE,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EACtC,eAAe,EAAE,KAAK,GACrB,IAAI,CAAC;AA+CR;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAG1C;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAG1C;AAQD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAK/C;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,MAAM,EACX,cAAc,EAAE,MAAM,GACrB,IAAI,CAiBN"}
1
+ {"version":3,"file":"exports.d.ts","sourceRoot":"","sources":["../../../src/features/saveDataManager/exports.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAarD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyFG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,GAAG,EAAE,KAAK,EACpD,GAAG,EAAE,MAAM,EAAE,qEAAqE;AAClF,CAAC,EAAE,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE,KAAK,CAAC,EACnC,eAAe,CAAC,EAAE,MAAM,OAAO,GAC9B,IAAI,CAAC;AACR,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,EAAE,kEAAkE;AAC/E,CAAC,EAAE,QAAQ,EACX,eAAe,EAAE,KAAK,GACrB,IAAI,CAAC;AA+CR;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAG1C;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAG1C;AAQD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAK/C;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,MAAM,EACX,cAAc,EAAE,MAAM,GACrB,IAAI,CAiBN"}
@@ -210,7 +210,7 @@ function deepCopyDefaultMap(self, defaultMap, serializationType, traversalDescri
210
210
  local constructorArg = ____isDefaultMap_result_0
211
211
  if serializationType == SerializationType.SERIALIZE and not isPrimitive(nil, constructorArg) then
212
212
  if insideMap then
213
- error("Failed to deep copy a DefaultMap because it was instantiated with a factory function and was also inside of another map. You cannot use a nested DefaultMap in this way because factory functions are not serializable. (In other words, there is no way to copy the function that you are using for the DefaultMap into the \"save#.dat\" file.) Instead, refactor your data structure so that the DefaultMap is not nested.")
213
+ error("Failed to deep copy a DefaultMap because it was instantiated with a factory function and was also inside of an array, map, or set. For more information, see: https://isaacscript.github.io/main/gotchas#failed-to-deep-copy-a-defaultmap")
214
214
  else
215
215
  return deepCopyMap(
216
216
  nil,
@@ -3,7 +3,6 @@
3
3
  /// <reference types="isaac-typescript-definitions" />
4
4
  /// <reference types="isaac-typescript-definitions" />
5
5
  /// <reference types="isaac-typescript-definitions" />
6
- import { AnyClass } from "../types";
7
6
  /**
8
7
  * This is the format of the object that you give to the save data manager. It will contains all of
9
8
  * the variables for the particular mod feature.
@@ -43,17 +42,28 @@ export interface SaveData<Persistent = unknown, Run = unknown, Level = unknown>
43
42
  * The recursive nature of this type is based on the `Immutable` type:
44
43
  * https://stackoverflow.com/questions/41879327/deepreadonly-object-typescript
45
44
  */
46
- declare type Serializable<T> = T extends SerializableIsaacAPIClass ? T : T extends IsaacAPIClass ? IsaacAPIClassIsNotSerializable : T extends SerializablePrimitive ? T : T extends Array<infer U> ? SerializableArray<U> : T extends Map<infer K, infer V> ? SerializableMap<K, V> : T extends Set<infer M> ? SerializableSet<M> : SerializableObject<T>;
47
- declare type SerializableInsideArrayOrMap<T> = T extends AnyClass ? CustomClassIsNotSerializable : Serializable<T>;
45
+ declare type Serializable<T> = T extends SerializablePrimitive ? T : T extends SerializableIsaacAPIClass ? T : T extends IsaacAPIClass ? ErrorIsaacAPIClassIsNotSerializable : T extends Array<infer U> ? SerializableArray<U> : T extends ReadonlyArray<infer U> ? SerializableReadonlyArray<U> : T extends Map<infer K, infer V> ? SerializableMap<K, V> : T extends ReadonlyMap<infer K, infer V> ? SerializableReadonlyMap<K, V> : T extends Set<infer V> ? SerializableSet<V> : T extends ReadonlySet<infer V> ? SerializableReadonlySet<V> : SerializableObject<T>;
46
+ /**
47
+ * This is mostly copied from the `Serializable` type. The difference is that we want to disallow
48
+ * classes with methods.
49
+ */
50
+ declare type SerializableInsideArrayOrMap<T> = T extends SerializablePrimitive ? T : T extends SerializableIsaacAPIClass ? T : T extends IsaacAPIClass ? ErrorIsaacAPIClassIsNotSerializable : T extends Array<infer U> ? SerializableArray<U> : T extends ReadonlyArray<infer U> ? SerializableReadonlyArray<U> : T extends Map<infer K, infer V> ? SerializableMap<K, V> : T extends ReadonlyMap<infer K, infer V> ? SerializableReadonlyMap<K, V> : T extends Set<infer V> ? SerializableSet<V> : T extends ReadonlySet<infer V> ? SerializableReadonlySet<V> : T extends HasMethods<T> ? ErrorCustomClassNotSerializable : T extends Function ? FunctionIsNotSerializable : SerializableObject<T>;
48
51
  declare type SerializablePrimitive = boolean | string | number | undefined | null;
49
52
  declare type SerializableArray<T> = Array<SerializableInsideArrayOrMap<T>>;
53
+ declare type SerializableReadonlyArray<T> = ReadonlyArray<SerializableInsideArrayOrMap<T>>;
50
54
  declare type SerializableMap<K, V> = Map<SerializableInsideArrayOrMap<K>, SerializableInsideArrayOrMap<V>>;
55
+ declare type SerializableReadonlyMap<K, V> = ReadonlyMap<SerializableInsideArrayOrMap<K>, SerializableInsideArrayOrMap<V>>;
51
56
  declare type SerializableSet<T> = Set<SerializableInsideArrayOrMap<T>>;
57
+ declare type SerializableReadonlySet<T> = ReadonlySet<SerializableInsideArrayOrMap<T>>;
52
58
  declare type SerializableObject<T> = {
53
59
  [K in keyof T]: Serializable<T[K]>;
54
60
  };
55
61
  declare type SerializableIsaacAPIClass = Color | KColor | RNG | Vector;
56
- declare type IsaacAPIClassIsNotSerializable = "Error: Isaac API classes (such as e.g. `Entity` or `RoomConfig`) are not serializable. For more information, see: https://isaacscript.github.io/main/gotchas#isaac-api-classes-are-not-serializable";
57
- declare type CustomClassIsNotSerializable = 'Error: The "DefaultMap" class and other custom classes are not serializable when they are placed inside of an array, map, or set. For more information, see: https://isaacscript.github.io/main/gotchas#defaultmap-and-other-custom-classes-are-not-serializable';
62
+ declare type HasMethods<T> = {} extends {
63
+ [K in keyof T as T[K] extends Function ? K : never]-?: 1;
64
+ } ? never : T;
65
+ declare type FunctionIsNotSerializable = "Error: Functions are not serializable. For more information, see: https://isaacscript.github.io/main/gotchas#functions-are-not-serializable";
66
+ declare type ErrorIsaacAPIClassIsNotSerializable = "Error: Isaac API classes (such as e.g. `Entity` or `RoomConfig`) are not serializable. For more information, see: https://isaacscript.github.io/main/gotchas#isaac-api-classes-are-not-serializable";
67
+ declare type ErrorCustomClassNotSerializable = "Error: Custom classes with one or more methods are not serializable when inside of an array, map, or set. For more information, see: https://isaacscript.github.io/main/gotchas#custom-classes-are-not-serializable";
58
68
  export {};
59
69
  //# sourceMappingURL=SaveData.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SaveData.d.ts","sourceRoot":"","sources":["../../src/interfaces/SaveData.ts"],"names":[],"mappings":";;;;;AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,WAAW,QAAQ,CACvB,UAAU,GAAG,OAAO,EACpB,GAAG,GAAG,OAAO,EACb,KAAK,GAAG,OAAO;IAEf,UAAU,CAAC,EAAE,YAAY,CAAC,UAAU,CAAC,CAAC;IACtC,GAAG,CAAC,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC;IACxB,KAAK,CAAC,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED;;;;;;;GAOG;AACH,aAAK,YAAY,CAAC,CAAC,IAAI,CAAC,SAAS,yBAAyB,GACtD,CAAC,GACD,CAAC,SAAS,aAAa,GACvB,8BAA8B,GAC9B,CAAC,SAAS,qBAAqB,GAC/B,CAAC,GACD,CAAC,SAAS,KAAK,CAAC,MAAM,CAAC,CAAC,GACxB,iBAAiB,CAAC,CAAC,CAAC,GACpB,CAAC,SAAS,GAAG,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,GAC/B,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,GACrB,CAAC,SAAS,GAAG,CAAC,MAAM,CAAC,CAAC,GACtB,eAAe,CAAC,CAAC,CAAC,GAClB,kBAAkB,CAAC,CAAC,CAAC,CAAC;AAE1B,aAAK,4BAA4B,CAAC,CAAC,IAAI,CAAC,SAAS,QAAQ,GACrD,4BAA4B,GAC5B,YAAY,CAAC,CAAC,CAAC,CAAC;AAEpB,aAAK,qBAAqB,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;AAC1E,aAAK,iBAAiB,CAAC,CAAC,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC,CAAC,CAAC,CAAC;AACnE,aAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,GAAG,CAC9B,4BAA4B,CAAC,CAAC,CAAC,EAC/B,4BAA4B,CAAC,CAAC,CAAC,CAChC,CAAC;AACF,aAAK,eAAe,CAAC,CAAC,IAAI,GAAG,CAAC,4BAA4B,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/D,aAAK,kBAAkB,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,CAAC;AACpE,aAAK,yBAAyB,GAAG,KAAK,GAAG,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC;AAE/D,aAAK,8BAA8B,GACjC,qMAAqM,CAAC;AAExM,aAAK,4BAA4B,GAC/B,kQAAkQ,CAAC"}
1
+ {"version":3,"file":"SaveData.d.ts","sourceRoot":"","sources":["../../src/interfaces/SaveData.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,68 @@
1
+ local ____lualib = require("lualib_bundle")
2
+ local Map = ____lualib.Map
3
+ local __TS__New = ____lualib.__TS__New
4
+ local __TS__Class = ____lualib.__TS__Class
1
5
  local ____exports = {}
6
+ local function test(self, _saveData)
7
+ end
8
+ do
9
+ local saveDataWithPrimitives = {run = {foo = 123, bar = "bar", baz = true, nested = {foo = 123, bar = "bar", baz = true}}}
10
+ test(nil, saveDataWithPrimitives)
11
+ end
12
+ do
13
+ local saveDataWithEntity = {run = {foo = {}}}
14
+ test(nil, saveDataWithEntity)
15
+ end
16
+ do
17
+ local saveDataWithMap = {run = {foo = __TS__New(Map)}}
18
+ test(nil, saveDataWithMap)
19
+ end
20
+ do
21
+ local saveDataWithMap = {run = {foo = __TS__New(Map)}}
22
+ test(nil, saveDataWithMap)
23
+ end
24
+ do
25
+ local saveDataWithMap = {run = {foo = __TS__New(Map)}}
26
+ test(nil, saveDataWithMap)
27
+ end
28
+ do
29
+ local Foo = __TS__Class()
30
+ Foo.name = "Foo"
31
+ function Foo.prototype.____constructor(self)
32
+ self.someField = 123
33
+ end
34
+ local saveDataWithClass = {run = {foo = __TS__New(Foo)}}
35
+ test(nil, saveDataWithClass)
36
+ end
37
+ do
38
+ local Foo = __TS__Class()
39
+ Foo.name = "Foo"
40
+ function Foo.prototype.____constructor(self)
41
+ self.someField = 123
42
+ end
43
+ function Foo.prototype.someMethod(self)
44
+ end
45
+ local saveDataWithClassWithMethod = {run = {foo = __TS__New(Foo)}}
46
+ test(nil, saveDataWithClassWithMethod)
47
+ end
48
+ do
49
+ local Foo = __TS__Class()
50
+ Foo.name = "Foo"
51
+ function Foo.prototype.____constructor(self)
52
+ self.someField = 123
53
+ end
54
+ local saveDataWithNestedClass = {run = {fooMap = __TS__New(Map)}}
55
+ test(nil, saveDataWithNestedClass)
56
+ end
57
+ do
58
+ local Foo = __TS__Class()
59
+ Foo.name = "Foo"
60
+ function Foo.prototype.____constructor(self)
61
+ self.someField = 123
62
+ end
63
+ function Foo.prototype.someMethod(self)
64
+ end
65
+ local saveDataWithNestedClass = {run = {fooMap = __TS__New(Map)}}
66
+ test(nil, saveDataWithNestedClass)
67
+ end
2
68
  return ____exports
@@ -1,4 +1,3 @@
1
- export * from "./AnyClass";
2
1
  export * from "./AnyEntity";
3
2
  export * from "./AnyGridEntity";
4
3
  export * from "./CollectibleIndex";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "isaacscript-common",
3
- "version": "6.23.0",
3
+ "version": "7.0.0",
4
4
  "description": "Helper functions and features for IsaacScript mods.",
5
5
  "keywords": [
6
6
  "isaac",
@@ -5,9 +5,7 @@ import { isFunction, isPrimitive } from "../functions/types";
5
5
  * A function that creates the default value for your `DefaultMap`. For example, if it was a
6
6
  * `DefaultMap` containing maps, the factory function would be: `() => new Map()`
7
7
  */
8
- export type FactoryFunction<V, Args extends unknown[]> = (
9
- ...extraArgs: Args
10
- ) => V;
8
+ export type FactoryFunction<V, Args extends unknown[]> = (...args: Args) => V;
11
9
 
12
10
  /**
13
11
  * `DefaultMap` is a data structure that makes working with default values easier.
@@ -127,13 +125,13 @@ export class DefaultMap<Key, Value, Args extends unknown[] = []> extends Map<
127
125
  * If the key exists, this will return the same thing as the normal `Map.get` method. Otherwise,
128
126
  * it will set a default value for the provided key, and then return the default value.
129
127
  */
130
- getAndSetDefault(key: Key, ...extraArgs: Args): Value {
128
+ getAndSetDefault(key: Key, ...args: Args): Value {
131
129
  const value = super.get(key);
132
130
  if (value !== undefined) {
133
131
  return value;
134
132
  }
135
133
 
136
- const defaultValue = this.getDefaultValue(...extraArgs);
134
+ const defaultValue = this.getDefaultValue(...args);
137
135
  this.set(key, defaultValue);
138
136
  return defaultValue;
139
137
  }
@@ -142,13 +140,13 @@ export class DefaultMap<Key, Value, Args extends unknown[] = []> extends Map<
142
140
  * Returns the default value to be used for a new key. (If a factory function was provided during
143
141
  * instantiation, this will execute the factory function.)
144
142
  */
145
- getDefaultValue(...extraArgs: Args): Value {
143
+ getDefaultValue(...args: Args): Value {
146
144
  if (this.defaultValue !== undefined) {
147
145
  return this.defaultValue;
148
146
  }
149
147
 
150
148
  if (this.defaultValueFactory !== undefined) {
151
- return this.defaultValueFactory(...extraArgs);
149
+ return this.defaultValueFactory(...args);
152
150
  }
153
151
 
154
152
  error("A DefaultMap was incorrectly instantiated.");
@@ -170,3 +168,34 @@ export class DefaultMap<Key, Value, Args extends unknown[] = []> extends Map<
170
168
  error("A DefaultMap was incorrectly instantiated.");
171
169
  }
172
170
  }
171
+
172
+ /* eslint-disable @typescript-eslint/no-unused-vars */
173
+ function test() {
174
+ // Boolean
175
+ const myDefaultMapBoolean = new DefaultMap<string, boolean>(false);
176
+ const myDefaultMapBooleanFactory = new DefaultMap<string, boolean>(
177
+ () => false,
178
+ );
179
+ const myDefaultMapBooleanWithoutParams = new DefaultMap(false);
180
+
181
+ // Number
182
+ const myDefaultMapNumber = new DefaultMap<string, number>(123);
183
+ const myDefaultMapNumberFactory = new DefaultMap<string, number>(() => 123);
184
+ const myDefaultMapNumberWithoutParams = new DefaultMap(123);
185
+
186
+ // String
187
+ const myDefaultMapString = new DefaultMap<string, string>("foo");
188
+ const myDefaultMapStringFactory = new DefaultMap<string, string>(() => "foo");
189
+ const myDefaultMapStringWithoutParams = new DefaultMap("foo");
190
+
191
+ // Array
192
+ const myDefaultMapArray = new DefaultMap<string, string[]>(() => []);
193
+ const myDefaultMapArrayWithoutParams = new DefaultMap(() => []);
194
+
195
+ // Map
196
+ const myDefaultMapMap = new DefaultMap<string, Map<string, string>>(
197
+ () => new Map(),
198
+ );
199
+ const myDefaultMapMapWithoutParams = new DefaultMap(() => new Map());
200
+ }
201
+ /* eslint-enable @typescript-eslint/no-unused-vars */
@@ -12,16 +12,10 @@ const FEATURE_NAME = "disableInputs";
12
12
  const v = {
13
13
  run: {
14
14
  /** Indexed by the requesting feature key. */
15
- disableInputsWithWhitelistMap: new Map<
16
- string,
17
- Set<ButtonAction> | ReadonlySet<ButtonAction>
18
- >(),
15
+ disableInputsWithWhitelistMap: new Map<string, ReadonlySet<ButtonAction>>(),
19
16
 
20
17
  /** Indexed by the requesting feature key. */
21
- enableInputsWithBlacklistMap: new Map<
22
- string,
23
- Set<ButtonAction> | ReadonlySet<ButtonAction>
24
- >(),
18
+ enableInputsWithBlacklistMap: new Map<string, ReadonlySet<ButtonAction>>(),
25
19
  },
26
20
  };
27
21
 
@@ -154,7 +148,7 @@ export function enableAllInputsExceptFor(
154
148
  */
155
149
  export function disableAllInputsExceptFor(
156
150
  key: string,
157
- whitelist: Set<ButtonAction>,
151
+ whitelist: Set<ButtonAction> | ReadonlySet<ButtonAction>,
158
152
  ): void {
159
153
  errorIfFeaturesNotInitialized(FEATURE_NAME);
160
154
 
@@ -31,7 +31,7 @@ const v = {
31
31
  };
32
32
 
33
33
  export function runInNFramesInit(mod: Mod): void {
34
- saveDataManager(FEATURE_NAME, v, () => false); // Functions are not serializable.
34
+ saveDataManager(FEATURE_NAME, v, false); // Functions are not serializable.
35
35
 
36
36
  mod.AddCallback(ModCallback.POST_UPDATE, postUpdate); // 1
37
37
  mod.AddCallback(ModCallback.POST_RENDER, postRender); // 2
@@ -13,7 +13,7 @@ const v = {
13
13
  };
14
14
 
15
15
  export function runNextRoomInit(mod: ModUpgraded): void {
16
- saveDataManager(FEATURE_NAME, v, () => false); // Functions are not serializable.
16
+ saveDataManager(FEATURE_NAME, v, false); // Functions are not serializable.
17
17
 
18
18
  mod.AddCallbackCustom(
19
19
  ModCallbackCustom.POST_NEW_ROOM_REORDERED,
@@ -113,7 +113,7 @@ export function saveDataManager<Persistent, Run, Level>(
113
113
  ): void;
114
114
  export function saveDataManager(
115
115
  key: string, // This is the overload for the case when saving data is disabled.
116
- v: SaveData<unknown, unknown, unknown>,
116
+ v: SaveData,
117
117
  conditionalFunc: false,
118
118
  ): void;
119
119
  export function saveDataManager<Persistent, Run, Level>(
@@ -233,7 +233,7 @@ function deepCopyDefaultMap(
233
233
  // throw a run-time error to immediately alert the end-user that their data structure is
234
234
  // invalid.
235
235
  error(
236
- 'Failed to deep copy a DefaultMap because it was instantiated with a factory function and was also inside of another map. You cannot use a nested DefaultMap in this way because factory functions are not serializable. (In other words, there is no way to copy the function that you are using for the DefaultMap into the "save#.dat" file.) Instead, refactor your data structure so that the DefaultMap is not nested.',
236
+ "Failed to deep copy a DefaultMap because it was instantiated with a factory function and was also inside of an array, map, or set. For more information, see: https://isaacscript.github.io/main/gotchas#failed-to-deep-copy-a-defaultmap",
237
237
  );
238
238
  } else {
239
239
  // In most cases, the DefaultMap will be attached to a normal table element. In this case, if
@@ -1,4 +1,4 @@
1
- import { AnyClass } from "../types";
1
+ /* eslint-disable max-classes-per-file */
2
2
 
3
3
  /**
4
4
  * This is the format of the object that you give to the save data manager. It will contains all of
@@ -44,36 +44,238 @@ export interface SaveData<
44
44
  * The recursive nature of this type is based on the `Immutable` type:
45
45
  * https://stackoverflow.com/questions/41879327/deepreadonly-object-typescript
46
46
  */
47
- type Serializable<T> = T extends SerializableIsaacAPIClass
48
- ? T
49
- : T extends IsaacAPIClass
50
- ? IsaacAPIClassIsNotSerializable
51
- : T extends SerializablePrimitive
52
- ? T
53
- : T extends Array<infer U>
54
- ? SerializableArray<U>
55
- : T extends Map<infer K, infer V>
56
- ? SerializableMap<K, V>
57
- : T extends Set<infer M>
58
- ? SerializableSet<M>
59
- : SerializableObject<T>;
60
-
61
- type SerializableInsideArrayOrMap<T> = T extends AnyClass
62
- ? CustomClassIsNotSerializable
63
- : Serializable<T>;
47
+ type Serializable<T> =
48
+ // Allow the trivial case of primitives.
49
+ T extends SerializablePrimitive
50
+ ? T
51
+ : // Allow a specific subset of Isaac API classes that are copyable / serializable.
52
+ T extends SerializableIsaacAPIClass
53
+ ? T
54
+ : // Disallow all other Isaac API classes.
55
+ T extends IsaacAPIClass
56
+ ? ErrorIsaacAPIClassIsNotSerializable
57
+ : // Allow some specific "container" objects.
58
+ // These container objects are explicitly handled by the save data manager, but there are
59
+ // restrictions on the things inside of them.
60
+ T extends Array<infer U>
61
+ ? SerializableArray<U>
62
+ : T extends ReadonlyArray<infer U>
63
+ ? SerializableReadonlyArray<U>
64
+ : T extends Map<infer K, infer V>
65
+ ? SerializableMap<K, V>
66
+ : T extends ReadonlyMap<infer K, infer V>
67
+ ? SerializableReadonlyMap<K, V>
68
+ : T extends Set<infer V>
69
+ ? SerializableSet<V>
70
+ : T extends ReadonlySet<infer V>
71
+ ? SerializableReadonlySet<V>
72
+ : // Allow any other object, as long as the values are themselves serializable.
73
+ SerializableObject<T>;
74
+
75
+ /**
76
+ * This is mostly copied from the `Serializable` type. The difference is that we want to disallow
77
+ * classes with methods.
78
+ */
79
+ type SerializableInsideArrayOrMap<T> =
80
+ // Allow the trivial case of primitives.
81
+ T extends SerializablePrimitive
82
+ ? T
83
+ : // Allow a specific subset of Isaac API classes that are copyable / serializable.
84
+ T extends SerializableIsaacAPIClass
85
+ ? T
86
+ : // Disallow all other Isaac API classes.
87
+ T extends IsaacAPIClass
88
+ ? ErrorIsaacAPIClassIsNotSerializable
89
+ : // Allow some specific "container" objects.
90
+ // These container objects are explicitly handled by the save data manager, but there are
91
+ // restrictions on the things inside of them.
92
+ T extends Array<infer U>
93
+ ? SerializableArray<U>
94
+ : T extends ReadonlyArray<infer U>
95
+ ? SerializableReadonlyArray<U>
96
+ : T extends Map<infer K, infer V>
97
+ ? SerializableMap<K, V>
98
+ : T extends ReadonlyMap<infer K, infer V>
99
+ ? SerializableReadonlyMap<K, V>
100
+ : T extends Set<infer V>
101
+ ? SerializableSet<V>
102
+ : T extends ReadonlySet<infer V>
103
+ ? SerializableReadonlySet<V>
104
+ : // Disallow objects with functions on them (i.e. classes with methods).
105
+ // (This has to be after allowing maps and sets, because those have functions inside of them.)
106
+ T extends HasMethods<T>
107
+ ? ErrorCustomClassNotSerializable
108
+ : // Disallow functions.
109
+ // (We can only disallow functions when inside of containers, because we want to allow classes
110
+ // with methods attached to normal objects.)
111
+ T extends Function // eslint-disable-line @typescript-eslint/ban-types
112
+ ? FunctionIsNotSerializable
113
+ : // Finally, allow any other object, as long as the values are themselves serializable.
114
+ SerializableObject<T>;
64
115
 
65
116
  type SerializablePrimitive = boolean | string | number | undefined | null;
66
117
  type SerializableArray<T> = Array<SerializableInsideArrayOrMap<T>>;
118
+ type SerializableReadonlyArray<T> = ReadonlyArray<
119
+ SerializableInsideArrayOrMap<T>
120
+ >;
67
121
  type SerializableMap<K, V> = Map<
68
122
  SerializableInsideArrayOrMap<K>,
69
123
  SerializableInsideArrayOrMap<V>
70
124
  >;
125
+ type SerializableReadonlyMap<K, V> = ReadonlyMap<
126
+ SerializableInsideArrayOrMap<K>,
127
+ SerializableInsideArrayOrMap<V>
128
+ >;
71
129
  type SerializableSet<T> = Set<SerializableInsideArrayOrMap<T>>;
130
+ type SerializableReadonlySet<T> = ReadonlySet<SerializableInsideArrayOrMap<T>>;
72
131
  type SerializableObject<T> = { [K in keyof T]: Serializable<T[K]> };
73
132
  type SerializableIsaacAPIClass = Color | KColor | RNG | Vector;
74
133
 
75
- type IsaacAPIClassIsNotSerializable =
134
+ // eslint-disable-next-line @typescript-eslint/ban-types
135
+ type HasMethods<T> = {} extends {
136
+ // eslint-disable-next-line @typescript-eslint/ban-types
137
+ [K in keyof T as T[K] extends Function ? K : never]-?: 1;
138
+ }
139
+ ? never
140
+ : T;
141
+
142
+ type FunctionIsNotSerializable =
143
+ "Error: Functions are not serializable. For more information, see: https://isaacscript.github.io/main/gotchas#functions-are-not-serializable";
144
+
145
+ type ErrorIsaacAPIClassIsNotSerializable =
76
146
  "Error: Isaac API classes (such as e.g. `Entity` or `RoomConfig`) are not serializable. For more information, see: https://isaacscript.github.io/main/gotchas#isaac-api-classes-are-not-serializable";
77
147
 
78
- type CustomClassIsNotSerializable =
79
- 'Error: The "DefaultMap" class and other custom classes are not serializable when they are placed inside of an array, map, or set. For more information, see: https://isaacscript.github.io/main/gotchas#defaultmap-and-other-custom-classes-are-not-serializable';
148
+ type ErrorCustomClassNotSerializable =
149
+ "Error: Custom classes with one or more methods are not serializable when inside of an array, map, or set. For more information, see: https://isaacscript.github.io/main/gotchas#custom-classes-are-not-serializable";
150
+
151
+ // -----
152
+ // Tests
153
+ // -----
154
+
155
+ function test<Persistent, Run, Level>(
156
+ _saveData: SaveData<Persistent, Run, Level>,
157
+ ) {}
158
+
159
+ {
160
+ const saveDataWithPrimitives = {
161
+ run: {
162
+ foo: 123,
163
+ bar: "bar",
164
+ baz: true,
165
+ nested: {
166
+ foo: 123,
167
+ bar: "bar",
168
+ baz: true,
169
+ },
170
+ },
171
+ };
172
+
173
+ // Primitives and nested primitives are allowed.
174
+ test(saveDataWithPrimitives);
175
+ }
176
+
177
+ {
178
+ const saveDataWithEntity = {
179
+ run: {
180
+ foo: {} as Entity,
181
+ },
182
+ };
183
+
184
+ // @ts-expect-error Isaac API classes are not serializable.
185
+ test(saveDataWithEntity);
186
+ }
187
+
188
+ {
189
+ const saveDataWithMap = {
190
+ run: {
191
+ foo: new Map<string, string>(),
192
+ },
193
+ };
194
+
195
+ // Maps with primitive values are allowed.
196
+ test(saveDataWithMap);
197
+ }
198
+
199
+ {
200
+ const saveDataWithMap = {
201
+ run: {
202
+ foo: new Map<string, () => void>(),
203
+ },
204
+ };
205
+
206
+ // @ts-expect-error Maps with function values are not serializable.
207
+ test(saveDataWithMap);
208
+ }
209
+
210
+ {
211
+ const saveDataWithMap = {
212
+ run: {
213
+ foo: new Map<string, Map<string, string>>(),
214
+ },
215
+ };
216
+
217
+ // Nested maps are allowed.
218
+ test(saveDataWithMap);
219
+ }
220
+
221
+ {
222
+ class Foo {
223
+ someField = 123;
224
+ }
225
+
226
+ const saveDataWithClass = {
227
+ run: {
228
+ foo: new Foo(),
229
+ },
230
+ };
231
+
232
+ // Custom classes without methods are allowed.
233
+ test(saveDataWithClass);
234
+ }
235
+
236
+ {
237
+ class Foo {
238
+ someField = 123;
239
+ someMethod() {} // eslint-disable-line class-methods-use-this
240
+ }
241
+
242
+ const saveDataWithClassWithMethod = {
243
+ run: {
244
+ foo: new Foo(),
245
+ },
246
+ };
247
+
248
+ // Custom classes with methods are allowed.
249
+ test(saveDataWithClassWithMethod);
250
+ }
251
+
252
+ {
253
+ class Foo {
254
+ someField = 123;
255
+ }
256
+
257
+ const saveDataWithNestedClass = {
258
+ run: {
259
+ fooMap: new Map<string, Foo>(),
260
+ },
261
+ };
262
+
263
+ // Nested custom classes without methods are allowed.
264
+ test(saveDataWithNestedClass);
265
+ }
266
+
267
+ {
268
+ class Foo {
269
+ someField = 123;
270
+ someMethod() {} // eslint-disable-line class-methods-use-this
271
+ }
272
+
273
+ const saveDataWithNestedClass = {
274
+ run: {
275
+ fooMap: new Map<string, Foo>(),
276
+ },
277
+ };
278
+
279
+ // @ts-expect-error Nested custom classes with methods are not serializable.
280
+ test(saveDataWithNestedClass);
281
+ }
@@ -1,4 +1,3 @@
1
- export * from "./AnyClass";
2
1
  export * from "./AnyEntity";
3
2
  export * from "./AnyGridEntity";
4
3
  export * from "./CollectibleIndex";
@@ -1,4 +1,3 @@
1
- export * as AnyClass from "./AnyClass";
2
1
  export * as AnyEntity from "./AnyEntity";
3
2
  export * as AnyGridEntity from "./AnyGridEntity";
4
3
  export * as CollectibleIndex from "./CollectibleIndex";
@@ -1,2 +0,0 @@
1
- export declare type AnyClass = new (...args: readonly unknown[]) => unknown;
2
- //# sourceMappingURL=AnyClass.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AnyClass.d.ts","sourceRoot":"","sources":["../../src/types/AnyClass.ts"],"names":[],"mappings":"AAAA,oBAAY,QAAQ,GAAG,KAAK,GAAG,IAAI,EAAE,SAAS,OAAO,EAAE,KAAK,OAAO,CAAC"}
@@ -1,2 +0,0 @@
1
- local ____exports = {}
2
- return ____exports
@@ -1 +0,0 @@
1
- export type AnyClass = new (...args: readonly unknown[]) => unknown;