forked from mobxjs/serializr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
map.ts
70 lines (69 loc) · 2.8 KB
/
map.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import {
invariant,
isAliasedPropSchema,
isPropSchema,
isMapLike,
processAdditionalPropArgs,
} from "../utils/utils"
import { _defaultPrimitiveProp } from "../constants"
import list from "./list"
import { PropSchema, AdditionalPropArgs } from "../api/types"
/**
* Similar to list, but map represents a string keyed dynamic collection.
* This can be both plain objects (default) or ES6 Map like structures.
* This will be inferred from the initial value of the targetted attribute.
*
* @param additionalArgs optional object that contains beforeDeserialize and/or afterDeserialize handlers
*/
export default function map(
propSchema: PropSchema,
additionalArgs?: AdditionalPropArgs
): PropSchema {
propSchema = propSchema || _defaultPrimitiveProp
invariant(isPropSchema(propSchema), "expected prop schema as first argument")
invariant(
!isAliasedPropSchema(propSchema),
"provided prop is aliased, please put aliases first"
)
let result: PropSchema = {
serializer: function (m: Map<any, any> | { [key: string]: any }) {
invariant(m && typeof m === "object", "expected object or Map")
const result: { [key: string]: any } = {}
if (isMapLike(m)) {
m.forEach((value, key) => (result[key] = propSchema.serializer(value, key, m)))
} else {
for (const key in m) result[key] = propSchema.serializer(m[key], key, m)
}
return result
},
deserializer: function (jsonObject, done, context, oldValue) {
if (!jsonObject || typeof jsonObject !== "object")
return void done("[serializr] expected JSON object")
const keys = Object.keys(jsonObject)
list(propSchema, additionalArgs).deserializer(
keys.map(function (key) {
return jsonObject[key]
}),
function (err, values) {
if (err) return void done(err)
const isMap = isMapLike(oldValue)
let newValue
if (isMap) {
// if the oldValue is a map, we recycle it
// there are many variations and this way we don't have to
// know about the original constructor
oldValue.clear()
newValue = oldValue
} else newValue = {}
for (let i = 0, l = keys.length; i < l; i++)
if (isMap) newValue.set(keys[i], values[i])
else newValue[keys[i]] = values[i]
done(null, newValue)
},
context
)
},
}
result = processAdditionalPropArgs(result, additionalArgs)
return result
}