mobx-keystone 2.1.0 → 2.2.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/CHANGELOG.md +11 -0
- package/README.md +1 -1
- package/dist/mobx-keystone.esm.js +275 -489
- package/dist/mobx-keystone.esm.mjs +275 -489
- package/dist/mobx-keystone.umd.js +274 -492
- package/dist/types/actionMiddlewares/undoMiddleware.d.ts +2 -10
- package/dist/types/modelShared/modelDecorator.d.ts +5 -2
- package/dist/types/modelShared/prop.d.ts +42 -29
- package/dist/types/ref/Ref.d.ts +1 -4
- package/dist/types/snapshot/SnapshotOf.d.ts +4 -4
- package/dist/types/snapshot/applySnapshot.d.ts +1 -1
- package/dist/types/snapshot/fromSnapshot.d.ts +2 -2
- package/dist/types/snapshot/getSnapshot.d.ts +1 -1
- package/dist/types/types/index.d.ts +1 -0
- package/dist/types/types/schemas.d.ts +41 -37
- package/dist/types/types/tProp.d.ts +12 -6
- package/dist/types/types/types.d.ts +6 -6
- package/dist/types/types/utility/typeToStoredData.d.ts +14 -10
- package/dist/types/types/utility/typesCodecCore.d.ts +3 -0
- package/dist/types/utils/ModelPool.d.ts +0 -1
- package/dist/types/utils/types.d.ts +6 -0
- package/dist/types/wrappers/ArraySet.d.ts +1 -0
- package/package.json +4 -2
- package/src/action/modelFlow.ts +35 -66
- package/src/actionMiddlewares/actionTrackingMiddleware.ts +41 -71
- package/src/actionMiddlewares/transactionMiddleware.ts +1 -1
- package/src/actionMiddlewares/undoMiddleware.ts +16 -22
- package/src/context/context.ts +15 -36
- package/src/dataModel/utils.ts +5 -28
- package/src/deepChange/onDeepChange.ts +44 -126
- package/src/model/BaseModel.ts +1 -1
- package/src/model/utils.ts +5 -10
- package/src/modelShared/modelDecorator.ts +11 -5
- package/src/modelShared/prop.ts +115 -111
- package/src/modelShared/sharedInternalModel.ts +2 -2
- package/src/parent/arrayPaths.ts +1 -4
- package/src/parent/path.ts +0 -10
- package/src/patch/patchRecorder.ts +13 -28
- package/src/ref/core.ts +6 -19
- package/src/rootStore/rootStore.ts +1 -3
- package/src/snapshot/SnapshotOf.ts +24 -48
- package/src/snapshot/applySnapshot.ts +1 -1
- package/src/snapshot/fromSnapshot.ts +10 -3
- package/src/snapshot/getSnapshot.ts +1 -1
- package/src/snapshot/internal.ts +0 -2
- package/src/snapshot/reconcileModelSnapshot.ts +5 -3
- package/src/snapshot/reconcilePlainObjectSnapshot.ts +3 -1
- package/src/treeUtils/draft.ts +6 -1
- package/src/treeUtils/sandbox.ts +10 -7
- package/src/tweaker/tweakArray.ts +20 -50
- package/src/tweaker/tweakPlainObject.ts +9 -15
- package/src/types/arrayBased/typesArray.ts +13 -19
- package/src/types/arrayBased/typesTuple.ts +16 -25
- package/src/types/createCachedTypeCheck.ts +17 -30
- package/src/types/index.ts +1 -0
- package/src/types/objectBased/typesDataModelData.ts +7 -8
- package/src/types/objectBased/typesObject.ts +11 -15
- package/src/types/objectBased/typesRecord.ts +11 -15
- package/src/types/schemas.ts +59 -71
- package/src/types/tProp.ts +29 -29
- package/src/types/utility/typeToStoredData.ts +22 -21
- package/src/types/utility/typesCodecCore.ts +5 -0
- package/src/types/utility/typesCodecSupport.ts +3 -3
- package/src/types/utility/typesMap.ts +43 -51
- package/src/types/utility/typesRefinement.ts +7 -8
- package/src/types/utility/typesSkipCheck.ts +7 -8
- package/src/types/utility/typesTag.ts +7 -8
- package/src/utils/ModelPool.ts +1 -18
- package/src/utils/decorators.ts +5 -5
- package/src/utils/index.ts +1 -20
- package/src/utils/types.ts +5 -0
- package/src/wrappers/ArraySet.ts +27 -14
- package/src/wrappers/ObjectMap.ts +1 -6
- package/src/wrappers/asMap.ts +1 -21
- package/src/wrappers/asSet.ts +0 -8
|
@@ -45,6 +45,11 @@ type CodecConfig<TEncodedType extends AnyType, TRuntime> = {
|
|
|
45
45
|
is(value: unknown): value is TRuntime
|
|
46
46
|
} & ModelPropTransform<TypeToData<TEncodedType>, TRuntime>
|
|
47
47
|
|
|
48
|
+
// exported (and publicly re-exported) so emitted declaration files can reference it by name
|
|
49
|
+
// instead of expanding it inline in every exported model class, which is much slower and larger
|
|
50
|
+
/**
|
|
51
|
+
* A codec type whose snapshot and stored forms are those of its encoded type.
|
|
52
|
+
*/
|
|
48
53
|
export type CodecFromEncoded<TEncodedType extends AnyType, TRuntime> = CodecType<
|
|
49
54
|
TRuntime,
|
|
50
55
|
TypeToSnapshotIn<TEncodedType>,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isObservableArray, isObservableObject, remove } from "mobx"
|
|
2
2
|
import type { ModelPropTransform } from "../../modelShared/prop"
|
|
3
|
-
import { copyOwnEnumerableProps, isArray, isObject, lazy } from "../../utils"
|
|
3
|
+
import { copyOwnEnumerableProps, hasOwnProp, isArray, isObject, lazy } from "../../utils"
|
|
4
4
|
import { setIfDifferent } from "../../utils/setIfDifferent"
|
|
5
5
|
import { ArrayTypeInfo, typesArray } from "../arrayBased/typesArray"
|
|
6
6
|
import { TupleTypeInfo, typesTuple } from "../arrayBased/typesTuple"
|
|
@@ -136,7 +136,7 @@ function createObjectRuntimeAdapter(
|
|
|
136
136
|
get(target, prop, receiver) {
|
|
137
137
|
if (typeof prop === "string") {
|
|
138
138
|
const childSupport = getChildSupports()[prop]
|
|
139
|
-
if (childSupport &&
|
|
139
|
+
if (childSupport && hasOwnProp(target, prop)) {
|
|
140
140
|
return childSupport.adapter.toRuntime(target[prop], (newStoredValue) => {
|
|
141
141
|
target[prop] = newStoredValue
|
|
142
142
|
})
|
|
@@ -200,7 +200,7 @@ function createRecordRuntimeAdapter(
|
|
|
200
200
|
|
|
201
201
|
const proxy = new Proxy(stored, {
|
|
202
202
|
get(target, prop, receiver) {
|
|
203
|
-
if (typeof prop === "string" &&
|
|
203
|
+
if (typeof prop === "string" && hasOwnProp(target, prop)) {
|
|
204
204
|
const valueSupport = getValueSupport()
|
|
205
205
|
return valueSupport.adapter.toRuntime(target[prop], (newStoredValue) => {
|
|
206
206
|
target[prop] = newStoredValue
|
|
@@ -41,18 +41,14 @@ function makeMapProxy<TKeyStored, TKeyRuntime, TValueStored, TValueRuntime>(
|
|
|
41
41
|
return getValue(storedKey)
|
|
42
42
|
}
|
|
43
43
|
case "getOrInsert":
|
|
44
|
-
return (key: TKeyRuntime, defaultValue: TValueRuntime) => {
|
|
45
|
-
const storedKey = keyAdapter.toStored(key)
|
|
46
|
-
if (!target.has(storedKey)) {
|
|
47
|
-
target.set(storedKey, valueAdapter.toStored(defaultValue))
|
|
48
|
-
}
|
|
49
|
-
return getValue(storedKey)
|
|
50
|
-
}
|
|
51
44
|
case "getOrInsertComputed":
|
|
52
|
-
return (key: TKeyRuntime,
|
|
45
|
+
return (key: TKeyRuntime, valueOrCallback: unknown) => {
|
|
53
46
|
const storedKey = keyAdapter.toStored(key)
|
|
54
47
|
if (!target.has(storedKey)) {
|
|
55
|
-
const value =
|
|
48
|
+
const value =
|
|
49
|
+
prop === "getOrInsert"
|
|
50
|
+
? (valueOrCallback as TValueRuntime)
|
|
51
|
+
: (valueOrCallback as (key: TKeyRuntime) => TValueRuntime)(key)
|
|
56
52
|
target.set(storedKey, valueAdapter.toStored(value))
|
|
57
53
|
}
|
|
58
54
|
return getValue(storedKey)
|
|
@@ -114,10 +110,18 @@ function makeMapProxy<TKeyStored, TKeyRuntime, TValueStored, TValueRuntime>(
|
|
|
114
110
|
}) as unknown as Map<TKeyRuntime, TValueRuntime>
|
|
115
111
|
}
|
|
116
112
|
|
|
117
|
-
function
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
113
|
+
function makeMapTransform<
|
|
114
|
+
TStored extends object,
|
|
115
|
+
TKeyStored,
|
|
116
|
+
TKeyRuntime,
|
|
117
|
+
TValueStored,
|
|
118
|
+
TValueRuntime,
|
|
119
|
+
>(
|
|
120
|
+
keyAdapter: RuntimeAdapter<TKeyStored, TKeyRuntime>,
|
|
121
|
+
valueAdapter: RuntimeAdapter<TValueStored, TValueRuntime>,
|
|
122
|
+
toStored: (runtimeMap: Map<TKeyRuntime, TValueRuntime>) => TStored
|
|
123
|
+
): ModelPropTransform<TStored, Map<TKeyRuntime, TValueRuntime>> {
|
|
124
|
+
const storedByRuntime = new WeakMap<Map<TKeyRuntime, TValueRuntime>, TStored>()
|
|
121
125
|
|
|
122
126
|
return {
|
|
123
127
|
transform({ originalValue, cachedTransformedValue }) {
|
|
@@ -125,63 +129,51 @@ function makeObjectBackedMapTransform<TStoredValue, TRuntimeValue>(
|
|
|
125
129
|
return cachedTransformedValue
|
|
126
130
|
}
|
|
127
131
|
|
|
128
|
-
const runtimeMap = makeMapProxy(
|
|
132
|
+
const runtimeMap = makeMapProxy(
|
|
133
|
+
asMap(originalValue as any) as Map<TKeyStored, TValueStored>,
|
|
134
|
+
keyAdapter,
|
|
135
|
+
valueAdapter
|
|
136
|
+
)
|
|
129
137
|
|
|
130
138
|
storedByRuntime.set(runtimeMap, originalValue)
|
|
131
139
|
return runtimeMap
|
|
132
140
|
},
|
|
133
141
|
|
|
134
142
|
untransform({ transformedValue }) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
143
|
+
return storedByRuntime.get(transformedValue) ?? toStored(transformedValue)
|
|
144
|
+
},
|
|
145
|
+
}
|
|
146
|
+
}
|
|
139
147
|
|
|
148
|
+
function makeObjectBackedMapTransform<TStoredValue, TRuntimeValue>(
|
|
149
|
+
valueAdapter: RuntimeAdapter<TStoredValue, TRuntimeValue>
|
|
150
|
+
): ModelPropTransform<Record<string, TStoredValue>, Map<string, TRuntimeValue>> {
|
|
151
|
+
return makeMapTransform(
|
|
152
|
+
identityRuntimeAdapter as RuntimeAdapter<string, string>,
|
|
153
|
+
valueAdapter,
|
|
154
|
+
(runtimeMap) => {
|
|
140
155
|
const result: Record<string, TStoredValue> = {}
|
|
141
|
-
|
|
156
|
+
runtimeMap.forEach((value, key) => {
|
|
142
157
|
const storedValue = valueAdapter.toStored(value)
|
|
143
158
|
if (key === "__proto__") setProtoProp(result, storedValue)
|
|
144
159
|
else result[key] = storedValue
|
|
145
160
|
})
|
|
146
161
|
return result
|
|
147
|
-
}
|
|
148
|
-
|
|
162
|
+
}
|
|
163
|
+
)
|
|
149
164
|
}
|
|
150
165
|
|
|
151
166
|
function makeArrayBackedMapTransform<TKeyStored, TKeyRuntime, TValueStored, TValueRuntime>(
|
|
152
167
|
keyAdapter: RuntimeAdapter<TKeyStored, TKeyRuntime>,
|
|
153
168
|
valueAdapter: RuntimeAdapter<TValueStored, TValueRuntime>
|
|
154
169
|
): ModelPropTransform<Array<[TKeyStored, TValueStored]>, Map<TKeyRuntime, TValueRuntime>> {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if (cachedTransformedValue) {
|
|
163
|
-
return cachedTransformedValue
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const runtimeMap = makeMapProxy(asMap(originalValue), keyAdapter, valueAdapter)
|
|
167
|
-
|
|
168
|
-
storedByRuntime.set(runtimeMap, originalValue)
|
|
169
|
-
return runtimeMap
|
|
170
|
-
},
|
|
171
|
-
|
|
172
|
-
untransform({ transformedValue }) {
|
|
173
|
-
const cachedStored = storedByRuntime.get(transformedValue)
|
|
174
|
-
if (cachedStored) {
|
|
175
|
-
return cachedStored
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
const result: Array<[TKeyStored, TValueStored]> = []
|
|
179
|
-
transformedValue.forEach((value, key) => {
|
|
180
|
-
result.push([keyAdapter.toStored(key), valueAdapter.toStored(value)])
|
|
181
|
-
})
|
|
182
|
-
return result
|
|
183
|
-
},
|
|
184
|
-
}
|
|
170
|
+
return makeMapTransform(keyAdapter, valueAdapter, (runtimeMap) => {
|
|
171
|
+
const result: Array<[TKeyStored, TValueStored]> = []
|
|
172
|
+
runtimeMap.forEach((value, key) => {
|
|
173
|
+
result.push([keyAdapter.toStored(key), valueAdapter.toStored(value)])
|
|
174
|
+
})
|
|
175
|
+
return result
|
|
176
|
+
})
|
|
185
177
|
}
|
|
186
178
|
|
|
187
179
|
export function typesMapFromObject<TValueType extends AnyType>(
|
|
@@ -62,6 +62,11 @@ export function typesRefinement<T extends AnyType>(
|
|
|
62
62
|
return `${refinementName}<${baseTypeName}>`
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
const processorPlan = snapshotProcessorPlan(
|
|
66
|
+
() => [baseChecker],
|
|
67
|
+
([processor]) => processor
|
|
68
|
+
)
|
|
69
|
+
|
|
65
70
|
const thisTc: TypeChecker = new TypeChecker(
|
|
66
71
|
baseChecker.baseType,
|
|
67
72
|
|
|
@@ -103,14 +108,8 @@ export function typesRefinement<T extends AnyType>(
|
|
|
103
108
|
// we cannot check refinement here since it checks data instances, not snapshots
|
|
104
109
|
(sn) => baseChecker.snapshotType(sn),
|
|
105
110
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
([processor]) => processor
|
|
109
|
-
),
|
|
110
|
-
snapshotProcessorPlan(
|
|
111
|
-
() => [baseChecker],
|
|
112
|
-
([processor]) => processor
|
|
113
|
-
)
|
|
111
|
+
processorPlan,
|
|
112
|
+
processorPlan
|
|
114
113
|
)
|
|
115
114
|
|
|
116
115
|
return thisTc
|
|
@@ -42,20 +42,19 @@ export function typesSkipCheck<T extends AnyType>(baseType: T): T {
|
|
|
42
42
|
return `skipCheck<${baseTypeName}>`
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
const processorPlan = snapshotProcessorPlan(
|
|
46
|
+
() => [baseChecker],
|
|
47
|
+
([processor]) => processor
|
|
48
|
+
)
|
|
49
|
+
|
|
45
50
|
const thisTc: TypeChecker = new TypeChecker(
|
|
46
51
|
baseChecker.baseType,
|
|
47
52
|
(_data, _path, _typeCheckedValue) => null, // always passes validation
|
|
48
53
|
getTypeName,
|
|
49
54
|
typeInfoGen,
|
|
50
55
|
(sn) => baseChecker.snapshotType(sn),
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
([processor]) => processor
|
|
54
|
-
),
|
|
55
|
-
snapshotProcessorPlan(
|
|
56
|
-
() => [baseChecker],
|
|
57
|
-
([processor]) => processor
|
|
58
|
-
)
|
|
56
|
+
processorPlan,
|
|
57
|
+
processorPlan
|
|
59
58
|
)
|
|
60
59
|
thisTc.skipCheck = true
|
|
61
60
|
|
|
@@ -52,20 +52,19 @@ export function typesTag<T extends AnyType, A>(baseType: T, tag: A, typeName?: s
|
|
|
52
52
|
return `${taggedName}<${baseTypeName}>`
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
const processorPlan = snapshotProcessorPlan(
|
|
56
|
+
() => [baseChecker],
|
|
57
|
+
([processor]) => processor
|
|
58
|
+
)
|
|
59
|
+
|
|
55
60
|
const thisTc: TypeChecker = new TypeChecker(
|
|
56
61
|
baseChecker.baseType,
|
|
57
62
|
(data, path, typeCheckedValue) => baseChecker.check(data, path, typeCheckedValue),
|
|
58
63
|
getTypeName,
|
|
59
64
|
typeInfoGen,
|
|
60
65
|
(sn) => baseChecker.snapshotType(sn),
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
([processor]) => processor
|
|
64
|
-
),
|
|
65
|
-
snapshotProcessorPlan(
|
|
66
|
-
() => [baseChecker],
|
|
67
|
-
([processor]) => processor
|
|
68
|
-
)
|
|
66
|
+
processorPlan,
|
|
67
|
+
processorPlan
|
|
69
68
|
)
|
|
70
69
|
|
|
71
70
|
return thisTc
|
package/src/utils/ModelPool.ts
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import type { AnyModel } from "../model/BaseModel"
|
|
2
|
-
import { getModelIdPropertyName } from "../model/getModelMetadata"
|
|
3
2
|
import { modelIdKey, modelTypeKey } from "../model/metadata"
|
|
4
|
-
import {
|
|
5
|
-
import type { ModelClass } from "../modelShared/BaseModelShared"
|
|
6
|
-
import { getModelInfoForName } from "../modelShared/modelInfo"
|
|
3
|
+
import { isModel } from "../model/utils"
|
|
7
4
|
import { dataToModelNode } from "../parent/core"
|
|
8
5
|
import {
|
|
9
6
|
type DeepObjectChildrenExtensionAccessor,
|
|
@@ -46,20 +43,6 @@ export class ModelPool {
|
|
|
46
43
|
findModelByTypeAndId(modelType: string, modelId: string | undefined): AnyModel | undefined {
|
|
47
44
|
return modelId !== undefined ? this.pool.get(modelType)?.get(modelId) : undefined
|
|
48
45
|
}
|
|
49
|
-
|
|
50
|
-
findModelForSnapshot(sn: any): AnyModel | undefined {
|
|
51
|
-
const modelType = getSnapshotModelType(sn)
|
|
52
|
-
if (modelType === undefined) {
|
|
53
|
-
return undefined
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const modelInfo = getModelInfoForName(modelType)!
|
|
57
|
-
const modelIdPropertyName = getModelIdPropertyName(modelInfo.class as ModelClass<AnyModel>)
|
|
58
|
-
|
|
59
|
-
return modelIdPropertyName !== undefined
|
|
60
|
-
? this.findModelByTypeAndId(modelType, (sn as any)[modelIdPropertyName])
|
|
61
|
-
: undefined
|
|
62
|
-
}
|
|
63
46
|
}
|
|
64
47
|
|
|
65
48
|
let deepChildrenModels: DeepObjectChildrenExtensionAccessor<DeepChildrenModels> | undefined
|
package/src/utils/decorators.ts
CHANGED
|
@@ -109,7 +109,7 @@ export function decorateWrapMethodOrField(
|
|
|
109
109
|
const propertyKey: string = args[1]
|
|
110
110
|
const baseDescriptor: PropertyDescriptor | undefined = args[2]
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
checkModelDecoratorTarget(decoratorName, target)
|
|
113
113
|
checkDecoratorContext(decoratorName, propertyKey, false)
|
|
114
114
|
|
|
115
115
|
const data = getActionNameAndContextOverride(target, propertyKey, true)
|
|
@@ -166,7 +166,7 @@ export function decorateWrapMethodOrField(
|
|
|
166
166
|
inited = true
|
|
167
167
|
|
|
168
168
|
const target = this
|
|
169
|
-
|
|
169
|
+
checkModelDecoratorTarget(decoratorName, target)
|
|
170
170
|
|
|
171
171
|
// find the deepest proto that matches the value
|
|
172
172
|
let proto = this
|
|
@@ -195,7 +195,7 @@ export function decorateWrapMethodOrField(
|
|
|
195
195
|
const instance = this
|
|
196
196
|
|
|
197
197
|
if (!data) {
|
|
198
|
-
|
|
198
|
+
checkModelDecoratorTarget(decoratorName, instance)
|
|
199
199
|
data = getActionNameAndContextOverride(instance, propertyKey, false)
|
|
200
200
|
}
|
|
201
201
|
|
|
@@ -207,7 +207,7 @@ export function decorateWrapMethodOrField(
|
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
default:
|
|
210
|
-
throw failure(`@${decoratorName} can only be used on fields or methods
|
|
210
|
+
throw failure(`@${decoratorName} can only be used on fields or methods`)
|
|
211
211
|
}
|
|
212
212
|
}
|
|
213
213
|
}
|
|
@@ -270,7 +270,7 @@ function getActionNameAndContextOverride(
|
|
|
270
270
|
}
|
|
271
271
|
}
|
|
272
272
|
|
|
273
|
-
function
|
|
273
|
+
function checkModelDecoratorTarget(decoratorName: string, target: any) {
|
|
274
274
|
if (!inDevMode) {
|
|
275
275
|
return
|
|
276
276
|
}
|
package/src/utils/index.ts
CHANGED
|
@@ -267,15 +267,6 @@ export function assertIsObject(value: unknown, argName: string): asserts value i
|
|
|
267
267
|
}
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
-
/**
|
|
271
|
-
* @internal
|
|
272
|
-
*/
|
|
273
|
-
export function assertIsPlainObject(value: unknown, argName: string): asserts value is object {
|
|
274
|
-
if (!isPlainObject(value)) {
|
|
275
|
-
throw failure(`${argName} must be a plain object`)
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
270
|
/**
|
|
280
271
|
* @internal
|
|
281
272
|
*/
|
|
@@ -342,15 +333,6 @@ export function assertIsPrimitive(
|
|
|
342
333
|
}
|
|
343
334
|
}
|
|
344
335
|
|
|
345
|
-
/**
|
|
346
|
-
* @internal
|
|
347
|
-
*/
|
|
348
|
-
export function assertIsString(value: unknown, argName: string): asserts value is string {
|
|
349
|
-
if (typeof value !== "string") {
|
|
350
|
-
throw failure(`${argName} must be a string`)
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
336
|
/**
|
|
355
337
|
* @internal
|
|
356
338
|
*/
|
|
@@ -372,8 +354,7 @@ export function addLateInitializationFunction(
|
|
|
372
354
|
fn: (instance: any) => void
|
|
373
355
|
) {
|
|
374
356
|
let array: LateInitializationFunctionsArray | undefined = target[symbol]
|
|
375
|
-
|
|
376
|
-
if (!(array && Object.prototype.hasOwnProperty.call(target, symbol))) {
|
|
357
|
+
if (!(array && hasOwnProp(target, symbol))) {
|
|
377
358
|
// leave base array unmodified, create new array in the derived class
|
|
378
359
|
array = array ? array.slice() : []
|
|
379
360
|
addHiddenProp(target, symbol, array)
|
package/src/utils/types.ts
CHANGED
|
@@ -46,3 +46,8 @@ export type IsNeverType<T, IfNever, IfNotNever> = [T] extends [never] ? IfNever
|
|
|
46
46
|
* @ignore
|
|
47
47
|
*/
|
|
48
48
|
export type Flatten<T> = T extends Record<any, any> ? { [P in keyof T]: T[P] } : T
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @ignore
|
|
52
|
+
*/
|
|
53
|
+
export type SimplifyObject<T> = { [P in keyof T]: T[P] } & {}
|
package/src/wrappers/ArraySet.ts
CHANGED
|
@@ -8,6 +8,15 @@ import { typesArray } from "../types/arrayBased/typesArray"
|
|
|
8
8
|
import { tProp } from "../types/tProp"
|
|
9
9
|
import { typesUnchecked } from "../types/utility/typesUnchecked"
|
|
10
10
|
import { namespace } from "../utils"
|
|
11
|
+
import {
|
|
12
|
+
isSetLikeDisjointFrom,
|
|
13
|
+
isSetLikeSubsetOf,
|
|
14
|
+
isSetLikeSupersetOf,
|
|
15
|
+
setLikeDifference,
|
|
16
|
+
setLikeIntersection,
|
|
17
|
+
setLikeSymmetricDifference,
|
|
18
|
+
setLikeUnion,
|
|
19
|
+
} from "../utils/setLike"
|
|
11
20
|
|
|
12
21
|
const arraySetBase = Model({
|
|
13
22
|
[modelIdKey]: idProp,
|
|
@@ -96,39 +105,43 @@ export class ArraySet<V> extends arraySetBase implements Set<V> {
|
|
|
96
105
|
|
|
97
106
|
readonly [Symbol.toStringTag] = "ArraySet"
|
|
98
107
|
|
|
108
|
+
// `has` scans the items, so the set operations look values up in a set built
|
|
109
|
+
// on the first lookup instead (not before, since many of them never look up)
|
|
110
|
+
private toSetLike(): ReadonlySetLike<V> {
|
|
111
|
+
let lookup: Set<V> | undefined
|
|
112
|
+
return {
|
|
113
|
+
size: this.items.length,
|
|
114
|
+
has: (value) => (lookup ??= new Set(this.items)).has(value),
|
|
115
|
+
keys: () => this.values(),
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
99
119
|
union<U>(other: ReadonlySetLike<U>): Set<V | U> {
|
|
100
|
-
|
|
101
|
-
return s.union(other)
|
|
120
|
+
return setLikeUnion(this.toSetLike(), other)
|
|
102
121
|
}
|
|
103
122
|
|
|
104
123
|
intersection<U>(other: ReadonlySetLike<U>): Set<V & U> {
|
|
105
|
-
|
|
106
|
-
return s.intersection(other)
|
|
124
|
+
return setLikeIntersection(this.toSetLike(), other)
|
|
107
125
|
}
|
|
108
126
|
|
|
109
127
|
difference<U>(other: ReadonlySetLike<U>): Set<V> {
|
|
110
|
-
|
|
111
|
-
return s.difference(other)
|
|
128
|
+
return setLikeDifference(this.toSetLike(), other)
|
|
112
129
|
}
|
|
113
130
|
|
|
114
131
|
symmetricDifference<U>(other: ReadonlySetLike<U>): Set<V | U> {
|
|
115
|
-
|
|
116
|
-
return s.symmetricDifference(other)
|
|
132
|
+
return setLikeSymmetricDifference(this.toSetLike(), other)
|
|
117
133
|
}
|
|
118
134
|
|
|
119
135
|
isSubsetOf(other: ReadonlySetLike<unknown>): boolean {
|
|
120
|
-
|
|
121
|
-
return s.isSubsetOf(other)
|
|
136
|
+
return isSetLikeSubsetOf(this.toSetLike(), other)
|
|
122
137
|
}
|
|
123
138
|
|
|
124
139
|
isSupersetOf(other: ReadonlySetLike<unknown>): boolean {
|
|
125
|
-
|
|
126
|
-
return s.isSupersetOf(other)
|
|
140
|
+
return isSetLikeSupersetOf(this.toSetLike(), other)
|
|
127
141
|
}
|
|
128
142
|
|
|
129
143
|
isDisjointFrom(other: ReadonlySetLike<unknown>): boolean {
|
|
130
|
-
|
|
131
|
-
return s.isDisjointFrom(other)
|
|
144
|
+
return isSetLikeDisjointFrom(this.toSetLike(), other)
|
|
132
145
|
}
|
|
133
146
|
}
|
|
134
147
|
|
|
@@ -70,12 +70,7 @@ export class ObjectMap<V> extends objectMapBase implements Map<string, V> {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
getOrInsert(key: string, defaultValue: V): V {
|
|
73
|
-
|
|
74
|
-
return this.get(key) as V
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
this.set(key, defaultValue)
|
|
78
|
-
return this.get(key) as V
|
|
73
|
+
return this.getOrInsertComputed(key, () => defaultValue)
|
|
79
74
|
}
|
|
80
75
|
|
|
81
76
|
getOrInsertComputed(key: string, callback: (key: string) => V): V {
|
package/src/wrappers/asMap.ts
CHANGED
|
@@ -4,8 +4,6 @@ import {
|
|
|
4
4
|
type IObjectDidChange,
|
|
5
5
|
type IObservableArray,
|
|
6
6
|
intercept,
|
|
7
|
-
isObservableArray,
|
|
8
|
-
isObservableObject,
|
|
9
7
|
type ObservableMap,
|
|
10
8
|
observable,
|
|
11
9
|
observe,
|
|
@@ -21,7 +19,6 @@ import {
|
|
|
21
19
|
failure,
|
|
22
20
|
getMobxVersion,
|
|
23
21
|
hasOwnProp,
|
|
24
|
-
inDevMode,
|
|
25
22
|
isArray,
|
|
26
23
|
isEqualOrBothNaN,
|
|
27
24
|
setProtoProp,
|
|
@@ -44,12 +41,7 @@ function addTs6MapExtras<K, V>(map: ObservableMap<K, V>): ObservableMap<K, V> &
|
|
|
44
41
|
|
|
45
42
|
if (!mapWithExtras.getOrInsert) {
|
|
46
43
|
mapWithExtras.getOrInsert = function (key: K, defaultValue: V): V {
|
|
47
|
-
|
|
48
|
-
return this.get(key) as V
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
this.set(key, defaultValue)
|
|
52
|
-
return this.get(key) as V
|
|
44
|
+
return this.getOrInsertComputed(key, () => defaultValue)
|
|
53
45
|
}
|
|
54
46
|
}
|
|
55
47
|
|
|
@@ -70,12 +62,6 @@ function addTs6MapExtras<K, V>(map: ObservableMap<K, V>): ObservableMap<K, V> &
|
|
|
70
62
|
|
|
71
63
|
const observableMapBackedByObservableObject = action(
|
|
72
64
|
<T>(obj: object): ObservableMapWithDataObject<string, T, typeof obj> => {
|
|
73
|
-
if (inDevMode) {
|
|
74
|
-
if (!isObservableObject(obj)) {
|
|
75
|
-
throw failure("assertion failed: expected an observable object")
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
65
|
const map = transaction(() =>
|
|
80
66
|
untracked(() => {
|
|
81
67
|
const map = observable.map<string, T>(undefined, { deep: false })
|
|
@@ -175,12 +161,6 @@ const observableMapBackedByObservableObject = action(
|
|
|
175
161
|
const observableMapBackedByObservableArray = <K, T>(
|
|
176
162
|
array: IObservableArray<[K, T]>
|
|
177
163
|
): ObservableMapWithDataObject<K, T, typeof array> => {
|
|
178
|
-
if (inDevMode) {
|
|
179
|
-
if (!isObservableArray(array)) {
|
|
180
|
-
throw failure("assertion failed: expected an observable array")
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
164
|
const map: ObservableMap<K, T> = untracked(() => {
|
|
185
165
|
if (getMobxVersion() >= 6) {
|
|
186
166
|
return observable.map<K, T>(array, { deep: false })
|
package/src/wrappers/asSet.ts
CHANGED
|
@@ -3,7 +3,6 @@ import {
|
|
|
3
3
|
type IObservableArray,
|
|
4
4
|
type ISetWillChange,
|
|
5
5
|
intercept,
|
|
6
|
-
isObservableArray,
|
|
7
6
|
type ObservableSet,
|
|
8
7
|
observable,
|
|
9
8
|
observe,
|
|
@@ -16,7 +15,6 @@ import {
|
|
|
16
15
|
assertIsSet,
|
|
17
16
|
failure,
|
|
18
17
|
getMobxVersion,
|
|
19
|
-
inDevMode,
|
|
20
18
|
isEqualOrBothNaN,
|
|
21
19
|
} from "../utils"
|
|
22
20
|
import { tag } from "../utils/tag"
|
|
@@ -24,12 +22,6 @@ import { tag } from "../utils/tag"
|
|
|
24
22
|
const observableSetBackedByObservableArray = <T>(
|
|
25
23
|
array: IObservableArray<T>
|
|
26
24
|
): ObservableSet<T> & { dataObject: typeof array } => {
|
|
27
|
-
if (inDevMode) {
|
|
28
|
-
if (!isObservableArray(array)) {
|
|
29
|
-
throw failure("assertion failed: expected an observable array")
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
25
|
const set = transaction(() =>
|
|
34
26
|
untracked(() => {
|
|
35
27
|
if (getMobxVersion() >= 6) {
|