UNPKG

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
"use strict"; 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 }; }