forked from gcanti/tcomb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
interface.js
131 lines (110 loc) · 3.83 KB
/
interface.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
var assert = require('./assert');
var isTypeName = require('./isTypeName');
var String = require('./String');
var Function = require('./Function');
var isBoolean = require('./isBoolean');
var isObject = require('./isObject');
var isNil = require('./isNil');
var create = require('./create');
var getTypeName = require('./getTypeName');
var dict = require('./dict');
var getDefaultInterfaceName = require('./getDefaultInterfaceName');
var isIdentity = require('./isIdentity');
var is = require('./is');
var extend = require('./extend');
var assign = require('./assign');
function extendInterface(mixins, name) {
return extend(inter, mixins, name);
}
function getOptions(options) {
if (!isObject(options)) {
options = isNil(options) ? {} : { name: options };
}
if (!options.hasOwnProperty('strict')) {
options.strict = inter.strict;
}
return options;
}
function inter(props, options) {
options = getOptions(options);
var name = options.name;
var strict = options.strict;
if (process.env.NODE_ENV !== 'production') {
assert(dict(String, Function).is(props), function () { return 'Invalid argument props ' + assert.stringify(props) + ' supplied to interface(props, [options]) combinator (expected a dictionary String -> Type)'; });
assert(isTypeName(name), function () { return 'Invalid argument name ' + assert.stringify(name) + ' supplied to interface(props, [options]) combinator (expected a string)'; });
assert(isBoolean(strict), function () { return 'Invalid argument strict ' + assert.stringify(strict) + ' supplied to struct(props, [options]) combinator (expected a boolean)'; });
}
var displayName = name || getDefaultInterfaceName(props);
var identity = Object.keys(props).map(function (prop) { return props[prop]; }).every(isIdentity);
function Interface(value, path) {
if (process.env.NODE_ENV === 'production') {
if (identity) {
return value; // just trust the input if elements must not be hydrated
}
}
if (process.env.NODE_ENV !== 'production') {
path = path || [displayName];
assert(!isNil(value), function () { return 'Invalid value ' + value + ' supplied to ' + path.join('/'); });
// strictness
if (strict) {
for (var k in value) {
assert(props.hasOwnProperty(k), function () { return 'Invalid additional prop "' + k + '" supplied to ' + path.join('/'); });
}
}
}
var idempotent = true;
var ret = identity ? {} : assign({}, value);
for (var prop in props) {
var expected = props[prop];
var actual = value[prop];
var instance = create(expected, actual, ( process.env.NODE_ENV !== 'production' ? path.concat(prop + ': ' + getTypeName(expected)) : null ));
idempotent = idempotent && ( actual === instance );
ret[prop] = instance;
}
if (idempotent) { // implements idempotency
ret = value;
}
if (process.env.NODE_ENV !== 'production') {
Object.freeze(ret);
}
return ret;
}
Interface.meta = {
kind: 'interface',
props: props,
name: name,
identity: identity,
strict: strict
};
Interface.displayName = displayName;
Interface.is = function (x) {
if (isNil(x)) {
return false;
}
if (strict) {
for (var k in x) {
if (!props.hasOwnProperty(k)) {
return false;
}
}
}
for (var prop in props) {
if (!is(x[prop], props[prop])) {
return false;
}
}
return true;
};
Interface.update = function (instance, patch) {
return Interface(assert.update(instance, patch));
};
Interface.extend = function (xs, name) {
return extendInterface([Interface].concat(xs), name);
};
return Interface;
}
inter.strict = false;
inter.getOptions = getOptions;
inter.getDefaultName = getDefaultInterfaceName;
inter.extend = extendInterface;
module.exports = inter;