react-jsonschema-form-semantic
Version:
A simple React component capable of building HTML forms out of a JSON schema. Uses React Semantic UI (css not bundled)
235 lines (196 loc) • 7.53 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _defineProperty2 = require("babel-runtime/helpers/defineProperty");
var _defineProperty3 = _interopRequireDefault(_defineProperty2);
var _extends6 = require("babel-runtime/helpers/extends");
var _extends7 = _interopRequireDefault(_extends6);
var _keys = require("babel-runtime/core-js/object/keys");
var _keys2 = _interopRequireDefault(_keys);
var _getIterator2 = require("babel-runtime/core-js/get-iterator");
var _getIterator3 = _interopRequireDefault(_getIterator2);
exports.toErrorList = toErrorList;
exports.default = validateFormData;
var _toPath = require("lodash/toPath");
var _toPath2 = _interopRequireDefault(_toPath);
var _ajv = require("ajv");
var _ajv2 = _interopRequireDefault(_ajv);
var _utils = require("./utils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var ajv = new _ajv2.default({
errorDataPath: "property",
allErrors: true
});
// add custom formats
ajv.addFormat("data-url", /^data:([a-z]+\/[a-z0-9-+.]+)?;name=(.*);base64,(.*)$/);
ajv.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*\)))$/);
function toErrorSchema(errors) {
// Transforms a ajv validation errors list:
// [
// {property: ".level1.level2[2].level3", message: "err a"},
// {property: ".level1.level2[2].level3", message: "err b"},
// {property: ".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 = (0, _toPath2.default)(property);
var parent = errorSchema;
// If the property is at the root (.level1) then toPath creates
// an empty array element at the first index. Remove it.
if (path.length > 0 && path[0] === "") {
path.splice(0, 1);
}
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = (0, _getIterator3.default)(path.slice(0)), _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 (0, _keys2.default)(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 (0, _keys2.default)(formData).reduce(function (acc, key) {
return (0, _extends7.default)({}, acc, (0, _defineProperty3.default)({}, key, createErrorHandler(formData[key])));
}, handler);
}
if (Array.isArray(formData)) {
return formData.reduce(function (acc, value, key) {
return (0, _extends7.default)({}, acc, (0, _defineProperty3.default)({}, key, createErrorHandler(value)));
}, handler);
}
return handler;
}
function unwrapErrorHandler(errorHandler) {
return (0, _keys2.default)(errorHandler).reduce(function (acc, key) {
if (key === "addError") {
return acc;
} else if (key === "__errors") {
return (0, _extends7.default)({}, acc, (0, _defineProperty3.default)({}, key, errorHandler[key]));
}
return (0, _extends7.default)({}, acc, (0, _defineProperty3.default)({}, key, unwrapErrorHandler(errorHandler[key])));
}, {});
}
/**
* Transforming the error output from ajv to format used by jsonschema.
* At some point, components should be updated to support ajv.
*/
function transformAjvErrors() {
var errors = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
if (errors === null) {
return [];
}
return errors.map(function (e) {
var dataPath = e.dataPath,
keyword = e.keyword,
message = e.message,
params = e.params;
var property = "" + dataPath;
// put data in expected format
return {
name: keyword,
property: property,
message: message,
params: params, // specific to ajv
stack: (property + " " + message).trim()
};
});
}
/**
* 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, transformErrors) {
try {
ajv.validate(schema, formData);
} catch (e) {
// swallow errors thrown in ajv due to invalid schemas, these
// still get displayed
}
var errors = transformAjvErrors(ajv.errors);
if (typeof transformErrors === "function") {
errors = transformErrors(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 };
}