mobx-keystone 0.67.2 → 0.67.3
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 +4 -0
- package/dist/mobx-keystone.es.js +5 -6
- package/dist/mobx-keystone.es.mjs +5 -6
- package/dist/mobx-keystone.umd.js +5 -6
- package/dist/model/BaseModel.d.ts +1 -5
- package/dist/model/Model.d.ts +5 -5
- package/package.json +10 -10
- package/src/dataModel/BaseDataModel.ts +1 -1
- package/src/model/BaseModel.ts +7 -7
- package/src/model/Model.ts +26 -16
- package/src/snapshot/internal.ts +4 -3
- package/src/tweaker/core.ts +1 -1
- package/src/tweaker/tweakModel.ts +1 -1
- package/src/tweaker/tweakPlainObject.ts +4 -4
- package/src/types/TypeChecker.ts +4 -3
- package/src/utils/index.ts +413 -413
package/src/utils/index.ts
CHANGED
|
@@ -1,413 +1,413 @@
|
|
|
1
|
-
import * as mobx from "mobx"
|
|
2
|
-
import {
|
|
3
|
-
IObservableArray,
|
|
4
|
-
isObservableArray,
|
|
5
|
-
isObservableMap,
|
|
6
|
-
isObservableObject,
|
|
7
|
-
isObservableSet,
|
|
8
|
-
ObservableMap,
|
|
9
|
-
ObservableSet,
|
|
10
|
-
} from "mobx"
|
|
11
|
-
import { JSONPrimitiveValue, PrimitiveValue } from "./types"
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* A mobx-keystone error.
|
|
15
|
-
*/
|
|
16
|
-
export class MobxKeystoneError extends Error {
|
|
17
|
-
constructor(msg: string) {
|
|
18
|
-
super(msg)
|
|
19
|
-
|
|
20
|
-
// Set the prototype explicitly.
|
|
21
|
-
Object.setPrototypeOf(this, MobxKeystoneError.prototype)
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* @internal
|
|
27
|
-
*/
|
|
28
|
-
export function failure(msg: string) {
|
|
29
|
-
return new MobxKeystoneError(msg)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const writableHiddenPropDescriptor: PropertyDescriptor = {
|
|
33
|
-
enumerable: false,
|
|
34
|
-
writable: true,
|
|
35
|
-
configurable: false,
|
|
36
|
-
value: undefined,
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* @internal
|
|
41
|
-
*/
|
|
42
|
-
export function addHiddenProp(object: any, propName: PropertyKey, value: any, writable = true) {
|
|
43
|
-
if (writable) {
|
|
44
|
-
Object.defineProperty(object, propName, writableHiddenPropDescriptor)
|
|
45
|
-
object[propName] = value
|
|
46
|
-
} else {
|
|
47
|
-
Object.defineProperty(object, propName, {
|
|
48
|
-
enumerable: false,
|
|
49
|
-
writable,
|
|
50
|
-
configurable: true,
|
|
51
|
-
value,
|
|
52
|
-
})
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* @internal
|
|
58
|
-
*/
|
|
59
|
-
export function makePropReadonly<T>(object: T, propName: keyof T, enumerable: boolean) {
|
|
60
|
-
const propDesc = Object.getOwnPropertyDescriptor(object, propName)
|
|
61
|
-
if (propDesc) {
|
|
62
|
-
propDesc.enumerable = enumerable
|
|
63
|
-
if (propDesc.get) {
|
|
64
|
-
delete propDesc.set
|
|
65
|
-
} else {
|
|
66
|
-
propDesc.writable = false
|
|
67
|
-
}
|
|
68
|
-
Object.defineProperty(object, propName, propDesc)
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* @internal
|
|
74
|
-
*/
|
|
75
|
-
export function isPlainObject(value: unknown): value is
|
|
76
|
-
if (!isObject(value)) return false
|
|
77
|
-
const proto = Object.getPrototypeOf(value)
|
|
78
|
-
return proto === Object.prototype || proto === null
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* @internal
|
|
83
|
-
*/
|
|
84
|
-
export function isObject(value: unknown): value is Record<PropertyKey, unknown> {
|
|
85
|
-
return value !== null && typeof value === "object"
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* @internal
|
|
90
|
-
*/
|
|
91
|
-
export function isPrimitive(value: unknown): value is PrimitiveValue {
|
|
92
|
-
switch (typeof value) {
|
|
93
|
-
case "number":
|
|
94
|
-
case "string":
|
|
95
|
-
case "boolean":
|
|
96
|
-
case "undefined":
|
|
97
|
-
case "bigint":
|
|
98
|
-
return true
|
|
99
|
-
}
|
|
100
|
-
return value === null
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* @internal
|
|
105
|
-
*/
|
|
106
|
-
export function isJSONPrimitive(value: unknown): value is JSONPrimitiveValue {
|
|
107
|
-
switch (typeof value) {
|
|
108
|
-
case "number":
|
|
109
|
-
return isFinite(value)
|
|
110
|
-
case "string":
|
|
111
|
-
case "boolean":
|
|
112
|
-
return true
|
|
113
|
-
}
|
|
114
|
-
return value === null
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* @internal
|
|
119
|
-
*/
|
|
120
|
-
export function deleteFromArray<T>(array: T[], value: T): boolean {
|
|
121
|
-
let index = array.indexOf(value)
|
|
122
|
-
if (index >= 0) {
|
|
123
|
-
array.splice(index, 1)
|
|
124
|
-
return true
|
|
125
|
-
}
|
|
126
|
-
return false
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* @internal
|
|
131
|
-
*/
|
|
132
|
-
export function isMap(val: unknown): val is Map<any, any> | ObservableMap {
|
|
133
|
-
return val instanceof Map || isObservableMap(val)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* @internal
|
|
138
|
-
*/
|
|
139
|
-
export function isSet(val: unknown): val is Set<any> | ObservableSet {
|
|
140
|
-
return val instanceof Set || isObservableSet(val)
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* @internal
|
|
145
|
-
*/
|
|
146
|
-
export function isArray(val: unknown): val is any[] | IObservableArray {
|
|
147
|
-
return Array.isArray(val) || isObservableArray(val)
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* @internal
|
|
152
|
-
*/
|
|
153
|
-
export function inDevMode(): boolean {
|
|
154
|
-
return process.env.NODE_ENV !== "production"
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* @internal
|
|
159
|
-
*/
|
|
160
|
-
export function assertIsObject(value: unknown, argName: string): asserts value is object {
|
|
161
|
-
if (!isObject(value)) {
|
|
162
|
-
throw failure(`${argName} must be an object`)
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* @internal
|
|
168
|
-
*/
|
|
169
|
-
export function assertIsPlainObject(value: unknown, argName: string): asserts value is object {
|
|
170
|
-
if (!isPlainObject(value)) {
|
|
171
|
-
throw failure(`${argName} must be a plain object`)
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* @internal
|
|
177
|
-
*/
|
|
178
|
-
export function assertIsObservableObject(value: unknown, argName: string): asserts value is object {
|
|
179
|
-
if (!isObservableObject(value)) {
|
|
180
|
-
throw failure(`${argName} must be an observable object`)
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* @internal
|
|
186
|
-
*/
|
|
187
|
-
export function assertIsObservableArray(
|
|
188
|
-
value: unknown,
|
|
189
|
-
argName: string
|
|
190
|
-
): asserts value is IObservableArray {
|
|
191
|
-
if (!isObservableArray(value)) {
|
|
192
|
-
throw failure(`${argName} must be an observable array`)
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* @internal
|
|
198
|
-
*/
|
|
199
|
-
export function assertIsMap(value: unknown, argName: string): asserts value is Map<any, any> {
|
|
200
|
-
if (!isMap(value)) {
|
|
201
|
-
throw failure(`${argName} must be a map`)
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* @internal
|
|
207
|
-
*/
|
|
208
|
-
export function assertIsSet(value: unknown, argName: string): asserts value is Set<any> {
|
|
209
|
-
if (!isSet(value)) {
|
|
210
|
-
throw failure(`${argName} must be a set`)
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* @internal
|
|
216
|
-
*/
|
|
217
|
-
export function assertIsFunction(value: unknown, argName: string): asserts value is Function {
|
|
218
|
-
if (typeof value !== "function") {
|
|
219
|
-
throw failure(`${argName} must be a function`)
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* @internal
|
|
225
|
-
*/
|
|
226
|
-
export function assertIsPrimitive(
|
|
227
|
-
value: unknown,
|
|
228
|
-
argName: string
|
|
229
|
-
): asserts value is PrimitiveValue {
|
|
230
|
-
if (!isPrimitive(value)) {
|
|
231
|
-
throw failure(`${argName} must be a primitive`)
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* @internal
|
|
237
|
-
*/
|
|
238
|
-
export function assertIsString(value: unknown, argName: string): asserts value is string {
|
|
239
|
-
if (typeof value !== "string") {
|
|
240
|
-
throw failure(`${argName} must be a string`)
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* @internal
|
|
246
|
-
*/
|
|
247
|
-
export interface DecorateMethodOrFieldData {
|
|
248
|
-
target: any
|
|
249
|
-
propertyKey: string
|
|
250
|
-
baseDescriptor?: PropertyDescriptor & { initializer?: () => any }
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* @internal
|
|
255
|
-
*/
|
|
256
|
-
export const runAfterNewSymbol = Symbol("runAfterNew")
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* @internal
|
|
260
|
-
*/
|
|
261
|
-
export const runBeforeOnInitSymbol = Symbol("runBeforeOnInit")
|
|
262
|
-
|
|
263
|
-
type WrapFunction = (data: DecorateMethodOrFieldData, fn: any) => any
|
|
264
|
-
type LateInitializationFunctionsArray = ((instance: any) => void)[]
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* @internal
|
|
268
|
-
*/
|
|
269
|
-
export function addLateInitializationFunction(
|
|
270
|
-
target: any,
|
|
271
|
-
symbol: symbol,
|
|
272
|
-
fn: (instance: any) => void
|
|
273
|
-
) {
|
|
274
|
-
let array: LateInitializationFunctionsArray = target[symbol]
|
|
275
|
-
if (!array) {
|
|
276
|
-
array = []
|
|
277
|
-
addHiddenProp(target, symbol, array)
|
|
278
|
-
}
|
|
279
|
-
array.push(fn)
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
* @internal
|
|
284
|
-
*/
|
|
285
|
-
export function decorateWrapMethodOrField(
|
|
286
|
-
decoratorName: string,
|
|
287
|
-
data: DecorateMethodOrFieldData,
|
|
288
|
-
wrap: WrapFunction
|
|
289
|
-
): any {
|
|
290
|
-
const { target, propertyKey, baseDescriptor } = data
|
|
291
|
-
|
|
292
|
-
const addFieldDecorator = () => {
|
|
293
|
-
addLateInitializationFunction(target, runAfterNewSymbol, (instance) => {
|
|
294
|
-
instance[propertyKey] = wrap(data, instance[propertyKey])
|
|
295
|
-
})
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
if (baseDescriptor) {
|
|
299
|
-
if (baseDescriptor.get !== undefined) {
|
|
300
|
-
throw failure(`@${decoratorName} cannot be used with getters`)
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
if (baseDescriptor.value) {
|
|
304
|
-
// babel / typescript - method decorator
|
|
305
|
-
// @action method() { }
|
|
306
|
-
return {
|
|
307
|
-
enumerable: false,
|
|
308
|
-
writable: true,
|
|
309
|
-
configurable: true,
|
|
310
|
-
value: wrap(data, baseDescriptor.value),
|
|
311
|
-
}
|
|
312
|
-
} else {
|
|
313
|
-
// babel - field decorator: @action method = () => {}
|
|
314
|
-
addFieldDecorator()
|
|
315
|
-
}
|
|
316
|
-
} else {
|
|
317
|
-
// typescript - field decorator
|
|
318
|
-
addFieldDecorator()
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
|
-
* @internal
|
|
324
|
-
*/
|
|
325
|
-
export function runLateInitializationFunctions(target: any, symbol: symbol): void {
|
|
326
|
-
const fns: LateInitializationFunctionsArray | undefined = target[symbol]
|
|
327
|
-
if (fns) {
|
|
328
|
-
for (const fn of fns) {
|
|
329
|
-
fn(target)
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
const warningsAlreadyDisplayed = new Set<string>()
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* @internal
|
|
338
|
-
*/
|
|
339
|
-
export function logWarning(type: "warn" | "error", msg: string, uniqueKey?: string): void {
|
|
340
|
-
if (uniqueKey) {
|
|
341
|
-
if (warningsAlreadyDisplayed.has(uniqueKey)) {
|
|
342
|
-
return
|
|
343
|
-
}
|
|
344
|
-
warningsAlreadyDisplayed.add(uniqueKey)
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
msg = "[mobx-keystone] " + msg
|
|
348
|
-
switch (type) {
|
|
349
|
-
case "warn":
|
|
350
|
-
console.warn(msg)
|
|
351
|
-
break
|
|
352
|
-
case "error":
|
|
353
|
-
console.error(msg)
|
|
354
|
-
break
|
|
355
|
-
default:
|
|
356
|
-
throw failure(`unknown log type - ${type}`)
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
/**
|
|
361
|
-
* @internal
|
|
362
|
-
*/
|
|
363
|
-
export function lazy<A extends unknown[], R>(getter: (...args: A) => R): typeof getter {
|
|
364
|
-
let memoizedValue: R
|
|
365
|
-
let memoized = false
|
|
366
|
-
|
|
367
|
-
return (...args: A): R => {
|
|
368
|
-
if (!memoized) {
|
|
369
|
-
memoizedValue = getter(...args)
|
|
370
|
-
memoized = true
|
|
371
|
-
}
|
|
372
|
-
return memoizedValue
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* @internal
|
|
378
|
-
*/
|
|
379
|
-
export const identityFn = <T>(x: T): T => x
|
|
380
|
-
|
|
381
|
-
/**
|
|
382
|
-
* @internal
|
|
383
|
-
*/
|
|
384
|
-
export const mobx6 = {
|
|
385
|
-
// eslint-disable-next-line no-useless-concat
|
|
386
|
-
makeObservable: (mobx as any)[
|
|
387
|
-
// just to ensure import * is kept properly
|
|
388
|
-
String.fromCharCode("l".charCodeAt(0) + 1) + "akeObservable"
|
|
389
|
-
],
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
/**
|
|
393
|
-
* @internal
|
|
394
|
-
*/
|
|
395
|
-
export function propNameToSetterName(propName: string): string {
|
|
396
|
-
return `set${propName[0].toUpperCase()}${propName.slice(1)}`
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
/**
|
|
400
|
-
* @internal
|
|
401
|
-
*/
|
|
402
|
-
export function getMobxVersion(): number {
|
|
403
|
-
if (mobx6.makeObservable!) {
|
|
404
|
-
return 6
|
|
405
|
-
} else {
|
|
406
|
-
return 5
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
/**
|
|
411
|
-
* @internal
|
|
412
|
-
*/
|
|
413
|
-
export const namespace = "mobx-keystone"
|
|
1
|
+
import * as mobx from "mobx"
|
|
2
|
+
import {
|
|
3
|
+
IObservableArray,
|
|
4
|
+
isObservableArray,
|
|
5
|
+
isObservableMap,
|
|
6
|
+
isObservableObject,
|
|
7
|
+
isObservableSet,
|
|
8
|
+
ObservableMap,
|
|
9
|
+
ObservableSet,
|
|
10
|
+
} from "mobx"
|
|
11
|
+
import { JSONPrimitiveValue, PrimitiveValue } from "./types"
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A mobx-keystone error.
|
|
15
|
+
*/
|
|
16
|
+
export class MobxKeystoneError extends Error {
|
|
17
|
+
constructor(msg: string) {
|
|
18
|
+
super(msg)
|
|
19
|
+
|
|
20
|
+
// Set the prototype explicitly.
|
|
21
|
+
Object.setPrototypeOf(this, MobxKeystoneError.prototype)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @internal
|
|
27
|
+
*/
|
|
28
|
+
export function failure(msg: string) {
|
|
29
|
+
return new MobxKeystoneError(msg)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const writableHiddenPropDescriptor: PropertyDescriptor = {
|
|
33
|
+
enumerable: false,
|
|
34
|
+
writable: true,
|
|
35
|
+
configurable: false,
|
|
36
|
+
value: undefined,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @internal
|
|
41
|
+
*/
|
|
42
|
+
export function addHiddenProp(object: any, propName: PropertyKey, value: any, writable = true) {
|
|
43
|
+
if (writable) {
|
|
44
|
+
Object.defineProperty(object, propName, writableHiddenPropDescriptor)
|
|
45
|
+
object[propName] = value
|
|
46
|
+
} else {
|
|
47
|
+
Object.defineProperty(object, propName, {
|
|
48
|
+
enumerable: false,
|
|
49
|
+
writable,
|
|
50
|
+
configurable: true,
|
|
51
|
+
value,
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @internal
|
|
58
|
+
*/
|
|
59
|
+
export function makePropReadonly<T>(object: T, propName: keyof T, enumerable: boolean) {
|
|
60
|
+
const propDesc = Object.getOwnPropertyDescriptor(object, propName)
|
|
61
|
+
if (propDesc) {
|
|
62
|
+
propDesc.enumerable = enumerable
|
|
63
|
+
if (propDesc.get) {
|
|
64
|
+
delete propDesc.set
|
|
65
|
+
} else {
|
|
66
|
+
propDesc.writable = false
|
|
67
|
+
}
|
|
68
|
+
Object.defineProperty(object, propName, propDesc)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @internal
|
|
74
|
+
*/
|
|
75
|
+
export function isPlainObject(value: unknown): value is Record<PropertyKey, unknown> {
|
|
76
|
+
if (!isObject(value)) return false
|
|
77
|
+
const proto = Object.getPrototypeOf(value)
|
|
78
|
+
return proto === Object.prototype || proto === null
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @internal
|
|
83
|
+
*/
|
|
84
|
+
export function isObject(value: unknown): value is Record<PropertyKey, unknown> {
|
|
85
|
+
return value !== null && typeof value === "object"
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* @internal
|
|
90
|
+
*/
|
|
91
|
+
export function isPrimitive(value: unknown): value is PrimitiveValue {
|
|
92
|
+
switch (typeof value) {
|
|
93
|
+
case "number":
|
|
94
|
+
case "string":
|
|
95
|
+
case "boolean":
|
|
96
|
+
case "undefined":
|
|
97
|
+
case "bigint":
|
|
98
|
+
return true
|
|
99
|
+
}
|
|
100
|
+
return value === null
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* @internal
|
|
105
|
+
*/
|
|
106
|
+
export function isJSONPrimitive(value: unknown): value is JSONPrimitiveValue {
|
|
107
|
+
switch (typeof value) {
|
|
108
|
+
case "number":
|
|
109
|
+
return isFinite(value)
|
|
110
|
+
case "string":
|
|
111
|
+
case "boolean":
|
|
112
|
+
return true
|
|
113
|
+
}
|
|
114
|
+
return value === null
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @internal
|
|
119
|
+
*/
|
|
120
|
+
export function deleteFromArray<T>(array: T[], value: T): boolean {
|
|
121
|
+
let index = array.indexOf(value)
|
|
122
|
+
if (index >= 0) {
|
|
123
|
+
array.splice(index, 1)
|
|
124
|
+
return true
|
|
125
|
+
}
|
|
126
|
+
return false
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @internal
|
|
131
|
+
*/
|
|
132
|
+
export function isMap(val: unknown): val is Map<any, any> | ObservableMap {
|
|
133
|
+
return val instanceof Map || isObservableMap(val)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* @internal
|
|
138
|
+
*/
|
|
139
|
+
export function isSet(val: unknown): val is Set<any> | ObservableSet {
|
|
140
|
+
return val instanceof Set || isObservableSet(val)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* @internal
|
|
145
|
+
*/
|
|
146
|
+
export function isArray(val: unknown): val is any[] | IObservableArray {
|
|
147
|
+
return Array.isArray(val) || isObservableArray(val)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* @internal
|
|
152
|
+
*/
|
|
153
|
+
export function inDevMode(): boolean {
|
|
154
|
+
return process.env.NODE_ENV !== "production"
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* @internal
|
|
159
|
+
*/
|
|
160
|
+
export function assertIsObject(value: unknown, argName: string): asserts value is object {
|
|
161
|
+
if (!isObject(value)) {
|
|
162
|
+
throw failure(`${argName} must be an object`)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* @internal
|
|
168
|
+
*/
|
|
169
|
+
export function assertIsPlainObject(value: unknown, argName: string): asserts value is object {
|
|
170
|
+
if (!isPlainObject(value)) {
|
|
171
|
+
throw failure(`${argName} must be a plain object`)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* @internal
|
|
177
|
+
*/
|
|
178
|
+
export function assertIsObservableObject(value: unknown, argName: string): asserts value is object {
|
|
179
|
+
if (!isObservableObject(value)) {
|
|
180
|
+
throw failure(`${argName} must be an observable object`)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* @internal
|
|
186
|
+
*/
|
|
187
|
+
export function assertIsObservableArray(
|
|
188
|
+
value: unknown,
|
|
189
|
+
argName: string
|
|
190
|
+
): asserts value is IObservableArray {
|
|
191
|
+
if (!isObservableArray(value)) {
|
|
192
|
+
throw failure(`${argName} must be an observable array`)
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* @internal
|
|
198
|
+
*/
|
|
199
|
+
export function assertIsMap(value: unknown, argName: string): asserts value is Map<any, any> {
|
|
200
|
+
if (!isMap(value)) {
|
|
201
|
+
throw failure(`${argName} must be a map`)
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* @internal
|
|
207
|
+
*/
|
|
208
|
+
export function assertIsSet(value: unknown, argName: string): asserts value is Set<any> {
|
|
209
|
+
if (!isSet(value)) {
|
|
210
|
+
throw failure(`${argName} must be a set`)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* @internal
|
|
216
|
+
*/
|
|
217
|
+
export function assertIsFunction(value: unknown, argName: string): asserts value is Function {
|
|
218
|
+
if (typeof value !== "function") {
|
|
219
|
+
throw failure(`${argName} must be a function`)
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* @internal
|
|
225
|
+
*/
|
|
226
|
+
export function assertIsPrimitive(
|
|
227
|
+
value: unknown,
|
|
228
|
+
argName: string
|
|
229
|
+
): asserts value is PrimitiveValue {
|
|
230
|
+
if (!isPrimitive(value)) {
|
|
231
|
+
throw failure(`${argName} must be a primitive`)
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* @internal
|
|
237
|
+
*/
|
|
238
|
+
export function assertIsString(value: unknown, argName: string): asserts value is string {
|
|
239
|
+
if (typeof value !== "string") {
|
|
240
|
+
throw failure(`${argName} must be a string`)
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* @internal
|
|
246
|
+
*/
|
|
247
|
+
export interface DecorateMethodOrFieldData {
|
|
248
|
+
target: any
|
|
249
|
+
propertyKey: string
|
|
250
|
+
baseDescriptor?: PropertyDescriptor & { initializer?: () => any }
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* @internal
|
|
255
|
+
*/
|
|
256
|
+
export const runAfterNewSymbol = Symbol("runAfterNew")
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* @internal
|
|
260
|
+
*/
|
|
261
|
+
export const runBeforeOnInitSymbol = Symbol("runBeforeOnInit")
|
|
262
|
+
|
|
263
|
+
type WrapFunction = (data: DecorateMethodOrFieldData, fn: any) => any
|
|
264
|
+
type LateInitializationFunctionsArray = ((instance: any) => void)[]
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* @internal
|
|
268
|
+
*/
|
|
269
|
+
export function addLateInitializationFunction(
|
|
270
|
+
target: any,
|
|
271
|
+
symbol: symbol,
|
|
272
|
+
fn: (instance: any) => void
|
|
273
|
+
) {
|
|
274
|
+
let array: LateInitializationFunctionsArray = target[symbol]
|
|
275
|
+
if (!array) {
|
|
276
|
+
array = []
|
|
277
|
+
addHiddenProp(target, symbol, array)
|
|
278
|
+
}
|
|
279
|
+
array.push(fn)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* @internal
|
|
284
|
+
*/
|
|
285
|
+
export function decorateWrapMethodOrField(
|
|
286
|
+
decoratorName: string,
|
|
287
|
+
data: DecorateMethodOrFieldData,
|
|
288
|
+
wrap: WrapFunction
|
|
289
|
+
): any {
|
|
290
|
+
const { target, propertyKey, baseDescriptor } = data
|
|
291
|
+
|
|
292
|
+
const addFieldDecorator = () => {
|
|
293
|
+
addLateInitializationFunction(target, runAfterNewSymbol, (instance) => {
|
|
294
|
+
instance[propertyKey] = wrap(data, instance[propertyKey])
|
|
295
|
+
})
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (baseDescriptor) {
|
|
299
|
+
if (baseDescriptor.get !== undefined) {
|
|
300
|
+
throw failure(`@${decoratorName} cannot be used with getters`)
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (baseDescriptor.value) {
|
|
304
|
+
// babel / typescript - method decorator
|
|
305
|
+
// @action method() { }
|
|
306
|
+
return {
|
|
307
|
+
enumerable: false,
|
|
308
|
+
writable: true,
|
|
309
|
+
configurable: true,
|
|
310
|
+
value: wrap(data, baseDescriptor.value),
|
|
311
|
+
}
|
|
312
|
+
} else {
|
|
313
|
+
// babel - field decorator: @action method = () => {}
|
|
314
|
+
addFieldDecorator()
|
|
315
|
+
}
|
|
316
|
+
} else {
|
|
317
|
+
// typescript - field decorator
|
|
318
|
+
addFieldDecorator()
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* @internal
|
|
324
|
+
*/
|
|
325
|
+
export function runLateInitializationFunctions(target: any, symbol: symbol): void {
|
|
326
|
+
const fns: LateInitializationFunctionsArray | undefined = target[symbol]
|
|
327
|
+
if (fns) {
|
|
328
|
+
for (const fn of fns) {
|
|
329
|
+
fn(target)
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const warningsAlreadyDisplayed = new Set<string>()
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* @internal
|
|
338
|
+
*/
|
|
339
|
+
export function logWarning(type: "warn" | "error", msg: string, uniqueKey?: string): void {
|
|
340
|
+
if (uniqueKey) {
|
|
341
|
+
if (warningsAlreadyDisplayed.has(uniqueKey)) {
|
|
342
|
+
return
|
|
343
|
+
}
|
|
344
|
+
warningsAlreadyDisplayed.add(uniqueKey)
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
msg = "[mobx-keystone] " + msg
|
|
348
|
+
switch (type) {
|
|
349
|
+
case "warn":
|
|
350
|
+
console.warn(msg)
|
|
351
|
+
break
|
|
352
|
+
case "error":
|
|
353
|
+
console.error(msg)
|
|
354
|
+
break
|
|
355
|
+
default:
|
|
356
|
+
throw failure(`unknown log type - ${type}`)
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* @internal
|
|
362
|
+
*/
|
|
363
|
+
export function lazy<A extends unknown[], R>(getter: (...args: A) => R): typeof getter {
|
|
364
|
+
let memoizedValue: R
|
|
365
|
+
let memoized = false
|
|
366
|
+
|
|
367
|
+
return (...args: A): R => {
|
|
368
|
+
if (!memoized) {
|
|
369
|
+
memoizedValue = getter(...args)
|
|
370
|
+
memoized = true
|
|
371
|
+
}
|
|
372
|
+
return memoizedValue
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* @internal
|
|
378
|
+
*/
|
|
379
|
+
export const identityFn = <T>(x: T): T => x
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* @internal
|
|
383
|
+
*/
|
|
384
|
+
export const mobx6 = {
|
|
385
|
+
// eslint-disable-next-line no-useless-concat
|
|
386
|
+
makeObservable: (mobx as any)[
|
|
387
|
+
// just to ensure import * is kept properly
|
|
388
|
+
String.fromCharCode("l".charCodeAt(0) + 1) + "akeObservable"
|
|
389
|
+
],
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* @internal
|
|
394
|
+
*/
|
|
395
|
+
export function propNameToSetterName(propName: string): string {
|
|
396
|
+
return `set${propName[0].toUpperCase()}${propName.slice(1)}`
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* @internal
|
|
401
|
+
*/
|
|
402
|
+
export function getMobxVersion(): number {
|
|
403
|
+
if (mobx6.makeObservable!) {
|
|
404
|
+
return 6
|
|
405
|
+
} else {
|
|
406
|
+
return 5
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* @internal
|
|
412
|
+
*/
|
|
413
|
+
export const namespace = "mobx-keystone"
|