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;