himanshu-react-jsonschema-form
Version:
A simple React component capable of building HTML forms out of a JSON schema.
176 lines (154 loc) • 5.84 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: 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.toErrorList = toErrorList;
exports.default = validateFormData;
var _jsonschema = require("jsonschema");
var _utils = require("./utils");
function _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; }
var RE_ERROR_ARRAY_PATH = /\[\d+]/g;
function errorPropertyToPath(property) {
// Parse array indices, eg. "instance.level1.level2[2].level3"
// => ["instance", "level1", "level2", 2, "level3"]
return property.split(".").reduce(function (path, node) {
var match = node.match(RE_ERROR_ARRAY_PATH);
if (match) {
var nodeName = node.slice(0, node.indexOf("["));
var indices = match.map(function (str) {
return parseInt(str.slice(1, -1), 10);
});
path = path.concat(nodeName, indices);
} else {
path.push(node);
}
return path;
}, []);
}
function toErrorSchema(errors) {
// Transforms a jsonschema validation errors list:
// [
// {property: "instance.level1.level2[2].level3", message: "err a"},
// {property: "instance.level1.level2[2].level3", message: "err b"},
// {property: "instance.level1.level2[4].level3", message: "err b"},
// ]
// Into an error tree:
// {
// level1: {
// level2: {
// 2: {level3: {errors: ["err a", "err b"]}},
// 4: {level3: {errors: ["err b"]}},
// }
// }
// };
if (!errors.length) {
return {};
}
return errors.reduce(function (errorSchema, error) {
var property = error.property,
message = error.message;
var path = errorPropertyToPath(property);
var parent = errorSchema;
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = path.slice(1)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var segment = _step.value;
if (!(segment in parent)) {
parent[segment] = {};
}
parent = parent[segment];
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
if (Array.isArray(parent.__errors)) {
// We store the list of errors for this node in a property named __errors
// to avoid name collision with a possible sub schema field named
// "errors" (see `validate.createErrorHandler`).
parent.__errors = parent.__errors.concat(message);
} else {
parent.__errors = [message];
}
return errorSchema;
}, {});
}
function toErrorList(errorSchema) {
var fieldName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "root";
// XXX: We should transform fieldName as a full field path string.
var errorList = [];
if ("__errors" in errorSchema) {
errorList = errorList.concat(errorSchema.__errors.map(function (stack) {
return {
stack: fieldName + ": " + stack
};
}));
}
return Object.keys(errorSchema).reduce(function (acc, key) {
if (key !== "__errors") {
acc = acc.concat(toErrorList(errorSchema[key], key));
}
return acc;
}, errorList);
}
function createErrorHandler(formData) {
var handler = {
// We store the list of errors for this node in a property named __errors
// to avoid name collision with a possible sub schema field named
// "errors" (see `utils.toErrorSchema`).
__errors: [],
addError: function addError(message) {
this.__errors.push(message);
}
};
if ((0, _utils.isObject)(formData)) {
return Object.keys(formData).reduce(function (acc, key) {
return _extends({}, acc, _defineProperty({}, key, createErrorHandler(formData[key])));
}, handler);
}
return handler;
}
function unwrapErrorHandler(errorHandler) {
return Object.keys(errorHandler).reduce(function (acc, key) {
if (key === "addError") {
return acc;
} else if (key === "__errors") {
return _extends({}, acc, _defineProperty({}, key, errorHandler[key]));
}
return _extends({}, acc, _defineProperty({}, key, unwrapErrorHandler(errorHandler[key])));
}, {});
}
/**
* This function processes the formData with a user `validate` contributed
* function, which receives the form data and an `errorHandler` object that
* will be used to add custom validation errors for each field.
*/
function validateFormData(formData, schema, customValidate) {
var _jsonValidate = (0, _jsonschema.validate)(formData, schema),
errors = _jsonValidate.errors;
var errorSchema = toErrorSchema(errors);
if (typeof customValidate !== "function") {
return { errors: errors, errorSchema: errorSchema };
}
var errorHandler = customValidate(formData, createErrorHandler(formData));
var userErrorSchema = unwrapErrorHandler(errorHandler);
var newErrorSchema = (0, _utils.mergeObjects)(errorSchema, userErrorSchema, true);
// XXX: The errors list produced is not fully compliant with the format
// exposed by the jsonschema lib, which contains full field paths and other
// properties.
var newErrors = toErrorList(newErrorSchema);
return { errors: newErrors, errorSchema: newErrorSchema };
}