forked from gcanti/tcomb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fromJSON.js
155 lines (138 loc) · 5.86 KB
/
fromJSON.js
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
var assert = require('./assert');
var isFunction = require('./isFunction');
var isNil = require('./isNil');
var getTypeName = require('./getTypeName');
var isObject = require('./isObject');
var isArray = require('./isArray');
var isType = require('./isType');
var create = require('./create');
var assign = require('./assign');
function assignMany(values) {
return values.reduce(function (acc, v) {
return assign(acc, v);
}, {});
}
function fromJSON(value, type, path) {
if (process.env.NODE_ENV !== 'production') {
assert(isFunction(type), function () {
return 'Invalid argument type ' + assert.stringify(type) + ' supplied to fromJSON(value, type) (expected a type)';
});
path = path || [getTypeName(type)];
}
if (isFunction(type.fromJSON)) {
return create(type, type.fromJSON(value), path);
}
if (!isType(type)) {
return value instanceof type ? value : new type(value);
}
var kind = type.meta.kind;
var k;
var ret;
switch (kind) {
case 'maybe' :
return isNil(value) ? null : fromJSON(value, type.meta.type, path);
case 'subtype' : // the kind of a refinement is 'subtype' (for legacy reasons)
ret = fromJSON(value, type.meta.type, path);
if (process.env.NODE_ENV !== 'production') {
assert(type.meta.predicate(ret), function () {
return 'Invalid argument value ' + assert.stringify(value) + ' supplied to fromJSON(value, type) (expected a valid ' + getTypeName(type) + ')';
});
}
return ret;
case 'struct' :
if (process.env.NODE_ENV !== 'production') {
assert(isObject(value), function () {
return 'Invalid argument value ' + assert.stringify(value) + ' supplied to fromJSON(value, type) (expected an object for type ' + getTypeName(type) + ')';
});
}
var props = type.meta.props;
var defaultProps = type.meta.defaultProps;
ret = {};
for (k in props) {
var actual = value[k];
if (actual === undefined) {
actual = defaultProps[k];
}
if (props.hasOwnProperty(k)) {
ret[k] = fromJSON(actual, props[k], ( process.env.NODE_ENV !== 'production' ? path.concat(k + ': ' + getTypeName(props[k])) : null ));
}
}
return new type(ret);
case 'interface' :
if (process.env.NODE_ENV !== 'production') {
assert(isObject(value), function () {
return 'Invalid argument value ' + assert.stringify(value) + ' supplied to fromJSON(value, type) (expected an object)';
});
}
var interProps = type.meta.props;
ret = {};
for (k in interProps) {
if (interProps.hasOwnProperty(k)) {
ret[k] = fromJSON(value[k], interProps[k], ( process.env.NODE_ENV !== 'production' ? path.concat(k + ': ' + getTypeName(interProps[k])) : null ));
}
}
return ret;
case 'list' :
if (process.env.NODE_ENV !== 'production') {
assert(isArray(value), function () {
return 'Invalid argument value ' + assert.stringify(value) + ' supplied to fromJSON(value, type) (expected an array for type ' + getTypeName(type) + ')';
});
}
var elementType = type.meta.type;
var elementTypeName = getTypeName(elementType);
return value.map(function (element, i) {
return fromJSON(element, elementType, ( process.env.NODE_ENV !== 'production' ? path.concat(i + ': ' + elementTypeName) : null ));
});
case 'union' :
var actualType = type.dispatch(value);
if (process.env.NODE_ENV !== 'production') {
assert(isFunction(actualType), function () {
return 'Invalid argument value ' + assert.stringify(value) + ' supplied to fromJSON(value, type) (no constructor returned by dispatch of union ' + getTypeName(type) + ')';
});
}
return fromJSON(value, actualType, path);
case 'tuple' :
if (process.env.NODE_ENV !== 'production') {
assert(isArray(value), function () {
return 'Invalid argument value ' + assert.stringify(value) + ' supplied to fromJSON(value, type) (expected an array for type ' + getTypeName(type) + ')';
});
}
var types = type.meta.types;
if (process.env.NODE_ENV !== 'production') {
assert(isArray(value) && value.length === types.length, function () {
return 'Invalid value ' + assert.stringify(value) + ' supplied to fromJSON(value, type) (expected an array of length ' + types.length + ' for type ' + getTypeName(type) + ')';
});
}
return value.map(function (element, i) {
return fromJSON(element, types[i], ( process.env.NODE_ENV !== 'production' ? path.concat(i + ': ' + getTypeName(types[i])) : null ));
});
case 'dict' :
if (process.env.NODE_ENV !== 'production') {
assert(isObject(value), function () {
return 'Invalid argument value ' + assert.stringify(value) + ' supplied to fromJSON(value, type) (expected an object for type ' + getTypeName(type) + ')';
});
}
var domain = type.meta.domain;
var codomain = type.meta.codomain;
var domainName = getTypeName(domain);
var codomainName = getTypeName(codomain);
ret = {};
for (k in value) {
if (value.hasOwnProperty(k)) {
ret[domain(k, ( process.env.NODE_ENV !== 'production' ? path.concat(domainName) : null ))] = fromJSON(value[k], codomain, ( process.env.NODE_ENV !== 'production' ? path.concat(k + ': ' + codomainName) : null ));
}
}
return ret;
case 'intersection' :
var values = type.meta.types.map(function (type, i) {
return fromJSON(value, type, ( process.env.NODE_ENV !== 'production' ? path.concat(i + ': ' + getTypeName(type)) : null ));
});
return type(
isObject(values[0]) ? assignMany(values) : value,
path
);
default : // enums, irreducible
return type(value, path);
}
}
module.exports = fromJSON;