var assert = require('./assert'); var isTypeName = require('./isTypeName'); var isType = require('./isType'); var isNil = require('./isNil'); var mixin = require('./mixin'); var getTypeName = require('./getTypeName'); var isUnion = require('./isUnion'); // All the .declare-d types should be clearly different from each other thus they should have // different names when a name was not explicitly provided. var nextDeclareUniqueId = 1; module.exports = function declare(name) { if (process.env.NODE_ENV !== 'production') { assert(isTypeName(name), function () { return 'Invalid argument name ' + name + ' supplied to declare([name]) (expected a string)'; }); } var type; function Declare(value, path) { if (process.env.NODE_ENV !== 'production') { assert(!isNil(type), function () { return 'Type declared but not defined, don\'t forget to call .define on every declared type'; }); if (isUnion(type)) { assert(type.dispatch === Declare.dispatch, function () { return 'Please define the custom ' + name + '.dispatch function before calling ' + name + '.define()'; }); } } return type(value, path); } Declare.define = function (spec) { if (process.env.NODE_ENV !== 'production') { assert(isType(spec), function () { return 'Invalid argument type ' + assert.stringify(spec) + ' supplied to define(type) (expected a type)'; }); assert(isNil(type), function () { return 'Declare.define(type) can only be invoked once'; }); // assert(isNil(spec.meta.name) && Object.keys(spec.prototype).length === 0, function () { return 'Invalid argument type ' + assert.stringify(spec) + ' supplied to define(type) (expected a fresh, unnamed type)'; }); } if (isUnion(spec) && Declare.hasOwnProperty('dispatch')) { spec.dispatch = Declare.dispatch; } type = spec; mixin(Declare, type, true); // true because it overwrites Declare.displayName if (name) { type.displayName = Declare.displayName = name; Declare.meta.name = name; } Declare.meta.identity = type.meta.identity; Declare.prototype = type.prototype; return Declare; }; Declare.displayName = name || ( getTypeName(Declare) + "$" + nextDeclareUniqueId++ ); // in general I can't say if this type will be an identity, for safety setting to false Declare.meta = { identity: false }; Declare.prototype = null; return Declare; };