UNPKG

9.2 kBJavaScriptView Raw
1"use strict";
2
3var _interopRequireWildcard = require("@babel/runtime/helpers/builtin/interopRequireWildcard");
4
5var _interopRequireDefault = require("@babel/runtime/helpers/builtin/interopRequireDefault");
6
7exports.__esModule = true;
8exports.default = ObjectSchema;
9
10var _taggedTemplateLiteralLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/builtin/taggedTemplateLiteralLoose"));
11
12var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/builtin/extends"));
13
14var _has = _interopRequireDefault(require("lodash/has"));
15
16var _snakeCase2 = _interopRequireDefault(require("lodash/snakeCase"));
17
18var _camelCase2 = _interopRequireDefault(require("lodash/camelCase"));
19
20var _mapKeys = _interopRequireDefault(require("lodash/mapKeys"));
21
22var _mapValues = _interopRequireDefault(require("lodash/mapValues"));
23
24var _propertyExpr = require("property-expr");
25
26var _mixed = _interopRequireDefault(require("./mixed"));
27
28var _locale = require("./locale.js");
29
30var _sortFields = _interopRequireDefault(require("./util/sortFields"));
31
32var _sortByKeyOrder = _interopRequireDefault(require("./util/sortByKeyOrder"));
33
34var _inherits = _interopRequireDefault(require("./util/inherits"));
35
36var _makePath = _interopRequireDefault(require("./util/makePath"));
37
38var _runValidations = _interopRequireWildcard(require("./util/runValidations"));
39
40function _templateObject2() {
41 var data = (0, _taggedTemplateLiteralLoose2.default)(["", ".", ""]);
42
43 _templateObject2 = function _templateObject2() {
44 return data;
45 };
46
47 return data;
48}
49
50function _templateObject() {
51 var data = (0, _taggedTemplateLiteralLoose2.default)(["", ".", ""]);
52
53 _templateObject = function _templateObject() {
54 return data;
55 };
56
57 return data;
58}
59
60var isObject = function isObject(obj) {
61 return Object.prototype.toString.call(obj) === '[object Object]';
62};
63
64function unknown(ctx, value) {
65 var known = Object.keys(ctx.fields);
66 return Object.keys(value).filter(function (key) {
67 return known.indexOf(key) === -1;
68 });
69}
70
71function ObjectSchema(spec) {
72 var _this2 = this;
73
74 if (!(this instanceof ObjectSchema)) return new ObjectSchema(spec);
75
76 _mixed.default.call(this, {
77 type: 'object',
78 default: function _default() {
79 var _this = this;
80
81 if (!this._nodes.length) return undefined;
82 var dft = {};
83
84 this._nodes.forEach(function (key) {
85 dft[key] = _this.fields[key].default ? _this.fields[key].default() : undefined;
86 });
87
88 return dft;
89 }
90 });
91
92 this.fields = Object.create(null);
93 this._nodes = [];
94 this._excludedEdges = [];
95 this.withMutation(function () {
96 _this2.transform(function coerce(value) {
97 if (typeof value === 'string') {
98 try {
99 value = JSON.parse(value);
100 } catch (err) {
101 value = null;
102 }
103 }
104
105 if (this.isType(value)) return value;
106 return null;
107 });
108
109 if (spec) {
110 _this2.shape(spec);
111 }
112 });
113}
114
115(0, _inherits.default)(ObjectSchema, _mixed.default, {
116 _typeCheck: function _typeCheck(value) {
117 return isObject(value) || typeof value === 'function';
118 },
119 _cast: function _cast(_value, options) {
120 var _this3 = this;
121
122 if (options === void 0) {
123 options = {};
124 }
125
126 var value = _mixed.default.prototype._cast.call(this, _value, options); //should ignore nulls here
127
128
129 if (value === undefined) return this.default();
130 if (!this._typeCheck(value)) return value;
131 var fields = this.fields;
132 var strip = this._option('stripUnknown', options) === true;
133
134 var props = this._nodes.concat(Object.keys(value).filter(function (v) {
135 return _this3._nodes.indexOf(v) === -1;
136 }));
137
138 var intermediateValue = {}; // is filled during the transform below
139
140 var innerOptions = (0, _extends2.default)({}, options, {
141 parent: intermediateValue,
142 __validating: false
143 });
144 props.forEach(function (prop) {
145 var field = fields[prop];
146 var exists = (0, _has.default)(value, prop);
147
148 if (field) {
149 var fieldValue;
150 var strict = field._options && field._options.strict; // safe to mutate since this is fired in sequence
151
152 innerOptions.path = (0, _makePath.default)(_templateObject(), options.path, prop);
153 innerOptions.value = value[prop];
154 field = field.resolve(innerOptions);
155 if (field._strip === true) return;
156 fieldValue = !options.__validating || !strict ? field.cast(value[prop], innerOptions) : value[prop];
157 if (fieldValue !== undefined) intermediateValue[prop] = fieldValue;
158 } else if (exists && !strip) intermediateValue[prop] = value[prop];
159 });
160 return intermediateValue;
161 },
162 _validate: function _validate(_value, opts) {
163 var _this4 = this;
164
165 if (opts === void 0) {
166 opts = {};
167 }
168
169 var endEarly, recursive;
170 var sync = opts.sync;
171 var errors = [];
172 var originalValue = opts.originalValue != null ? opts.originalValue : _value;
173 endEarly = this._option('abortEarly', opts);
174 recursive = this._option('recursive', opts);
175 opts = (0, _extends2.default)({}, opts, {
176 __validating: true,
177 originalValue: originalValue
178 });
179 return _mixed.default.prototype._validate.call(this, _value, opts).catch((0, _runValidations.propagateErrors)(endEarly, errors)).then(function (value) {
180 if (!recursive || !isObject(value)) {
181 // only iterate though actual objects
182 if (errors.length) throw errors[0];
183 return value;
184 }
185
186 originalValue = originalValue || value;
187
188 var validations = _this4._nodes.map(function (key) {
189 var path = (0, _makePath.default)(_templateObject2(), opts.path, key);
190 var field = _this4.fields[key];
191 var innerOptions = (0, _extends2.default)({}, opts, {
192 path: path,
193 parent: value,
194 originalValue: originalValue[key]
195 });
196
197 if (field) {
198 // inner fields are always strict:
199 // 1. this isn't strict so the casting will also have cast inner values
200 // 2. this is strict in which case the nested values weren't cast either
201 innerOptions.strict = true;
202 if (field.validate) return field.validate(value[key], innerOptions);
203 }
204
205 return true;
206 });
207
208 return (0, _runValidations.default)({
209 sync: sync,
210 validations: validations,
211 value: value,
212 errors: errors,
213 endEarly: endEarly,
214 path: opts.path,
215 sort: (0, _sortByKeyOrder.default)(_this4.fields)
216 });
217 });
218 },
219 concat: function concat(schema) {
220 var next = _mixed.default.prototype.concat.call(this, schema);
221
222 next._nodes = (0, _sortFields.default)(next.fields, next._excludedEdges);
223 return next;
224 },
225 shape: function shape(schema, excludes) {
226 if (excludes === void 0) {
227 excludes = [];
228 }
229
230 var next = this.clone(),
231 fields = (0, _extends2.default)(next.fields, schema);
232 next.fields = fields;
233
234 if (excludes.length) {
235 if (!Array.isArray(excludes[0])) excludes = [excludes];
236 var keys = excludes.map(function (_ref) {
237 var first = _ref[0],
238 second = _ref[1];
239 return first + "-" + second;
240 });
241 next._excludedEdges = next._excludedEdges.concat(keys);
242 }
243
244 next._nodes = (0, _sortFields.default)(fields, next._excludedEdges);
245 return next;
246 },
247 from: function from(_from, to, alias) {
248 var fromGetter = (0, _propertyExpr.getter)(_from, true);
249 return this.transform(function (obj) {
250 var newObj = obj;
251 if (obj == null) return obj;
252
253 if ((0, _has.default)(obj, _from)) {
254 newObj = (0, _extends2.default)({}, obj);
255 if (!alias) delete obj[_from];
256 newObj[to] = fromGetter(obj);
257 }
258
259 return newObj;
260 });
261 },
262 noUnknown: function noUnknown(noAllow, message) {
263 if (noAllow === void 0) {
264 noAllow = true;
265 }
266
267 if (message === void 0) {
268 message = _locale.object.noUnknown;
269 }
270
271 if (typeof noAllow === 'string') {
272 message = noAllow;
273 noAllow = true;
274 }
275
276 var next = this.test({
277 name: 'noUnknown',
278 exclusive: true,
279 message: message,
280 test: function test(value) {
281 return value == null || !noAllow || unknown(this.schema, value).length === 0;
282 }
283 });
284 if (noAllow) next._options.stripUnknown = true;
285 return next;
286 },
287 transformKeys: function transformKeys(fn) {
288 return this.transform(function (obj) {
289 return obj && (0, _mapKeys.default)(obj, function (_, key) {
290 return fn(key);
291 });
292 });
293 },
294 camelCase: function camelCase() {
295 return this.transformKeys(_camelCase2.default);
296 },
297 snakeCase: function snakeCase() {
298 return this.transformKeys(_snakeCase2.default);
299 },
300 constantCase: function constantCase() {
301 return this.transformKeys(function (key) {
302 return (0, _snakeCase2.default)(key).toUpperCase();
303 });
304 },
305 describe: function describe() {
306 var base = _mixed.default.prototype.describe.call(this);
307
308 base.fields = (0, _mapValues.default)(this.fields, function (value) {
309 return value.describe();
310 });
311 return base;
312 }
313});
314module.exports = exports["default"];
\No newline at end of file