322 lines
9.2 KiB
JavaScript
322 lines
9.2 KiB
JavaScript
"use strict";
|
|
|
|
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
|
|
|
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
|
|
exports.__esModule = true;
|
|
exports.default = ObjectSchema;
|
|
|
|
var _taggedTemplateLiteralLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/taggedTemplateLiteralLoose"));
|
|
|
|
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
|
|
|
var _has = _interopRequireDefault(require("lodash/has"));
|
|
|
|
var _snakeCase2 = _interopRequireDefault(require("lodash/snakeCase"));
|
|
|
|
var _camelCase2 = _interopRequireDefault(require("lodash/camelCase"));
|
|
|
|
var _mapKeys = _interopRequireDefault(require("lodash/mapKeys"));
|
|
|
|
var _mapValues = _interopRequireDefault(require("lodash/mapValues"));
|
|
|
|
var _propertyExpr = require("property-expr");
|
|
|
|
var _mixed = _interopRequireDefault(require("./mixed"));
|
|
|
|
var _locale = require("./locale.js");
|
|
|
|
var _sortFields = _interopRequireDefault(require("./util/sortFields"));
|
|
|
|
var _sortByKeyOrder = _interopRequireDefault(require("./util/sortByKeyOrder"));
|
|
|
|
var _inherits = _interopRequireDefault(require("./util/inherits"));
|
|
|
|
var _makePath = _interopRequireDefault(require("./util/makePath"));
|
|
|
|
var _runValidations = _interopRequireWildcard(require("./util/runValidations"));
|
|
|
|
function _templateObject2() {
|
|
var data = (0, _taggedTemplateLiteralLoose2.default)(["", ".", ""]);
|
|
|
|
_templateObject2 = function _templateObject2() {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _templateObject() {
|
|
var data = (0, _taggedTemplateLiteralLoose2.default)(["", ".", ""]);
|
|
|
|
_templateObject = function _templateObject() {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
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;
|
|
});
|
|
}
|
|
|
|
function ObjectSchema(spec) {
|
|
var _this2 = this;
|
|
|
|
if (!(this instanceof ObjectSchema)) return new ObjectSchema(spec);
|
|
|
|
_mixed.default.call(this, {
|
|
type: 'object',
|
|
default: function _default() {
|
|
var _this = this;
|
|
|
|
if (!this._nodes.length) return undefined;
|
|
var dft = {};
|
|
|
|
this._nodes.forEach(function (key) {
|
|
dft[key] = _this.fields[key].default ? _this.fields[key].default() : undefined;
|
|
});
|
|
|
|
return dft;
|
|
}
|
|
});
|
|
|
|
this.fields = Object.create(null);
|
|
this._nodes = [];
|
|
this._excludedEdges = [];
|
|
this.withMutation(function () {
|
|
_this2.transform(function coerce(value) {
|
|
if (typeof value === 'string') {
|
|
try {
|
|
value = JSON.parse(value);
|
|
} catch (err) {
|
|
value = null;
|
|
}
|
|
}
|
|
|
|
if (this.isType(value)) return value;
|
|
return null;
|
|
});
|
|
|
|
if (spec) {
|
|
_this2.shape(spec);
|
|
}
|
|
});
|
|
}
|
|
|
|
(0, _inherits.default)(ObjectSchema, _mixed.default, {
|
|
_typeCheck: function _typeCheck(value) {
|
|
return isObject(value) || typeof value === 'function';
|
|
},
|
|
_cast: function _cast(_value, options) {
|
|
var _this3 = this;
|
|
|
|
if (options === void 0) {
|
|
options = {};
|
|
}
|
|
|
|
var value = _mixed.default.prototype._cast.call(this, _value, options); //should ignore nulls here
|
|
|
|
|
|
if (value === undefined) return this.default();
|
|
if (!this._typeCheck(value)) return value;
|
|
var fields = this.fields;
|
|
var strip = this._option('stripUnknown', options) === true;
|
|
|
|
var props = this._nodes.concat(Object.keys(value).filter(function (v) {
|
|
return _this3._nodes.indexOf(v) === -1;
|
|
}));
|
|
|
|
var intermediateValue = {}; // is filled during the transform below
|
|
|
|
var innerOptions = (0, _extends2.default)({}, options, {
|
|
parent: intermediateValue,
|
|
__validating: false
|
|
});
|
|
var isChanged = false;
|
|
props.forEach(function (prop) {
|
|
var field = fields[prop];
|
|
var exists = (0, _has.default)(value, prop);
|
|
|
|
if (field) {
|
|
var fieldValue;
|
|
var strict = field._options && field._options.strict; // safe to mutate since this is fired in sequence
|
|
|
|
innerOptions.path = (0, _makePath.default)(_templateObject(), options.path, prop);
|
|
innerOptions.value = value[prop];
|
|
field = field.resolve(innerOptions);
|
|
|
|
if (field._strip === true) {
|
|
isChanged = isChanged || prop in value;
|
|
return;
|
|
}
|
|
|
|
fieldValue = !options.__validating || !strict ? field.cast(value[prop], innerOptions) : value[prop];
|
|
if (fieldValue !== undefined) intermediateValue[prop] = fieldValue;
|
|
} else if (exists && !strip) intermediateValue[prop] = value[prop];
|
|
|
|
if (intermediateValue[prop] !== value[prop]) isChanged = true;
|
|
});
|
|
return isChanged ? intermediateValue : value;
|
|
},
|
|
_validate: function _validate(_value, opts) {
|
|
var _this4 = this;
|
|
|
|
if (opts === void 0) {
|
|
opts = {};
|
|
}
|
|
|
|
var endEarly, recursive;
|
|
var sync = opts.sync;
|
|
var errors = [];
|
|
var originalValue = opts.originalValue != null ? opts.originalValue : _value;
|
|
endEarly = this._option('abortEarly', opts);
|
|
recursive = this._option('recursive', opts);
|
|
opts = (0, _extends2.default)({}, opts, {
|
|
__validating: true,
|
|
originalValue: originalValue
|
|
});
|
|
return _mixed.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];
|
|
return value;
|
|
}
|
|
|
|
originalValue = originalValue || value;
|
|
|
|
var validations = _this4._nodes.map(function (key) {
|
|
var path = (0, _makePath.default)(_templateObject2(), opts.path, key);
|
|
var field = _this4.fields[key];
|
|
var innerOptions = (0, _extends2.default)({}, opts, {
|
|
path: path,
|
|
parent: value,
|
|
originalValue: originalValue[key]
|
|
});
|
|
|
|
if (field && field.validate) {
|
|
// inner fields are always strict:
|
|
// 1. this isn't strict so the casting will also have cast inner values
|
|
// 2. this is strict in which case the nested values weren't cast either
|
|
innerOptions.strict = true;
|
|
return field.validate(value[key], innerOptions);
|
|
}
|
|
|
|
return Promise.resolve(true);
|
|
});
|
|
|
|
return (0, _runValidations.default)({
|
|
sync: sync,
|
|
validations: validations,
|
|
value: value,
|
|
errors: errors,
|
|
endEarly: endEarly,
|
|
path: opts.path,
|
|
sort: (0, _sortByKeyOrder.default)(_this4.fields)
|
|
});
|
|
});
|
|
},
|
|
concat: function concat(schema) {
|
|
var next = _mixed.default.prototype.concat.call(this, schema);
|
|
|
|
next._nodes = (0, _sortFields.default)(next.fields, next._excludedEdges);
|
|
return next;
|
|
},
|
|
shape: function shape(schema, excludes) {
|
|
if (excludes === void 0) {
|
|
excludes = [];
|
|
}
|
|
|
|
var next = this.clone();
|
|
var fields = (0, _extends2.default)(next.fields, schema);
|
|
next.fields = fields;
|
|
|
|
if (excludes.length) {
|
|
if (!Array.isArray(excludes[0])) excludes = [excludes];
|
|
var keys = excludes.map(function (_ref) {
|
|
var first = _ref[0],
|
|
second = _ref[1];
|
|
return first + "-" + second;
|
|
});
|
|
next._excludedEdges = next._excludedEdges.concat(keys);
|
|
}
|
|
|
|
next._nodes = (0, _sortFields.default)(fields, next._excludedEdges);
|
|
return next;
|
|
},
|
|
from: function from(_from, to, alias) {
|
|
var fromGetter = (0, _propertyExpr.getter)(_from, true);
|
|
return this.transform(function (obj) {
|
|
if (obj == null) return obj;
|
|
var newObj = obj;
|
|
|
|
if ((0, _has.default)(obj, _from)) {
|
|
newObj = (0, _extends2.default)({}, obj);
|
|
if (!alias) delete newObj[_from];
|
|
newObj[to] = fromGetter(obj);
|
|
}
|
|
|
|
return newObj;
|
|
});
|
|
},
|
|
noUnknown: function noUnknown(noAllow, message) {
|
|
if (noAllow === void 0) {
|
|
noAllow = true;
|
|
}
|
|
|
|
if (message === void 0) {
|
|
message = _locale.object.noUnknown;
|
|
}
|
|
|
|
if (typeof noAllow === 'string') {
|
|
message = noAllow;
|
|
noAllow = true;
|
|
}
|
|
|
|
var next = this.test({
|
|
name: 'noUnknown',
|
|
exclusive: true,
|
|
message: message,
|
|
test: function test(value) {
|
|
return value == null || !noAllow || unknown(this.schema, value).length === 0;
|
|
}
|
|
});
|
|
if (noAllow) next._options.stripUnknown = true;
|
|
return next;
|
|
},
|
|
transformKeys: function transformKeys(fn) {
|
|
return this.transform(function (obj) {
|
|
return obj && (0, _mapKeys.default)(obj, function (_, key) {
|
|
return fn(key);
|
|
});
|
|
});
|
|
},
|
|
camelCase: function camelCase() {
|
|
return this.transformKeys(_camelCase2.default);
|
|
},
|
|
snakeCase: function snakeCase() {
|
|
return this.transformKeys(_snakeCase2.default);
|
|
},
|
|
constantCase: function constantCase() {
|
|
return this.transformKeys(function (key) {
|
|
return (0, _snakeCase2.default)(key).toUpperCase();
|
|
});
|
|
},
|
|
describe: function describe() {
|
|
var base = _mixed.default.prototype.describe.call(this);
|
|
|
|
base.fields = (0, _mapValues.default)(this.fields, function (value) {
|
|
return value.describe();
|
|
});
|
|
return base;
|
|
}
|
|
});
|
|
module.exports = exports["default"]; |