var assert = require('./assert'); var isTypeName = require('./isTypeName'); var isFunction = require('./isFunction'); var forbidNewOperator = require('./forbidNewOperator'); var isIdentity = require('./isIdentity'); var create = require('./create'); var is = require('./is'); var getTypeName = require('./getTypeName'); var getFunctionName = require('./getFunctionName'); function getDefaultName(type, predicate) { return '{' + getTypeName(type) + ' | ' + getFunctionName(predicate) + '}'; } function refinement(type, predicate, name) { if (process.env.NODE_ENV !== 'production') { assert(isFunction(type), function () { return 'Invalid argument type ' + assert.stringify(type) + ' supplied to refinement(type, predicate, [name]) combinator (expected a type)'; }); assert(isFunction(predicate), function () { return 'Invalid argument predicate supplied to refinement(type, predicate, [name]) combinator (expected a function)'; }); assert(isTypeName(name), function () { return 'Invalid argument name ' + assert.stringify(name) + ' supplied to refinement(type, predicate, [name]) combinator (expected a string)'; }); } var displayName = name || getDefaultName(type, predicate); var identity = isIdentity(type); function Refinement(value, path) { if (process.env.NODE_ENV !== 'production') { if (identity) { forbidNewOperator(this, Refinement); } path = path || [displayName]; } var x = create(type, value, path); if (process.env.NODE_ENV !== 'production') { assert(predicate(x), function () { return 'Invalid value ' + assert.stringify(value) + ' supplied to ' + path.join('/'); }); } return x; } Refinement.meta = { kind: 'subtype', type: type, predicate: predicate, name: name, identity: identity }; Refinement.displayName = displayName; Refinement.is = function (x) { return is(x, type) && predicate(x); }; Refinement.update = function (instance, patch) { return Refinement(assert.update(instance, patch)); }; return Refinement; } refinement.getDefaultName = getDefaultName; module.exports = refinement;