diff --git a/README.md b/README.md index 4f15515a7..7834a74a2 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ json separate from validating it, via the `cast` method. - [`string.matches(regex: Regex, message: ?string): Schema`](#stringmatchesregex-regex-message-string-schema) - [`string.email(message: ?string): Schema`](#stringemailmessage-string-schema) - [`string.url(message: ?string): Schema`](#stringurlmessage-string-schema) + - [`string.ensure(): Schema`](#stringensure-schema) - [`string.trim(message: ?string): Schema`](#stringtrimmessage-string-schema) - [`string.lowercase(message: ?string): Schema`](#stringlowercasemessage-string-schema) - [`string.uppercase(message: ?string): Schema`](#stringuppercasemessage-string-schema) @@ -64,7 +65,8 @@ json separate from validating it, via the `cast` method. - [`number.positive(message: ?string): Schema`](#numberpositivemessage-string-schema) - [`number.negative(message: ?string): Schema`](#numbernegativemessage-string-schema) - [`number.integer(message: ?string): Schema`](#numberintegermessage-string-schema) - - [`number.round(type: 'floor' | 'ceil' | 'round' = 'round'): Schema`](#numberroundtype-floor--ceil--round--round-schema) + - [`number.truncate(): Schema`](#numbertruncate-schema) + - [`number.round(type: 'floor' | 'ceil' | 'trunc' | 'round' = 'round'): Schema`](#numberroundtype-floor--ceil--trunc--round--round-schema) - [boolean](#boolean) - [date](#date) - [`date.min(limit: Date | string | Ref, message: ?string): Schema`](#dateminlimit-date--string--ref-message-string-schema) diff --git a/lib/Condition.js b/lib/Condition.js new file mode 100644 index 000000000..cd127df10 --- /dev/null +++ b/lib/Condition.js @@ -0,0 +1,78 @@ +'use strict'; + +exports.__esModule = true; + +var _has = require('lodash/has'); + +var _has2 = _interopRequireDefault(_has); + +var _isSchema = require('./util/isSchema'); + +var _isSchema2 = _interopRequireDefault(_isSchema); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Conditional = function () { + function Conditional(refs, options) { + var _this = this; + + _classCallCheck(this, Conditional); + + var is = options.is; + var then = options.then; + var otherwise = options.otherwise; + + + this.refs = [].concat(refs); + + if (typeof options === 'function') this.fn = options;else { + (function () { + if (!(0, _has2.default)(options, 'is')) throw new TypeError('`is:` is required for `when()` conditions'); + + if (!options.then && !options.otherwise) throw new TypeError('either `then:` or `otherwise:` is required for `when()` conditions'); + + var isFn = typeof is === 'function' ? is : function () { + for (var _len = arguments.length, values = Array(_len), _key = 0; _key < _len; _key++) { + values[_key] = arguments[_key]; + } + + return values.every(function (value) { + return value === is; + }); + }; + + _this.fn = function () { + for (var _len2 = arguments.length, values = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + values[_key2] = arguments[_key2]; + } + + var ctx = values.pop(); + return isFn.apply(undefined, values) ? ctx.concat(then) : ctx.concat(otherwise); + }; + })(); + } + } + + Conditional.prototype.getValue = function getValue(parent, context) { + var values = this.refs.map(function (r) { + return r.getValue(parent, context); + }); + + return values; + }; + + Conditional.prototype.resolve = function resolve(ctx, values) { + var schema = this.fn.apply(ctx, values.concat(ctx)); + + if (schema !== undefined && !(0, _isSchema2.default)(schema)) throw new TypeError('conditions must return a schema object'); + + return schema || ctx; + }; + + return Conditional; +}(); + +exports.default = Conditional; +module.exports = exports['default']; \ No newline at end of file diff --git a/lib/Lazy.js b/lib/Lazy.js new file mode 100644 index 000000000..17b7e8788 --- /dev/null +++ b/lib/Lazy.js @@ -0,0 +1,49 @@ +'use strict'; + +exports.__esModule = true; + +var _isSchema = require('./util/isSchema'); + +var _isSchema2 = _interopRequireDefault(_isSchema); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Lazy = function () { + function Lazy(mapFn) { + _classCallCheck(this, Lazy); + + this._resolve = function () { + var schema = mapFn.apply(undefined, arguments); + if (!(0, _isSchema2.default)(schema)) throw new TypeError('lazy() functions must return a valid schema'); + + return schema; + }; + } + + Lazy.prototype.resolve = function resolve(_ref) { + var value = _ref.value; + + var rest = _objectWithoutProperties(_ref, ['value']); + + return this._resolve(value, rest); + }; + + Lazy.prototype.cast = function cast(value, options) { + return this._resolve(value, options).cast(value, options); + }; + + Lazy.prototype.validate = function validate(value, options) { + return this._resolve(value, options).validate(value, options); + }; + + return Lazy; +}(); + +Lazy.prototype.__isYupSchema__ = true; + +exports.default = Lazy; +module.exports = exports['default']; \ No newline at end of file diff --git a/lib/Reference.js b/lib/Reference.js new file mode 100644 index 000000000..808ee43e6 --- /dev/null +++ b/lib/Reference.js @@ -0,0 +1,62 @@ +'use strict'; + +exports.__esModule = true; + +var _propertyExpr = require('property-expr'); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var validateName = function validateName(d) { + if (typeof d !== 'string') throw new TypeError('ref\'s must be strings, got: ' + d); +}; + +var Reference = function () { + Reference.isRef = function isRef(value) { + return !!(value && (value.__isYupRef || value instanceof Reference)); + }; + + function Reference(key, mapFn) { + var options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; + + _classCallCheck(this, Reference); + + validateName(key); + var prefix = options.contextPrefix || '$'; + + if (typeof key === 'function') { + key = '.'; + } + + this.key = key.trim(); + this.prefix = prefix; + this.isContext = this.key.indexOf(prefix) === 0; + this.isSelf = this.key === '.'; + + this.path = this.isContext ? this.key.slice(this.prefix.length) : this.key; + this._get = (0, _propertyExpr.getter)(this.path, true); + this.map = mapFn || function (value) { + return value; + }; + } + + Reference.prototype.cast = function cast(value, _ref) { + var parent = _ref.parent; + var context = _ref.context; + + return this.getValue(parent, context); + }; + + Reference.prototype.getValue = function getValue(parent, context) { + var isContext = this.isContext; + var value = this._get(isContext ? context : parent || context || {}); + return this.map(value); + }; + + return Reference; +}(); + +exports.default = Reference; + + +Reference.prototype.__isYupRef = true; +module.exports = exports['default']; \ No newline at end of file diff --git a/lib/ValidationError.js b/lib/ValidationError.js new file mode 100644 index 000000000..64de1ba5a --- /dev/null +++ b/lib/ValidationError.js @@ -0,0 +1,61 @@ +'use strict'; + +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } + +var strReg = /\$\{\s*(\w+)\s*\}/g; + +var replace = function replace(str) { + return function (params) { + return str.replace(strReg, function (_, key) { + return params[key] || ''; + }); + }; +}; + +module.exports = ValidationError; + +function ValidationError(errors, value, field, type) { + var _this = this; + + this.name = 'ValidationError'; + this.value = value; + this.path = field; + this.type = type; + this.errors = []; + this.inner = []; + + if (errors) [].concat(errors).forEach(function (err) { + _this.errors = _this.errors.concat(err.errors || err); + + if (err.inner) _this.inner = _this.inner.concat(err.inner.length ? err.inner : err); + }); + + this.message = this.errors.length > 1 ? this.errors.length + ' errors occurred' : this.errors[0]; + + if (Error.captureStackTrace) Error.captureStackTrace(this, ValidationError); +} + +ValidationError.prototype = Object.create(Error.prototype); +ValidationError.prototype.constructor = ValidationError; + +ValidationError.isError = function (err) { + return err && err.name === 'ValidationError'; +}; + +ValidationError.formatError = function (message, params) { + + if (typeof message === 'string') message = replace(message); + + var fn = function fn(_ref) { + var path = _ref.path; + var label = _ref.label; + + var params = _objectWithoutProperties(_ref, ['path', 'label']); + + params.path = label || path || 'this'; + + return message(params); + }; + + return arguments.length === 1 ? fn : fn(params); +}; \ No newline at end of file diff --git a/lib/array.js b/lib/array.js index aa5e6bad4..4a41c2e87 100644 --- a/lib/array.js +++ b/lib/array.js @@ -1,41 +1,42 @@ 'use strict'; +exports.__esModule = true; + var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; -var MixedSchema = require('./mixed'); -var Promise = require('universal-promise'); -var isAbsent = require('./util/isAbsent'); +var _inherits = require('./util/inherits'); -var _require = require('./locale.js'); +var _inherits2 = _interopRequireDefault(_inherits); -var mixed = _require.mixed; -var locale = _require.array; +var _isAbsent = require('./util/isAbsent'); -var _require2 = require('./util/_'); +var _isAbsent2 = _interopRequireDefault(_isAbsent); -var inherits = _require2.inherits; -var collectErrors = _require2.collectErrors; +var _mixed = require('./mixed'); +var _mixed2 = _interopRequireDefault(_mixed); -var scopeError = function scopeError(value) { - return function (err) { - err.value = value; - throw err; - }; -}; +var _locale = require('./locale.js'); + +var _runValidations = require('./util/runValidations'); + +var _runValidations2 = _interopRequireDefault(_runValidations); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var hasLength = function hasLength(value) { - return !isAbsent(value) && value.length > 0; + return !(0, _isAbsent2.default)(value) && value.length > 0; }; -module.exports = ArraySchema; +exports.default = ArraySchema; + function ArraySchema(type) { var _this = this; if (!(this instanceof ArraySchema)) return new ArraySchema(type); - MixedSchema.call(this, { type: 'array' }); + _mixed2.default.call(this, { type: 'array' }); this._subType = null; @@ -54,14 +55,14 @@ function ArraySchema(type) { }); } -inherits(ArraySchema, MixedSchema, { +(0, _inherits2.default)(ArraySchema, _mixed2.default, { _typeCheck: function _typeCheck(v) { return Array.isArray(v); }, _cast: function _cast(_value, _opts) { var _this2 = this; - var value = MixedSchema.prototype._cast.call(this, _value, _opts); + var value = _mixed2.default.prototype._cast.call(this, _value, _opts); //should ignore nulls here if (!this._typeCheck(value) || !this._subType) return value; @@ -75,39 +76,39 @@ inherits(ArraySchema, MixedSchema, { var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; - var errors = [], - subType, - endEarly, - recursive; - - subType = this._subType; - endEarly = this._option('abortEarly', options); - recursive = this._option('recursive', options); + var errors = []; + var path = options.path; + var subType = this._subType; + var endEarly = this._option('abortEarly', options); + var recursive = this._option('recursive', options); - return MixedSchema.prototype._validate.call(this, _value, options).catch(endEarly ? null : function (err) { - errors = err; - return err.value; - }).then(function (value) { + return _mixed2.default.prototype._validate.call(this, _value, options).catch((0, _runValidations.propagateErrors)(endEarly, errors)).then(function (value) { if (!recursive || !subType || !_this3._typeCheck(value)) { if (errors.length) throw errors[0]; return value; } - var validations = value.map(function (item, key) { - var path = (options.path || '') + '[' + key + ']'; + var validations = value.map(function (item, idx) { + var path = (options.path || '') + '[' + idx + ']'; // object._validate note for isStrict explanation - var innerOptions = _extends({}, options, { path: path, key: key, strict: true, parent: value }); + var innerOptions = _extends({}, options, { + path: path, + strict: true, + parent: value + }); if (subType.validate) return subType.validate(item, innerOptions); return true; }); - validations = endEarly ? Promise.all(validations).catch(scopeError(value)) : collectErrors({ validations: validations, value: value, errors: errors, path: options.path }); - - return validations.then(function () { - return value; + return (0, _runValidations2.default)({ + path: path, + value: value, + errors: errors, + endEarly: endEarly, + validations: validations }); }); }, @@ -117,12 +118,12 @@ inherits(ArraySchema, MixedSchema, { return next; }, required: function required(msg) { - var next = MixedSchema.prototype.required.call(this, msg || mixed.required); + var next = _mixed2.default.prototype.required.call(this, msg || _locale.mixed.required); - return next.test('required', msg || mixed.required, hasLength); + return next.test('required', msg || _locale.mixed.required, hasLength); }, min: function min(_min, message) { - message = message || locale.min; + message = message || _locale.array.min; return this.test({ message: message, @@ -130,25 +131,27 @@ inherits(ArraySchema, MixedSchema, { exclusive: true, params: { min: _min }, test: function test(value) { - return isAbsent(value) || value.length >= this.resolve(_min); + return (0, _isAbsent2.default)(value) || value.length >= this.resolve(_min); } }); }, max: function max(_max, message) { - message = message || locale.max; + message = message || _locale.array.max; return this.test({ message: message, name: 'max', exclusive: true, params: { max: _max }, test: function test(value) { - return isAbsent(value) || value.length <= this.resolve(_max); + return (0, _isAbsent2.default)(value) || value.length <= this.resolve(_max); } }); }, ensure: function ensure() { - return this.default([]).transform(function (val) { - return val == null ? [] : [].concat(val); + return this.default(function () { + return []; + }).transform(function (val) { + return val === null ? [] : [].concat(val); }); }, compact: function compact(rejector) { @@ -162,4 +165,5 @@ inherits(ArraySchema, MixedSchema, { return values != null ? values.filter(reject) : values; }); } -}); \ No newline at end of file +}); +module.exports = exports['default']; \ No newline at end of file diff --git a/lib/boolean.js b/lib/boolean.js index c3af93d5e..2701650e0 100644 --- a/lib/boolean.js +++ b/lib/boolean.js @@ -1,30 +1,43 @@ 'use strict'; -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; }; +exports.__esModule = true; -var MixedSchema = require('./mixed'), - inherits = require('./util/_').inherits; +var _inherits = require('./util/inherits'); + +var _inherits2 = _interopRequireDefault(_inherits); + +var _mixed = require('./mixed'); + +var _mixed2 = _interopRequireDefault(_mixed); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +exports.default = BooleanSchema; -module.exports = BooleanSchema; function BooleanSchema() { var _this = this; if (!(this instanceof BooleanSchema)) return new BooleanSchema(); - MixedSchema.call(this, { type: 'boolean' }); + _mixed2.default.call(this, { type: 'boolean' }); this.withMutation(function () { _this.transform(function (value) { - if (this.isType(value)) return value; - return (/true|1/i.test(value) - ); + if (!this.isType(value)) { + if (/^(true|1)$/i.test(value)) return true; + if (/^(false|0)$/i.test(value)) return false; + } + return value; }); }); } -inherits(BooleanSchema, MixedSchema, { +(0, _inherits2.default)(BooleanSchema, _mixed2.default, { _typeCheck: function _typeCheck(v) { - return typeof v === 'boolean' || (typeof v === 'undefined' ? 'undefined' : _typeof(v)) === 'object' && v instanceof Boolean; + if (v instanceof Boolean) v = v.valueOf(); + + return typeof v === 'boolean'; } -}); \ No newline at end of file +}); +module.exports = exports['default']; \ No newline at end of file diff --git a/lib/date.js b/lib/date.js index 9e632d894..6dc93b614 100644 --- a/lib/date.js +++ b/lib/date.js @@ -1,46 +1,65 @@ 'use strict'; -var MixedSchema = require('./mixed'); -var isoParse = require('./util/isodate'); -var locale = require('./locale.js').date; -var isAbsent = require('./util/isAbsent'); -var Ref = require('./util/reference'); +exports.__esModule = true; -var _require = require('./util/_'); +var _mixed = require('./mixed'); -var isDate = _require.isDate; -var inherits = _require.inherits; +var _mixed2 = _interopRequireDefault(_mixed); +var _inherits = require('./util/inherits'); + +var _inherits2 = _interopRequireDefault(_inherits); + +var _isodate = require('./util/isodate'); + +var _isodate2 = _interopRequireDefault(_isodate); + +var _locale = require('./locale.js'); + +var _isAbsent = require('./util/isAbsent'); + +var _isAbsent2 = _interopRequireDefault(_isAbsent); + +var _Reference = require('./Reference'); + +var _Reference2 = _interopRequireDefault(_Reference); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var invalidDate = new Date(''); -module.exports = DateSchema; +var isDate = function isDate(obj) { + return Object.prototype.toString.call(obj) === '[object Date]'; +}; + +exports.default = DateSchema; + function DateSchema() { var _this = this; if (!(this instanceof DateSchema)) return new DateSchema(); - MixedSchema.call(this, { type: 'date' }); + _mixed2.default.call(this, { type: 'date' }); this.withMutation(function () { _this.transform(function (value) { if (this.isType(value)) return isDate(value) ? new Date(value) : value; - value = isoParse(value); + value = (0, _isodate2.default)(value); return value ? new Date(value) : invalidDate; }); }); } -inherits(DateSchema, MixedSchema, { +(0, _inherits2.default)(DateSchema, _mixed2.default, { _typeCheck: function _typeCheck(v) { return isDate(v) && !isNaN(v.getTime()); }, min: function min(_min, msg) { var limit = _min; - if (!Ref.isRef(limit)) { + if (!_Reference2.default.isRef(limit)) { limit = this.cast(_min); if (!this._typeCheck(limit)) throw new TypeError('`min` must be a Date or a value that can be `cast()` to a Date'); } @@ -48,17 +67,17 @@ inherits(DateSchema, MixedSchema, { return this.test({ name: 'min', exclusive: true, - message: msg || locale.min, + message: msg || _locale.date.min, params: { min: _min }, test: function test(value) { - return isAbsent(value) || value >= this.resolve(limit); + return (0, _isAbsent2.default)(value) || value >= this.resolve(limit); } }); }, max: function max(_max, msg) { var limit = _max; - if (!Ref.isRef(limit)) { + if (!_Reference2.default.isRef(limit)) { limit = this.cast(_max); if (!this._typeCheck(limit)) throw new TypeError('`max` must be a Date or a value that can be `cast()` to a Date'); } @@ -66,11 +85,12 @@ inherits(DateSchema, MixedSchema, { return this.test({ name: 'max', exclusive: true, - message: msg || locale.max, + message: msg || _locale.date.max, params: { max: _max }, test: function test(value) { - return isAbsent(value) || value <= this.resolve(limit); + return (0, _isAbsent2.default)(value) || value <= this.resolve(limit); } }); } -}); \ No newline at end of file +}); +module.exports = exports['default']; \ No newline at end of file diff --git a/lib/index.js b/lib/index.js index 0bec7596b..8c3786c96 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,42 +1,58 @@ 'use strict'; -var mixed = require('./mixed'), - bool = require('./boolean'), - Ref = require('./util/reference'), - Lazy = require('./util/lazy'); +exports.__esModule = true; -var isSchema = function isSchema(schema) { - return schema && !!schema.__isYupSchema__; -}; +var _mixed = require('./mixed'); + +var _mixed2 = _interopRequireDefault(_mixed); + +var _boolean = require('./boolean'); + +var _boolean2 = _interopRequireDefault(_boolean); + +var _Reference = require('./Reference'); + +var _Reference2 = _interopRequireDefault(_Reference); -module.exports = { - mixed: mixed, +var _Lazy = require('./Lazy'); + +var _Lazy2 = _interopRequireDefault(_Lazy); + +var _isSchema = require('./util/isSchema'); + +var _isSchema2 = _interopRequireDefault(_isSchema); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +exports.default = { + mixed: _mixed2.default, string: require('./string'), number: require('./number'), - boolean: bool, - bool: bool, + boolean: _boolean2.default, + bool: _boolean2.default, date: require('./date'), object: require('./object'), array: require('./array'), reach: require('./util/reach'), - ValidationError: require('./util/validation-error'), + ValidationError: require('./ValidationError'), ref: function ref(key, options) { - return new Ref(key, options); + return new _Reference2.default(key, options); }, lazy: function lazy(fn) { - return new Lazy(fn); + return new _Lazy2.default(fn); }, - isSchema: isSchema, + isSchema: _isSchema2.default, addMethod: function addMethod(schemaType, name, fn) { - if (!schemaType || !isSchema(schemaType.prototype)) throw new TypeError('You must provide a yup schema constructor function'); + if (!schemaType || !(0, _isSchema2.default)(schemaType.prototype)) throw new TypeError('You must provide a yup schema constructor function'); if (typeof name !== 'string') throw new TypeError('A Method name must be provided'); if (typeof fn !== 'function') throw new TypeError('Method function must be provided'); schemaType.prototype[name] = fn; } -}; \ No newline at end of file +}; +module.exports = exports['default']; \ No newline at end of file diff --git a/lib/locale.js b/lib/locale.js index 43aa37c44..8d2929553 100644 --- a/lib/locale.js +++ b/lib/locale.js @@ -1,48 +1,57 @@ 'use strict'; -module.exports = { - mixed: { - default: '${path} is invalid', - notType: '${path} (value: `${value}`) must be a `${type}` type', - required: '${path} is a required field', - oneOf: '${path} must be one the following values: ${values}', - notOneOf: '${path} must not be one the following values: ${values}' - }, - - string: { - required: '${path} is a required field', - min: '${path} must be at least ${min} characters', - max: '${path} must be at most ${max} characters', - matches: '${path} must match the following: "${regex}"', - email: '${path} must be a valid email', - url: '${path} must be a valid URL', - trim: '${path} must be a trimmed string', - lowercase: '${path} must be a lowercase string', - uppercase: '${path} must be a upper case string' - }, - - number: { - min: '${path} must be greater than or equal to ${min}', - max: '${path} must be less than or equal to ${max}', - positive: '${path} must be a positive number', - negative: '${path} must be a negative number', - integer: '${path} must be an integer' - }, - - date: { - min: '${path} field must be later than ${min}', - max: '${path} field must be at earlier than ${max}' - }, - - boolean: {}, - - object: { - noUnknown: '${path} field cannot have keys not specified in the object shape' - }, - - array: { - required: '${path} is a required field', - min: '${path} field must have at least ${min} items', - max: '${path} field must have less than ${max} items' - } +exports.__esModule = true; +var mixed = exports.mixed = { + default: '${path} is invalid', + notType: '${path} must be a `${type}` type, got: "${value}" instead', + required: '${path} is a required field', + oneOf: '${path} must be one the following values: ${values}', + notOneOf: '${path} must not be one the following values: ${values}' +}; + +var string = exports.string = { + required: '${path} is a required field', + min: '${path} must be at least ${min} characters', + max: '${path} must be at most ${max} characters', + matches: '${path} must match the following: "${regex}"', + email: '${path} must be a valid email', + url: '${path} must be a valid URL', + trim: '${path} must be a trimmed string', + lowercase: '${path} must be a lowercase string', + uppercase: '${path} must be a upper case string' +}; + +var number = exports.number = { + min: '${path} must be greater than or equal to ${min}', + max: '${path} must be less than or equal to ${max}', + positive: '${path} must be a positive number', + negative: '${path} must be a negative number', + integer: '${path} must be an integer' +}; + +var date = exports.date = { + min: '${path} field must be later than ${min}', + max: '${path} field must be at earlier than ${max}' +}; + +var boolean = exports.boolean = {}; + +var object = exports.object = { + noUnknown: '${path} field cannot have keys not specified in the object shape' +}; + +var array = exports.array = { + required: '${path} is a required field', + min: '${path} field must have at least ${min} items', + max: '${path} field must have less than ${max} items' +}; + +exports.default = { + mixed: mixed, + string: string, + number: number, + date: date, + object: object, + array: array, + boolean: boolean }; \ No newline at end of file diff --git a/lib/mixed.js b/lib/mixed.js index b1cd8ff1c..76b920e13 100644 --- a/lib/mixed.js +++ b/lib/mixed.js @@ -2,30 +2,60 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; -var Promise = require('universal-promise'), - Condition = require('./util/condition'), - locale = require('./locale.js').mixed, - _ = require('./util/_'), - isAbsent = require('./util/isAbsent'), - cloneDeep = require('./util/clone'), - createValidation = require('./util/createValidation'), - BadSet = require('./util/set'), - Ref = require('./util/reference'); +var _typeName = require('type-name'); + +var _typeName2 = _interopRequireDefault(_typeName); + +var _has = require('lodash/has'); + +var _has2 = _interopRequireDefault(_has); + +var _locale = require('./locale'); + +var _Condition = require('./Condition'); + +var _Condition2 = _interopRequireDefault(_Condition); + +var _runValidations = require('./util/runValidations'); + +var _runValidations2 = _interopRequireDefault(_runValidations); + +var _merge = require('./util/merge'); + +var _merge2 = _interopRequireDefault(_merge); + +var _isAbsent = require('./util/isAbsent'); + +var _isAbsent2 = _interopRequireDefault(_isAbsent); + +var _clone = require('./util/clone'); + +var _clone2 = _interopRequireDefault(_clone); + +var _createValidation = require('./util/createValidation'); + +var _createValidation2 = _interopRequireDefault(_createValidation); + +var _set = require('./util/set'); + +var _set2 = _interopRequireDefault(_set); + +var _Reference = require('./Reference'); + +var _Reference2 = _interopRequireDefault(_Reference); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var notEmpty = function notEmpty(value) { - return !isAbsent(value); + return !(0, _isAbsent2.default)(value); }; -function runValidations(validations, endEarly, value, path) { - return endEarly ? Promise.all(validations) : _.collectErrors({ validations: validations, value: value, path: path }); -} - function extractTestParams(name, message, test, useCallback) { var opts = name; - if (typeof message === 'function') test = message, message = locale.default, name = null; + if (typeof message === 'function') test = message, message = _locale.mixed.default, name = null; - if (typeof name === 'function') test = name, message = locale.default, name = null; + if (typeof name === 'function') test = name, message = _locale.mixed.default, name = null; if (typeof name === 'string' || name === null) opts = { name: name, test: test, message: message, useCallback: useCallback, exclusive: false }; @@ -47,16 +77,16 @@ function SchemaType() { this._conditions = []; this._options = { abortEarly: true, recursive: true }; this._exclusive = Object.create(null); - this._whitelist = new BadSet(); - this._blacklist = new BadSet(); + this._whitelist = new _set2.default(); + this._blacklist = new _set2.default(); this.tests = []; this.transforms = []; this.withMutation(function () { - _this.typeError(locale.notType); + _this.typeError(_locale.mixed.notType); }); - if (_.has(options, 'default')) this._defaultDefault = options.default; + if ((0, _has2.default)(options, 'default')) this._defaultDefault = options.default; this._type = options.type || 'mixed'; } @@ -70,7 +100,7 @@ SchemaType.prototype = { clone: function clone() { if (this._mutate) return this; - return cloneDeep(this); + return (0, _clone2.default)(this); }, label: function label(_label) { var next = this.clone(); @@ -95,10 +125,10 @@ SchemaType.prototype = { if (schema._type !== this._type && this._type !== 'mixed') throw new TypeError('You cannot `concat()` schema\'s of different types: ' + this._type + ' and ' + schema._type); var cloned = this.clone(); - var next = _.merge(this.clone(), schema.clone()); + var next = (0, _merge2.default)(this.clone(), schema.clone()); // undefined isn't merged over, but is a valid value for default - if (schema._default === undefined && _.has(this, '_default')) next._default = schema._default; + if (schema._default === undefined && (0, _has2.default)(this, '_default')) next._default = schema._default; next.tests = cloned.tests; next._exclusive = cloned._exclusive; @@ -134,7 +164,13 @@ SchemaType.prototype = { var schema = this.resolve(opts); - return schema._cast(value, opts); + var result = schema._cast(value, opts); + + if (opts.assert !== false && !this.isType(result)) { + throw new TypeError('Expected ' + (opts.path || 'field') + ' to be type: "' + this._type + '". ' + ('Got "' + (0, _typeName2.default)(value) + '" instead.')); + } + + return result; }, _cast: function _cast(_value) { var _this2 = this; @@ -143,7 +179,7 @@ SchemaType.prototype = { return transform.call(_this2, value, _value); }, _value); - if (value === undefined && _.has(this, '_default')) { + if (value === undefined && (0, _has2.default)(this, '_default')) { value = this.default(); } @@ -180,7 +216,7 @@ SchemaType.prototype = { var label = this._label; if (!isStrict) { - value = this._cast(value, options, options); + value = this._cast(value, _extends({ assert: false }, options)); } // value is cast, we can check if it meets type requirements var validationParams = { value: value, path: path, schema: this, options: options, label: label }; @@ -192,12 +228,15 @@ SchemaType.prototype = { if (this._blacklistError) initialTests.push(this._blacklistError(validationParams)); - return runValidations(initialTests, endEarly, value, path).then(function () { - return runValidations(_this3.tests.map(function (fn) { - return fn(validationParams); - }), endEarly, value, path); - }).then(function () { - return value; + return (0, _runValidations2.default)({ validations: initialTests, endEarly: endEarly, value: value, path: path }).then(function (value) { + return (0, _runValidations2.default)({ + path: path, + value: value, + endEarly: endEarly, + validations: _this3.tests.map(function (fn) { + return fn(validationParams); + }) + }); }); }, isValid: function isValid(value, options, cb) { @@ -219,8 +258,8 @@ SchemaType.prototype = { }, default: function _default(def) { if (arguments.length === 0) { - var dflt = _.has(this, '_default') ? this._default : this._defaultDefault; - return typeof dflt === 'function' ? dflt.call(this) : cloneDeep(dflt); + var dflt = (0, _has2.default)(this, '_default') ? this._default : this._defaultDefault; + return typeof dflt === 'function' ? dflt.call(this) : (0, _clone2.default)(dflt); } var next = this.clone(); @@ -233,7 +272,7 @@ SchemaType.prototype = { return next; }, required: function required(msg) { - return this.test('required', msg || locale.required, notEmpty); + return this.test('required', msg || _locale.mixed.required, notEmpty); }, nullable: function nullable(value) { var next = this.clone(); @@ -264,7 +303,7 @@ SchemaType.prototype = { var opts = extractTestParams(name, message, _test, useCallback), next = this.clone(); - var validate = createValidation(opts); + var validate = (0, _createValidation2.default)(opts); var isExclusive = opts.exclusive || opts.name && next._exclusive[opts.name] === true; @@ -289,21 +328,21 @@ SchemaType.prototype = { when: function when(keys, options) { var next = this.clone(), deps = [].concat(keys).map(function (key) { - return new Ref(key); + return new _Reference2.default(key); }); deps.forEach(function (dep) { if (!dep.isContext) next._deps.push(dep.key); }); - next._conditions.push(new Condition(deps, options)); + next._conditions.push(new _Condition2.default(deps, options)); return next; }, typeError: function typeError(message) { var next = this.clone(); - next._typeError = createValidation({ + next._typeError = (0, _createValidation2.default)({ message: message, name: 'typeError', test: function test(value) { @@ -318,7 +357,7 @@ SchemaType.prototype = { return next; }, oneOf: function oneOf(enums) { - var message = arguments.length <= 1 || arguments[1] === undefined ? locale.oneOf : arguments[1]; + var message = arguments.length <= 1 || arguments[1] === undefined ? _locale.mixed.oneOf : arguments[1]; var next = this.clone(); @@ -329,7 +368,7 @@ SchemaType.prototype = { next._whitelist.add(val); }); - next._whitelistError = createValidation({ + next._whitelistError = (0, _createValidation2.default)({ message: message, name: 'oneOf', test: function test(value) { @@ -346,7 +385,7 @@ SchemaType.prototype = { return next; }, notOneOf: function notOneOf(enums) { - var message = arguments.length <= 1 || arguments[1] === undefined ? locale.notOneOf : arguments[1]; + var message = arguments.length <= 1 || arguments[1] === undefined ? _locale.mixed.notOneOf : arguments[1]; var next = this.clone(); @@ -355,7 +394,7 @@ SchemaType.prototype = { next._blacklist.add(val); }); - next._blacklistError = createValidation({ + next._blacklistError = (0, _createValidation2.default)({ message: message, name: 'notOneOf', test: function test(value) { @@ -379,7 +418,7 @@ SchemaType.prototype = { return next; }, _option: function _option(key, overrides) { - return _.has(overrides, key) ? overrides[key] : this._options[key]; + return (0, _has2.default)(overrides, key) ? overrides[key] : this._options[key]; }, describe: function describe() { var next = this.clone(); @@ -400,11 +439,11 @@ var aliases = { notOneOf: ['not', 'nope'] }; -for (var method in aliases) { - if (_.has(aliases, method)) aliases[method].forEach(function (alias) { +Object.keys(aliases).forEach(function (method) { + aliases[method].forEach(function (alias) { return SchemaType.prototype[alias] = SchemaType.prototype[method]; }); -} //eslint-disable-line no-loop-func +}); function nodeify(promise, cb) { if (typeof cb !== 'function') return promise; @@ -414,11 +453,4 @@ function nodeify(promise, cb) { }, function (err) { return cb(err); }); -} - -// [{ value, exclude }] - -// values.every(({ value, exclude }) => { -// var isEql = eql(value, otherval) -// return (exclude && !isEql) || isEql -// }) \ No newline at end of file +} \ No newline at end of file diff --git a/lib/number.js b/lib/number.js index a677db05d..71ad8f254 100644 --- a/lib/number.js +++ b/lib/number.js @@ -1,21 +1,29 @@ 'use strict'; -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; }; +var _inherits = require('./util/inherits'); -var SchemaObject = require('./mixed'); -var locale = require('./locale.js').number; -var isAbsent = require('./util/isAbsent'); +var _inherits2 = _interopRequireDefault(_inherits); -var _require = require('./util/_'); +var _mixed = require('./mixed'); -var isDate = _require.isDate; -var inherits = _require.inherits; +var _mixed2 = _interopRequireDefault(_mixed); +var _locale = require('./locale.js'); + +var _isAbsent = require('./util/isAbsent'); + +var _isAbsent2 = _interopRequireDefault(_isAbsent); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } module.exports = NumberSchema; +var isNaN = function isNaN(value) { + return value != +value; +}; + var isInteger = function isInteger(val) { - return isAbsent(val) || val === (val | 0); + return (0, _isAbsent2.default)(val) || val === (val | 0); }; function NumberSchema() { @@ -23,33 +31,34 @@ function NumberSchema() { if (!(this instanceof NumberSchema)) return new NumberSchema(); - SchemaObject.call(this, { type: 'number' }); + _mixed2.default.call(this, { type: 'number' }); this.withMutation(function () { _this.transform(function (value) { if (this.isType(value)) return value; - if (typeof value === 'boolean') return value ? 1 : 0; - return isDate(value) ? +value : parseFloat(value); + var parsed = parseFloat(value); + if (this.isType(parsed)) return parsed; + + return NaN; }); }); } -inherits(NumberSchema, SchemaObject, { - _typeCheck: function _typeCheck(v) { - if (typeof v === 'number' && !(v !== +v)) return true; - if ((typeof v === 'undefined' ? 'undefined' : _typeof(v)) === 'object' && v instanceof Number) return true; +(0, _inherits2.default)(NumberSchema, _mixed2.default, { + _typeCheck: function _typeCheck(value) { + if (value instanceof Number) value = value.valueOf(); - return false; + return typeof value === 'number' && !isNaN(value); }, min: function min(_min, msg) { return this.test({ name: 'min', exclusive: true, params: { min: _min }, - message: msg || locale.min, + message: msg || _locale.number.min, test: function test(value) { - return isAbsent(value) || value >= this.resolve(_min); + return (0, _isAbsent2.default)(value) || value >= this.resolve(_min); } }); }, @@ -58,33 +67,39 @@ inherits(NumberSchema, SchemaObject, { name: 'max', exclusive: true, params: { max: _max }, - message: msg || locale.max, + message: msg || _locale.number.max, test: function test(value) { - return isAbsent(value) || value <= this.resolve(_max); + return (0, _isAbsent2.default)(value) || value <= this.resolve(_max); } }); }, positive: function positive(msg) { - return this.min(0, msg || locale.positive); + return this.min(0, msg || _locale.number.positive); }, negative: function negative(msg) { - return this.max(0, msg || locale.negative); + return this.max(0, msg || _locale.number.negative); }, integer: function integer(msg) { - msg = msg || locale.integer; + msg = msg || _locale.number.integer; + return this.test('integer', msg, isInteger); + }, + truncate: function truncate() { return this.transform(function (value) { - return !isAbsent(value) ? value | 0 : value; - }).test('integer', msg, isInteger); + return !(0, _isAbsent2.default)(value) ? value | 0 : value; + }); }, round: function round(method) { - var avail = ['ceil', 'floor', 'round']; + var avail = ['ceil', 'floor', 'round', 'trunc']; method = method && method.toLowerCase() || 'round'; + // this exists for symemtry with the new Math.trunc + if (method === 'trunc') return this.truncate(); + if (avail.indexOf(method.toLowerCase()) === -1) throw new TypeError('Only valid options for round() are: ' + avail.join(', ')); return this.transform(function (value) { - return !isAbsent(value) ? Math[method](value) : value; + return !(0, _isAbsent2.default)(value) ? Math[method](value) : value; }); } }); \ No newline at end of file diff --git a/lib/object.js b/lib/object.js index c8029b090..042bd2c4d 100644 --- a/lib/object.js +++ b/lib/object.js @@ -2,39 +2,72 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; -var MixedSchema = require('./mixed'); -var Promise = require('universal-promise'); -var toposort = require('toposort'); -var locale = require('./locale.js').object; -var split = require('property-expr').split; -var Ref = require('./util/reference'); -var c = require('case'); -var sortByFields = require('./util/sortByFields'); - -var _require = require('./util/_'); - -var isObject = _require.isObject; -var transform = _require.transform; -var inherits = _require.inherits; -var collectErrors = _require.collectErrors; -var isSchema = _require.isSchema; -var has = _require.has; - - -c.type('altCamel', function (str) { - var result = c.camel(str), - idx = str.search(/[^_]/); +var _case = require('case'); - return idx === 0 ? result : str.substr(0, idx) + result; -}); +var _case2 = _interopRequireDefault(_case); + +var _has = require('lodash/has'); + +var _has2 = _interopRequireDefault(_has); + +var _omit = require('lodash/omit'); + +var _omit2 = _interopRequireDefault(_omit); + +var _mapKeys = require('lodash/mapKeys'); + +var _mapKeys2 = _interopRequireDefault(_mapKeys); + +var _transform = require('lodash/transform'); + +var _transform2 = _interopRequireDefault(_transform); + +var _mixed = require('./mixed'); + +var _mixed2 = _interopRequireDefault(_mixed); + +var _locale = require('./locale.js'); + +var _sortFields = require('./util/sortFields'); -var scopeError = function scopeError(value) { - return function (err) { - err.value = value; - throw err; - }; +var _sortFields2 = _interopRequireDefault(_sortFields); + +var _sortByKeyOrder = require('./util/sortByKeyOrder'); + +var _sortByKeyOrder2 = _interopRequireDefault(_sortByKeyOrder); + +var _inherits = require('./util/inherits'); + +var _inherits2 = _interopRequireDefault(_inherits); + +var _runValidations = require('./util/runValidations'); + +var _runValidations2 = _interopRequireDefault(_runValidations); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var isObject = function isObject(obj) { + return Object.prototype.toString.call(obj) === '[object Object]'; }; +function unknown(ctx, value) { + var known = Object.keys(ctx.fields); + return Object.keys(value).filter(function (key) { + return known.indexOf(key) === -1; + }); +} + +/** + * maintain "private" fields + * `"__FOO_BAR"` becomes `"__fooBar"` not `"fooBar"` + */ +function camelize(str) { + var result = _case2.default.camel(str), + idx = str.search(/[^_]/); + + return idx === 0 ? result : str.substr(0, idx) + result; +} + module.exports = ObjectSchema; function ObjectSchema(spec) { @@ -42,10 +75,10 @@ function ObjectSchema(spec) { if (!(this instanceof ObjectSchema)) return new ObjectSchema(spec); - MixedSchema.call(this, { type: 'object', default: function _default() { + _mixed2.default.call(this, { type: 'object', default: function _default() { var _this = this; - var dft = transform(this._nodes, function (obj, key) { + var dft = (0, _transform2.default)(this._nodes, function (obj, key) { obj[key] = _this.fields[key].default ? _this.fields[key].default() : undefined; }, {}); @@ -70,11 +103,13 @@ function ObjectSchema(spec) { return null; }); - if (spec) _this2.shape(spec); + if (spec) { + _this2.shape(spec); + } }); } -inherits(ObjectSchema, MixedSchema, { +(0, _inherits2.default)(ObjectSchema, _mixed2.default, { _typeCheck: function _typeCheck(value) { return isObject(value) || typeof value === 'function'; }, @@ -83,7 +118,7 @@ inherits(ObjectSchema, MixedSchema, { var opts = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; - var value = MixedSchema.prototype._cast.call(this, _value, opts); + var value = _mixed2.default.prototype._cast.call(this, _value, opts); //should ignore nulls here if (value === undefined) return this.default(); @@ -97,15 +132,17 @@ inherits(ObjectSchema, MixedSchema, { }), props = this._nodes.concat(extra); - var innerOptions = _extends({}, opts, { parent: {}, __validating: false }); + var innerOptions = _extends({}, opts, { + parent: {}, // is filled during the transform below + __validating: false + }); - value = transform(props, function (obj, prop) { + value = (0, _transform2.default)(props, function (obj, prop) { var field = fields[prop]; - var exists = has(value, prop); + var exists = (0, _has2.default)(value, prop); if (field) { var fieldValue = void 0; - var strict = field._options && field._options.strict; if (field._strip === true) return; @@ -132,10 +169,7 @@ inherits(ObjectSchema, MixedSchema, { opts = _extends({}, opts, { __validating: true }); - return MixedSchema.prototype._validate.call(this, _value, opts).catch(endEarly ? null : function (err) { - errors.push(err); - return err.value; - }).then(function (value) { + return _mixed2.default.prototype._validate.call(this, _value, opts).catch((0, _runValidations.propagateErrors)(endEarly, errors)).then(function (value) { if (!recursive || !isObject(value)) { // only iterate though actual objects if (errors.length) throw errors[0]; @@ -145,7 +179,7 @@ inherits(ObjectSchema, MixedSchema, { var validations = _this4._nodes.map(function (key) { var path = (opts.path ? opts.path + '.' : '') + key, field = _this4.fields[key], - innerOptions = _extends({}, opts, { key: key, path: path, parent: value }); + innerOptions = _extends({}, opts, { path: path, parent: value }); if (field) { // inner fields are always strict: @@ -159,20 +193,20 @@ inherits(ObjectSchema, MixedSchema, { return true; }); - validations = endEarly ? Promise.all(validations).catch(scopeError(value)) : collectErrors({ validations: validations, value: value, errors: errors, + return (0, _runValidations2.default)({ + validations: validations, + value: value, + errors: errors, + endEarly: endEarly, path: opts.path, - sort: sortByFields(_this4) - }); - - return validations.then(function () { - return value; + sort: (0, _sortByKeyOrder2.default)(_this4.fields) }); }); }, concat: function concat(schema) { - var next = MixedSchema.prototype.concat.call(this, schema); + var next = _mixed2.default.prototype.concat.call(this, schema); - next._nodes = sortFields(next.fields, next._excludedEdges); + next._nodes = (0, _sortFields2.default)(next.fields, next._excludedEdges); return next; }, @@ -186,11 +220,17 @@ inherits(ObjectSchema, MixedSchema, { next.fields = fields; - if (excludes.length) next._excludedEdges = next._excludedEdges.concat(excludes.map(function (v) { - return v[0] + '-' + v[1]; - })); // 'node-othernode' + if (excludes.length) { + var keys = excludes.map(function (_ref) { + var first = _ref[0]; + var second = _ref[1]; + return first + '-' + second; + }); - next._nodes = sortFields(fields, next._excludedEdges); + next._excludedEdges = next._excludedEdges.concat(keys); + } + + next._nodes = (0, _sortFields2.default)(fields, next._excludedEdges); return next; }, @@ -200,10 +240,8 @@ inherits(ObjectSchema, MixedSchema, { if (obj == null) return obj; - if (has(obj, _from)) { - newObj = transform(obj, function (o, val, key) { - return key !== _from && (o[key] = val); - }, {}); + if ((0, _has2.default)(obj, _from)) { + newObj = (0, _omit2.default)(obj, _from); newObj[to] = obj[_from]; if (alias) newObj[_from] = obj[_from]; @@ -214,7 +252,7 @@ inherits(ObjectSchema, MixedSchema, { }, noUnknown: function noUnknown() { var noAllow = arguments.length <= 0 || arguments[0] === undefined ? true : arguments[0]; - var message = arguments.length <= 1 || arguments[1] === undefined ? locale.noUnknown : arguments[1]; + var message = arguments.length <= 1 || arguments[1] === undefined ? _locale.object.noUnknown : arguments[1]; if (typeof noAllow === 'string') message = noAllow, noAllow = true; @@ -233,61 +271,19 @@ inherits(ObjectSchema, MixedSchema, { }, camelcase: function camelcase() { return this.transform(function (obj) { - return obj == null ? obj : transform(obj, function (newobj, val, key) { - return newobj[c.altCamel(key)] = val; + return obj && (0, _mapKeys2.default)(obj, function (_, key) { + return camelize(key); }); }); }, constantcase: function constantcase() { return this.transform(function (obj) { - return obj == null ? obj : transform(obj, function (newobj, val, key) { - return newobj[c.constant(key)] = val; + return obj && (0, _mapKeys2.default)(obj, function (_, key) { + return _case2.default.constant(key); }); }); } }); -function unknown(ctx, value) { - var known = Object.keys(ctx.fields); - return Object.keys(value).filter(function (key) { - return known.indexOf(key) === -1; - }); -} - -// ugly optimization avoiding a clone. clears default for recursive -// cast and resets it below; -// function tempClearDefault(schema, fn) { -// let hasDflt = has(schema, '_default') -// , dflt = schema._default; -// -// fn(schema) -// -// if (hasDflt) schema.default(dflt) -// else delete schema._default -// } - -function sortFields(fields) { - var excludes = arguments.length <= 1 || arguments[1] === undefined ? [] : arguments[1]; - - var edges = [], - nodes = []; - - for (var key in fields) { - if (has(fields, key)) { - var value = fields[key]; - - if (! ~nodes.indexOf(key)) nodes.push(key); - - var addNode = function addNode(depPath) { - //eslint-disable-line no-loop-func - var node = split(depPath)[0]; - - if (! ~nodes.indexOf(node)) nodes.push(node); - - if (! ~excludes.indexOf(key + '-' + node)) edges.push([key, node]); - }; - - if (Ref.isRef(value) && !value.isContext) addNode(value.path);else if (isSchema(value) && value._deps) value._deps.forEach(addNode); - } - }return toposort.array(nodes, edges).reverse(); -} \ No newline at end of file +ObjectSchema.prototype.camelCase = ObjectSchema.prototype.camelcase; +ObjectSchema.prototype.constantCase = ObjectSchema.prototype.constantcase; \ No newline at end of file diff --git a/lib/string.js b/lib/string.js index 04b398de3..deb0e213d 100644 --- a/lib/string.js +++ b/lib/string.js @@ -1,24 +1,29 @@ 'use strict'; -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; }; +var _inherits = require('./util/inherits'); -var MixedSchema = require('./mixed'); +var _inherits2 = _interopRequireDefault(_inherits); -var _require = require('./locale.js'); +var _mixed = require('./mixed'); -var mixed = _require.mixed; -var locale = _require.string; -var isAbsent = require('./util/isAbsent'); -var inherits = require('./util/_').inherits; +var _mixed2 = _interopRequireDefault(_mixed); + +var _locale = require('./locale'); + +var _isAbsent = require('./util/isAbsent'); + +var _isAbsent2 = _interopRequireDefault(_isAbsent); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var rEmail = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i; var rUrl = /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i; var hasLength = function hasLength(value) { - return !isAbsent(value) && value.length > 0; + return (0, _isAbsent2.default)(value) || value.length > 0; }; var isTrimmed = function isTrimmed(value) { - return isAbsent(value) || value === value.trim(); + return (0, _isAbsent2.default)(value) || value === value.trim(); }; module.exports = StringSchema; @@ -28,33 +33,35 @@ function StringSchema() { if (!(this instanceof StringSchema)) return new StringSchema(); - MixedSchema.call(this, { type: 'string' }); + _mixed2.default.call(this, { type: 'string' }); this.withMutation(function () { _this.transform(function (value) { if (this.isType(value)) return value; - return value == null ? '' : value.toString ? value.toString() : '' + value; + return value != null && value.toString ? value.toString() : value; }); }); } -inherits(StringSchema, MixedSchema, { +(0, _inherits2.default)(StringSchema, _mixed2.default, { _typeCheck: function _typeCheck(value) { - return typeof value === 'string' || (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object' && value instanceof String; + if (value instanceof String) value = value.valueOf(); + + return typeof value === 'string'; }, required: function required(msg) { - var next = MixedSchema.prototype.required.call(this, msg || mixed.required); + var next = _mixed2.default.prototype.required.call(this, msg || _locale.mixed.required); - return next.test('required', msg || mixed.required, hasLength); + return next.test('required', msg || _locale.mixed.required, hasLength); }, min: function min(_min, msg) { return this.test({ name: 'min', exclusive: true, - message: msg || locale.min, + message: msg || _locale.string.min, params: { min: _min }, test: function test(value) { - return isAbsent(value) || value.length >= this.resolve(_min); + return (0, _isAbsent2.default)(value) || value.length >= this.resolve(_min); } }); }, @@ -62,33 +69,38 @@ inherits(StringSchema, MixedSchema, { return this.test({ name: 'max', exclusive: true, - message: msg || locale.max, + message: msg || _locale.string.max, params: { max: _max }, test: function test(value) { - return isAbsent(value) || value.length <= this.resolve(_max); + return (0, _isAbsent2.default)(value) || value.length <= this.resolve(_max); } }); }, matches: function matches(regex, msg) { return this.test({ - message: msg || locale.matches, + message: msg || _locale.string.matches, params: { regex: regex }, test: function test(value) { - return isAbsent(value) || regex.test(value); + return (0, _isAbsent2.default)(value) || regex.test(value); } }); }, email: function email(msg) { - return this.matches(rEmail, msg || locale.email); + return this.matches(rEmail, msg || _locale.string.email); }, url: function url(msg) { - return this.matches(rUrl, msg || locale.url); + return this.matches(rUrl, msg || _locale.string.url); }, //-- transforms -- + ensure: function ensure() { + return this.default('').transform(function (val) { + return val === null ? '' : val; + }); + }, trim: function trim(msg) { - msg = msg || locale.trim; + msg = msg || _locale.string.trim; return this.transform(function (val) { return val != null ? val.trim() : val; @@ -96,25 +108,25 @@ inherits(StringSchema, MixedSchema, { }, lowercase: function lowercase(msg) { return this.transform(function (value) { - return !isAbsent(value) ? value.toLowerCase() : value; + return !(0, _isAbsent2.default)(value) ? value.toLowerCase() : value; }).test({ name: 'string_case', exclusive: true, - message: msg || locale.lowercase, + message: msg || _locale.string.lowercase, test: function test(value) { - return isAbsent(value) || value === value.toLowerCase(); + return (0, _isAbsent2.default)(value) || value === value.toLowerCase(); } }); }, uppercase: function uppercase(msg) { return this.transform(function (value) { - return !isAbsent(value) ? value.toUpperCase() : value; + return !(0, _isAbsent2.default)(value) ? value.toUpperCase() : value; }).test({ name: 'string_case', exclusive: true, - message: msg || locale.uppercase, + message: msg || _locale.string.uppercase, test: function test(value) { - return isAbsent(value) || value === value.toUpperCase(); + return (0, _isAbsent2.default)(value) || value === value.toUpperCase(); } }); } diff --git a/lib/util/clone.js b/lib/util/clone.js index 07a14cf5f..b97de72b3 100644 --- a/lib/util/clone.js +++ b/lib/util/clone.js @@ -1,24 +1,25 @@ 'use strict'; -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; }; +exports.__esModule = true; -// Copyright (c) 2011-2014, Walmart and other contributors. +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; }; // Copyright (c) 2011-2014, Walmart and other contributors. // Copyright (c) 2011, Yahoo Inc. // All rights reserved. https://github.com/hapijs/hoek/blob/master/LICENSE -var isSchema = function isSchema(schema) { - return schema && !!schema.__isYupSchema__; -}; +exports.default = clone; -module.exports = function clone(obj, seen) { +var _isSchema = require('./isSchema'); + +var _isSchema2 = _interopRequireDefault(_isSchema); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function clone(obj, seen) { var isFirst = !seen, - isImmutable = isSchema(obj) && !isFirst; + isImmutable = (0, _isSchema2.default)(obj) && !isFirst; if ((typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) !== 'object' || obj === null || isImmutable) return obj; - // if (global.REPORT_CLONE && isFirst) - // throw new Error() //console.log('clone') - seen = seen || { orig: [], copy: [] }; var lookup = seen.orig.indexOf(obj); @@ -68,4 +69,5 @@ module.exports = function clone(obj, seen) { } return newObj; -}; \ No newline at end of file +} +module.exports = exports['default']; \ No newline at end of file diff --git a/lib/util/createValidation.js b/lib/util/createValidation.js index e28061ccb..992f96152 100644 --- a/lib/util/createValidation.js +++ b/lib/util/createValidation.js @@ -2,24 +2,30 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; -function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } +var _universalPromise = require('universal-promise'); + +var _universalPromise2 = _interopRequireDefault(_universalPromise); + +var _mapValues = require('lodash/mapValues'); + +var _mapValues2 = _interopRequireDefault(_mapValues); -var Promise = require('universal-promise'); -var ValidationError = require('./validation-error'); -var Ref = require('./reference'); +var _ValidationError = require('../ValidationError'); -var _require = require('./_'); +var _ValidationError2 = _interopRequireDefault(_ValidationError); -var transform = _require.transform; +var _Reference = require('../Reference'); +var _Reference2 = _interopRequireDefault(_Reference); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } -var formatError = ValidationError.formatError; +var formatError = _ValidationError2.default.formatError; function resolveParams(oldParams, newParams, resolve) { - var start = _extends({}, oldParams, newParams); - return transform(start, function (obj, value, key) { - obj[key] = resolve(value); - }); + return (0, _mapValues2.default)(_extends({}, oldParams, newParams), resolve); } function createErrorFactory(_ref) { @@ -42,7 +48,7 @@ function createErrorFactory(_ref) { params = _extends({ path: path, value: value, label: label }, resolveParams(opts.params, params, resolve)); - return _extends(new ValidationError(typeof message === 'string' ? formatError(message, params) : message, value, path, type), { params: params }); + return _extends(new _ValidationError2.default(typeof message === 'string' ? formatError(message, params) : message, value, path, type), { params: params }); }; } @@ -64,7 +70,7 @@ module.exports = function createValidation(options) { var parent = options.parent; var resolve = function resolve(value) { - return Ref.isRef(value) ? value.getValue(parent, options.context) : value; + return _Reference2.default.isRef(value) ? value.getValue(parent, options.context) : value; }; var createError = createErrorFactory({ @@ -74,12 +80,12 @@ module.exports = function createValidation(options) { var ctx = _extends({ path: path, parent: parent, type: name, createError: createError, resolve: resolve, options: options }, rest); - return new Promise(function (resolve, reject) { + return new _universalPromise2.default(function (resolve, reject) { !useCallback ? resolve(test.call(ctx, value)) : test.call(ctx, value, function (err, valid) { return err ? reject(err) : resolve(valid); }); }).then(function (validOrError) { - if (ValidationError.isError(validOrError)) throw validOrError;else if (!validOrError) throw createError(); + if (_ValidationError2.default.isError(validOrError)) throw validOrError;else if (!validOrError) throw createError(); }); } diff --git a/lib/util/inherits.js b/lib/util/inherits.js new file mode 100644 index 000000000..6bd7a95f9 --- /dev/null +++ b/lib/util/inherits.js @@ -0,0 +1,20 @@ +"use strict"; + +exports.__esModule = true; + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +exports.default = inherits; +function inherits(ctor, superCtor, spec) { + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); + + _extends(ctor.prototype, spec); +} +module.exports = exports['default']; \ No newline at end of file diff --git a/lib/util/isSchema.js b/lib/util/isSchema.js new file mode 100644 index 000000000..fdbd303bd --- /dev/null +++ b/lib/util/isSchema.js @@ -0,0 +1,9 @@ +"use strict"; + +exports.__esModule = true; + +exports.default = function (obj) { + return obj && obj.__isYupSchema__; +}; + +module.exports = exports['default']; \ No newline at end of file diff --git a/lib/util/isodate.js b/lib/util/isodate.js index 8bcf7768c..347467b2d 100644 --- a/lib/util/isodate.js +++ b/lib/util/isodate.js @@ -24,7 +24,7 @@ module.exports = function parseIsoDate(date) { struct[3] = +struct[3] || 1; // allow arbitrary sub-second precision beyond milliseconds - struct[7] = struct[7] ? +(struct[7] + "00").substr(0, 3) : 0; + struct[7] = struct[7] ? +(struct[7] + '00').substr(0, 3) : 0; // timestamps without timezone identifiers should be considered local time if ((struct[8] === undefined || struct[8] === '') && (struct[9] === undefined || struct[9] === '')) timestamp = +new Date(struct[1], struct[2], struct[3], struct[4], struct[5], struct[6], struct[7]);else { diff --git a/lib/util/merge.js b/lib/util/merge.js new file mode 100644 index 000000000..3959db7c1 --- /dev/null +++ b/lib/util/merge.js @@ -0,0 +1,38 @@ +'use strict'; + +exports.__esModule = true; +exports.default = merge; + +var _has = require('lodash/has'); + +var _has2 = _interopRequireDefault(_has); + +var _isSchema = require('./isSchema'); + +var _isSchema2 = _interopRequireDefault(_isSchema); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var isObject = function isObject(obj) { + return Object.prototype.toString.call(obj) === '[object Object]'; +}; + +function merge(target, source) { + for (var key in source) { + if ((0, _has2.default)(source, key)) { + var targetVal = target[key], + sourceVal = source[key]; + + if (sourceVal === undefined) continue; + + if ((0, _isSchema2.default)(sourceVal)) { + target[key] = (0, _isSchema2.default)(targetVal) ? targetVal.concat(sourceVal) : sourceVal; + } else if (isObject(sourceVal)) { + target[key] = isObject(targetVal) ? merge(targetVal, sourceVal) : sourceVal; + } else if (Array.isArray(sourceVal)) { + target[key] = Array.isArray(targetVal) ? targetVal.concat(sourceVal) : sourceVal; + } else target[key] = source[key]; + } + }return target; +} +module.exports = exports['default']; \ No newline at end of file diff --git a/lib/util/reach.js b/lib/util/reach.js index b15405e61..2a9351fd2 100644 --- a/lib/util/reach.js +++ b/lib/util/reach.js @@ -1,13 +1,12 @@ 'use strict'; -var _require = require('property-expr'); +var _propertyExpr = require('property-expr'); -var forEach = _require.forEach; +var _has = require('lodash/has'); -var _require2 = require('./_'); - -var has = _require2.has; +var _has2 = _interopRequireDefault(_has); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var trim = function trim(part) { return part.substr(0, part.length - 1).substr(1); @@ -20,10 +19,10 @@ module.exports = function (obj, path, value, context) { // if only one "value" arg then use it for both context = context || value; - forEach(path, function (_part, isBracket, isArray) { + (0, _propertyExpr.forEach)(path, function (_part, isBracket, isArray) { var part = isBracket ? trim(_part) : _part; - if (isArray || has(obj, '_subType')) { + if (isArray || (0, _has2.default)(obj, '_subType')) { // we skipped an array var idx = isArray ? parseInt(part, 10) : 0; obj = obj.resolve({ context: context, parent: parent, value: value })._subType; @@ -40,7 +39,7 @@ module.exports = function (obj, path, value, context) { if (!isArray) { obj = obj.resolve({ context: context, parent: parent, value: value }); - if (!has(obj, 'fields') || !has(obj.fields, part)) throw new Error('The schema does not contain the path: ' + path + '. ' + ('(failed at: ' + lastPart + ' which is a type: "' + obj._type + '") ')); + if (!(0, _has2.default)(obj, 'fields') || !(0, _has2.default)(obj.fields, part)) throw new Error('The schema does not contain the path: ' + path + '. ' + ('(failed at: ' + lastPart + ' which is a type: "' + obj._type + '") ')); obj = obj.fields[part]; diff --git a/lib/util/runValidations.js b/lib/util/runValidations.js new file mode 100644 index 000000000..630b2ad50 --- /dev/null +++ b/lib/util/runValidations.js @@ -0,0 +1,88 @@ +'use strict'; + +exports.__esModule = true; +exports.propagateErrors = propagateErrors; +exports.settled = settled; +exports.collectErrors = collectErrors; +exports.default = runValidations; + +var _ValidationError = require('../ValidationError'); + +var _ValidationError2 = _interopRequireDefault(_ValidationError); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } + +var unwrapError = function unwrapError() { + var errors = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0]; + return errors.inner && errors.inner.length ? errors.inner : [].concat(errors); +}; + +function scopeToValue(promises, value) { + return Promise.all(promises).catch(function (err) { + if (err.name === 'ValidationError') err.value = value; + throw err; + }).then(function () { + return value; + }); +} + +/** + * If not failing on the first error, catch the errors + * and collect them in an array + */ +function propagateErrors(endEarly, errors) { + return endEarly ? null : function (err) { + errors.push(err); + return err.value; + }; +} + +function settled(promises) { + var settle = function settle(promise) { + return promise.then(function (value) { + return { fulfilled: true, value: value }; + }, function (value) { + return { fulfilled: false, value: value }; + }); + }; + + return Promise.all(promises.map(settle)); +} + +function collectErrors(_ref) { + var validations = _ref.validations; + var value = _ref.value; + var path = _ref.path; + var _ref$errors = _ref.errors; + var errors = _ref$errors === undefined ? unwrapError(errors) : _ref$errors; + var sort = _ref.sort; + + return settled(validations).then(function (results) { + var nestedErrors = results.filter(function (r) { + return !r.fulfilled; + }).reduce(function (arr, r) { + return arr.concat(r.value); + }, []); + + if (sort) nestedErrors.sort(sort); + + //show parent errors after the nested ones: name.first, name + errors = nestedErrors.concat(errors); + + if (errors.length) throw new _ValidationError2.default(errors, value, path); + + return value; + }); +} + +function runValidations(_ref2) { + var endEarly = _ref2.endEarly; + + var options = _objectWithoutProperties(_ref2, ['endEarly']); + + if (endEarly) return scopeToValue(options.validations, options.value); + + return collectErrors(options); +} \ No newline at end of file diff --git a/lib/util/scopeToValue.js b/lib/util/scopeToValue.js new file mode 100644 index 000000000..045d476d9 --- /dev/null +++ b/lib/util/scopeToValue.js @@ -0,0 +1,24 @@ +'use strict'; + +exports.__esModule = true; +exports.default = scopeToValue; + +var _universalPromise = require('universal-promise'); + +var _universalPromise2 = _interopRequireDefault(_universalPromise); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * Sets the error on a Validation error to a new + * value and re throws. + */ +function scopeToValue(promises, value) { + return _universalPromise2.default.all(promises).catch(function (err) { + if (err.name === 'ValidationError') err.value = value; + throw err; + }).then(function () { + return value; + }); +} +module.exports = exports['default']; \ No newline at end of file diff --git a/lib/util/set.js b/lib/util/set.js index 599274c2e..f535760b0 100644 --- a/lib/util/set.js +++ b/lib/util/set.js @@ -2,12 +2,13 @@ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +var _has2 = require('lodash/has'); -var _require = require('./_'); +var _has3 = _interopRequireDefault(_has2); -var _has = _require.has; +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } module.exports = function () { function BadSet() { @@ -34,7 +35,7 @@ module.exports = function () { }; BadSet.prototype.has = function has(item) { - return _has(this._map, stringify(item)); + return (0, _has3.default)(this._map, stringify(item)); }; _createClass(BadSet, [{ diff --git a/lib/util/sortByKeyOrder.js b/lib/util/sortByKeyOrder.js new file mode 100644 index 000000000..01ee8d262 --- /dev/null +++ b/lib/util/sortByKeyOrder.js @@ -0,0 +1,20 @@ +"use strict"; + +function findIndex(arr, err) { + var idx = Infinity; + arr.some(function (key, ii) { + if (err.path.indexOf(key) !== -1) { + idx = ii; + return true; + } + }); + + return idx; +} + +module.exports = function sortByKeyOrder(fields) { + var keys = Object.keys(fields); + return function (a, b) { + return findIndex(keys, a) - findIndex(keys, b); + }; +}; \ No newline at end of file diff --git a/lib/util/sortFields.js b/lib/util/sortFields.js new file mode 100644 index 000000000..de022c800 --- /dev/null +++ b/lib/util/sortFields.js @@ -0,0 +1,52 @@ +'use strict'; + +exports.__esModule = true; +exports.default = sortFields; + +var _toposort = require('toposort'); + +var _toposort2 = _interopRequireDefault(_toposort); + +var _has = require('lodash/has'); + +var _has2 = _interopRequireDefault(_has); + +var _propertyExpr = require('property-expr'); + +var _Reference = require('../Reference'); + +var _Reference2 = _interopRequireDefault(_Reference); + +var _isSchema = require('./isSchema'); + +var _isSchema2 = _interopRequireDefault(_isSchema); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function sortFields(fields) { + var excludes = arguments.length <= 1 || arguments[1] === undefined ? [] : arguments[1]; + + var edges = [], + nodes = []; + + function addNode(depPath, key) { + var node = (0, _propertyExpr.split)(depPath)[0]; + + if (! ~nodes.indexOf(node)) nodes.push(node); + + if (! ~excludes.indexOf(key + '-' + node)) edges.push([key, node]); + } + + for (var key in fields) { + if ((0, _has2.default)(fields, key)) { + var value = fields[key]; + + if (! ~nodes.indexOf(key)) nodes.push(key); + + if (_Reference2.default.isRef(value) && !value.isContext) addNode(value.path, key);else if ((0, _isSchema2.default)(value) && value._deps) value._deps.forEach(function (path) { + return addNode(path, key); + }); + } + }return _toposort2.default.array(nodes, edges).reverse(); +} +module.exports = exports['default']; \ No newline at end of file