83 lines
2.4 KiB
JavaScript
83 lines
2.4 KiB
JavaScript
var assert = require('./assert');
|
|
var isTypeName = require('./isTypeName');
|
|
var isFunction = require('./isFunction');
|
|
var getTypeName = require('./getTypeName');
|
|
var isIdentity = require('./isIdentity');
|
|
var isArray = require('./isArray');
|
|
var create = require('./create');
|
|
var is = require('./is');
|
|
|
|
function getDefaultName(types) {
|
|
return '[' + types.map(getTypeName).join(', ') + ']';
|
|
}
|
|
|
|
function tuple(types, name) {
|
|
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
assert(isArray(types) && types.every(isFunction), function () { return 'Invalid argument types ' + assert.stringify(types) + ' supplied to tuple(types, [name]) combinator (expected an array of types)'; });
|
|
assert(isTypeName(name), function () { return 'Invalid argument name ' + assert.stringify(name) + ' supplied to tuple(types, [name]) combinator (expected a string)'; });
|
|
}
|
|
|
|
var displayName = name || getDefaultName(types);
|
|
var identity = types.every(isIdentity);
|
|
|
|
function Tuple(value, path) {
|
|
|
|
if (process.env.NODE_ENV === 'production') {
|
|
if (identity) {
|
|
return value;
|
|
}
|
|
}
|
|
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
path = path || [displayName];
|
|
assert(isArray(value) && value.length === types.length, function () { return 'Invalid value ' + assert.stringify(value) + ' supplied to ' + path.join('/') + ' (expected an array of length ' + types.length + ')'; });
|
|
}
|
|
|
|
var idempotent = true;
|
|
var ret = [];
|
|
for (var i = 0, len = types.length; i < len; i++) {
|
|
var expected = types[i];
|
|
var actual = value[i];
|
|
var instance = create(expected, actual, ( process.env.NODE_ENV !== 'production' ? path.concat(i + ': ' + getTypeName(expected)) : null ));
|
|
idempotent = idempotent && ( actual === instance );
|
|
ret.push(instance);
|
|
}
|
|
|
|
if (idempotent) { // implements idempotency
|
|
ret = value;
|
|
}
|
|
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
Object.freeze(ret);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
Tuple.meta = {
|
|
kind: 'tuple',
|
|
types: types,
|
|
name: name,
|
|
identity: identity
|
|
};
|
|
|
|
Tuple.displayName = displayName;
|
|
|
|
Tuple.is = function (x) {
|
|
return isArray(x) &&
|
|
x.length === types.length &&
|
|
types.every(function (type, i) {
|
|
return is(x[i], type);
|
|
});
|
|
};
|
|
|
|
Tuple.update = function (instance, patch) {
|
|
return Tuple(assert.update(instance, patch));
|
|
};
|
|
|
|
return Tuple;
|
|
}
|
|
|
|
tuple.getDefaultName = getDefaultName;
|
|
module.exports = tuple; |