UNPKG

7.37 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6
7var _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; };
8
9exports.toErrorList = toErrorList;
10exports.default = validateFormData;
11
12var _lodash = require("lodash.topath");
13
14var _lodash2 = _interopRequireDefault(_lodash);
15
16var _ajv = require("ajv");
17
18var _ajv2 = _interopRequireDefault(_ajv);
19
20var _utils = require("./utils");
21
22function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
23
24function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
25
26var ajv = new _ajv2.default({
27 errorDataPath: "property",
28 allErrors: true
29});
30// add custom formats
31ajv.addFormat("data-url", /^data:([a-z]+\/[a-z0-9-+.]+)?;name=(.*);base64,(.*)$/);
32ajv.addFormat("color", /^(#?([0-9A-Fa-f]{3}){1,2}\b|aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|purple|red|silver|teal|white|yellow|(rgb\(\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*,\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*,\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*\))|(rgb\(\s*(\d?\d%|100%)+\s*,\s*(\d?\d%|100%)+\s*,\s*(\d?\d%|100%)+\s*\)))$/);
33
34function toErrorSchema(errors) {
35 // Transforms a ajv validation errors list:
36 // [
37 // {property: ".level1.level2[2].level3", message: "err a"},
38 // {property: ".level1.level2[2].level3", message: "err b"},
39 // {property: ".level1.level2[4].level3", message: "err b"},
40 // ]
41 // Into an error tree:
42 // {
43 // level1: {
44 // level2: {
45 // 2: {level3: {errors: ["err a", "err b"]}},
46 // 4: {level3: {errors: ["err b"]}},
47 // }
48 // }
49 // };
50 if (!errors.length) {
51 return {};
52 }
53 return errors.reduce(function (errorSchema, error) {
54 var property = error.property,
55 message = error.message;
56
57 var path = (0, _lodash2.default)(property);
58 var parent = errorSchema;
59
60 // If the property is at the root (.level1) then toPath creates
61 // an empty array element at the first index. Remove it.
62 if (path.length > 0 && path[0] === "") {
63 path.splice(0, 1);
64 }
65
66 var _iteratorNormalCompletion = true;
67 var _didIteratorError = false;
68 var _iteratorError = undefined;
69
70 try {
71 for (var _iterator = path.slice(0)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
72 var segment = _step.value;
73
74 if (!(segment in parent)) {
75 parent[segment] = {};
76 }
77 parent = parent[segment];
78 }
79 } catch (err) {
80 _didIteratorError = true;
81 _iteratorError = err;
82 } finally {
83 try {
84 if (!_iteratorNormalCompletion && _iterator.return) {
85 _iterator.return();
86 }
87 } finally {
88 if (_didIteratorError) {
89 throw _iteratorError;
90 }
91 }
92 }
93
94 if (Array.isArray(parent.__errors)) {
95 // We store the list of errors for this node in a property named __errors
96 // to avoid name collision with a possible sub schema field named
97 // "errors" (see `validate.createErrorHandler`).
98 parent.__errors = parent.__errors.concat(message);
99 } else {
100 parent.__errors = [message];
101 }
102 return errorSchema;
103 }, {});
104}
105
106function toErrorList(errorSchema) {
107 var fieldName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "root";
108
109 // XXX: We should transform fieldName as a full field path string.
110 var errorList = [];
111 if ("__errors" in errorSchema) {
112 errorList = errorList.concat(errorSchema.__errors.map(function (stack) {
113 return {
114 stack: fieldName + ": " + stack
115 };
116 }));
117 }
118 return Object.keys(errorSchema).reduce(function (acc, key) {
119 if (key !== "__errors") {
120 acc = acc.concat(toErrorList(errorSchema[key], key));
121 }
122 return acc;
123 }, errorList);
124}
125
126function createErrorHandler(formData) {
127 var handler = {
128 // We store the list of errors for this node in a property named __errors
129 // to avoid name collision with a possible sub schema field named
130 // "errors" (see `utils.toErrorSchema`).
131 __errors: [],
132 addError: function addError(message) {
133 this.__errors.push(message);
134 }
135 };
136 if ((0, _utils.isObject)(formData)) {
137 return Object.keys(formData).reduce(function (acc, key) {
138 return _extends({}, acc, _defineProperty({}, key, createErrorHandler(formData[key])));
139 }, handler);
140 }
141 if (Array.isArray(formData)) {
142 return formData.reduce(function (acc, value, key) {
143 return _extends({}, acc, _defineProperty({}, key, createErrorHandler(value)));
144 }, handler);
145 }
146 return handler;
147}
148
149function unwrapErrorHandler(errorHandler) {
150 return Object.keys(errorHandler).reduce(function (acc, key) {
151 if (key === "addError") {
152 return acc;
153 } else if (key === "__errors") {
154 return _extends({}, acc, _defineProperty({}, key, errorHandler[key]));
155 }
156 return _extends({}, acc, _defineProperty({}, key, unwrapErrorHandler(errorHandler[key])));
157 }, {});
158}
159
160/**
161 * Transforming the error output from ajv to format used by jsonschema.
162 * At some point, components should be updated to support ajv.
163 */
164function transformAjvErrors() {
165 var errors = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
166
167 if (errors === null) {
168 return [];
169 }
170
171 return errors.map(function (e) {
172 var dataPath = e.dataPath,
173 keyword = e.keyword,
174 message = e.message,
175 params = e.params;
176
177 var property = "" + dataPath;
178
179 // put data in expected format
180 return {
181 name: keyword,
182 property: property,
183 message: message,
184 params: params, // specific to ajv
185 stack: (property + " " + message).trim()
186 };
187 });
188}
189
190/**
191 * This function processes the formData with a user `validate` contributed
192 * function, which receives the form data and an `errorHandler` object that
193 * will be used to add custom validation errors for each field.
194 */
195function validateFormData(formData, schema, customValidate, transformErrors) {
196 try {
197 ajv.validate(schema, formData);
198 } catch (e) {
199 // swallow errors thrown in ajv due to invalid schemas, these
200 // still get displayed
201 }
202
203 var errors = transformAjvErrors(ajv.errors);
204
205 if (typeof transformErrors === "function") {
206 errors = transformErrors(errors);
207 }
208 var errorSchema = toErrorSchema(errors);
209
210 if (typeof customValidate !== "function") {
211 return { errors: errors, errorSchema: errorSchema };
212 }
213
214 var errorHandler = customValidate(formData, createErrorHandler(formData));
215 var userErrorSchema = unwrapErrorHandler(errorHandler);
216 var newErrorSchema = (0, _utils.mergeObjects)(errorSchema, userErrorSchema, true);
217 // XXX: The errors list produced is not fully compliant with the format
218 // exposed by the jsonschema lib, which contains full field paths and other
219 // properties.
220 var newErrors = toErrorList(newErrorSchema);
221
222 return { errors: newErrors, errorSchema: newErrorSchema };
223}
\No newline at end of file