UNPKG

decorated-ajv

Version:

AJV decorated with error handling and formats

259 lines (258 loc) 10.2 kB
import { __assign, __awaiter, __generator, __rest } from "tslib"; import Ajv from "ajv"; import addErrors from "ajv-errors"; import addFormats from "ajv-formats"; import standaloneCode from "ajv/dist/standalone"; import { uniq } from "lodash"; import fetch from "cross-fetch"; var downloadSchemaFromWeb = function (url) { return __awaiter(void 0, void 0, void 0, function () { var response; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, fetch(url)]; case 1: response = _a.sent(); return [4 /*yield*/, response.json()]; case 2: return [2 /*return*/, _a.sent()]; } }); }); }; var loadedSchemas = {}; var loadSchema = function (id) { return __awaiter(void 0, void 0, void 0, function () { var _a, _b; return __generator(this, function (_c) { switch (_c.label) { case 0: if (!!loadedSchemas[id]) return [3 /*break*/, 2]; _a = loadedSchemas; _b = id; return [4 /*yield*/, downloadSchemaFromWeb(id)]; case 1: _a[_b] = _c.sent(); _c.label = 2; case 2: return [2 /*return*/, loadedSchemas[id]]; } }); }); }; export var getAjv = function (options) { var ajv = new Ajv(__assign(__assign({ loadSchema: loadSchema }, options), { allErrors: true })); addFormats(ajv); addErrors(ajv); return ajv; }; export var getValidator = function (schema, ajv) { return __awaiter(void 0, void 0, void 0, function () { var _ajv, validator; return __generator(this, function (_a) { switch (_a.label) { case 0: _ajv = ajv || getAjv(); return [4 /*yield*/, _ajv.compileAsync(schema)]; case 1: validator = _a.sent(); return [2 /*return*/, validator]; } }); }); }; export var getCompiledValidator = function (schema, options) { if (options === void 0) { options = {}; } return __awaiter(void 0, void 0, void 0, function () { var _options, ajv, validate, moduleCode; return __generator(this, function (_a) { switch (_a.label) { case 0: _options = __assign({}, options); if (_options.code === undefined) { _options.code = {}; } _options.code.source = true; ajv = getAjv(_options); return [4 /*yield*/, getValidator(schema, ajv)]; case 1: validate = _a.sent(); moduleCode = standaloneCode(ajv, validate); return [2 /*return*/, moduleCode]; } }); }); }; /** * @param schema a valid JSON Schema. is ignored if validate function is passed * @param data * @param validate */ export var validate = function (schema, data, validate) { return __awaiter(void 0, void 0, void 0, function () { var _validate, _a, _b, violations; return __generator(this, function (_c) { switch (_c.label) { case 0: _a = validate; if (_a) return [3 /*break*/, 4]; if (!(typeof schema == "function")) return [3 /*break*/, 1]; _b = schema; return [3 /*break*/, 3]; case 1: return [4 /*yield*/, getValidator(schema)]; case 2: _b = _c.sent(); _c.label = 3; case 3: _a = (_b); _c.label = 4; case 4: _validate = _a; if (!_validate(data)) { violations = generateViolations(_validate.errors); return [2 /*return*/, violations]; } return [2 /*return*/, []]; } }); }); }; var generateViolations = function (errors) { var filteredErrors = errors; try { filteredErrors = filterErrors(errors); } catch (e) { // don't do anything } return filteredErrors.map( // eslint-disable-next-line @typescript-eslint/no-unused-vars function (_a) { var instancePath = _a.instancePath, message = _a.message, schemaPath = _a.schemaPath, keyword = _a.keyword, context = __rest(_a, ["instancePath", "message", "schemaPath", "keyword"]); return ({ path: (instancePath.match(/([^\\/])+/g) || []).join("."), message: message, context: context }); }); }; var filterErrors = function (errors) { var filteredErrors = errors.map(function (e) { e.params.__filter = {}; return e; }); filteredErrors = extractErrorMessageKeyword(filteredErrors); var siblings = getSiblings(filteredErrors); applyOneOfOrAnyOf(filteredErrors, "oneOf", siblings); applyOneOfOrAnyOf(filteredErrors, "anyOf", siblings); deleteErrorsForKey(filteredErrors, "allOf"); deleteErrorsForKey(filteredErrors, "if"); deleteErrorsForKey(filteredErrors, "then"); deleteErrorsForKey(filteredErrors, "else"); var remainingErrors = filteredErrors.filter(function (e) { var _a, _b; return !((_b = (_a = e.params) === null || _a === void 0 ? void 0 : _a.__filter) === null || _b === void 0 ? void 0 : _b.delete); }); if (remainingErrors.length == 0) { remainingErrors = [filteredErrors[0]]; } return remainingErrors.map(function (e) { delete e.params.__filter; return e; }); }; var extractErrorMessageKeyword = function (errors) { var allErrors = []; errors.forEach(function (error) { if (error.keyword == "errorMessage") { if (error.params.errors) { var originalErrors = error.params.errors; delete error.params.errors; var originalErrorsWithFilter = originalErrors.map(function (e) { e.params.__filter = { delete: true, errorMessage: error.schemaPath }; return e; }); allErrors.push.apply(allErrors, originalErrorsWithFilter); } } allErrors.push(error); }); return allErrors; }; var getSiblings = function (errors) { var siblings = {}; errors.forEach(function (error) { if (error.keyword != "errorMessage") { var schemaPath_1 = error.schemaPath; var parentSchemaPath_1 = schemaPath_1.substring(0, schemaPath_1.lastIndexOf("/")); errors.forEach(function (_error) { if (_error.keyword != "errorMessage") { if (!_error.schemaPath.startsWith(schemaPath_1) && _error.schemaPath.startsWith(parentSchemaPath_1)) { if (!siblings[schemaPath_1]) { siblings[schemaPath_1] = []; } siblings[schemaPath_1].push(_error.schemaPath); } } }); } }); return siblings; }; var applyOneOfOrAnyOf = function (errors, type, siblings) { deleteErrorsForKey(errors, type); var typeSchemaPaths = uniq(errors.filter(function (e) { return e.keyword == type; }).map(function (e) { return e.schemaPath; })); var typeSchemaPathToErrorsMap = {}; errors.forEach(function (error) { typeSchemaPaths.forEach(function (typeSp) { if (error.schemaPath != typeSp && error.schemaPath.startsWith(typeSp)) { if (!error.params.__filter[type]) { error.params.__filter[type] = []; } error.params.__filter[type].push(typeSp); if (!typeSchemaPathToErrorsMap[typeSp]) { typeSchemaPathToErrorsMap[typeSp] = []; } typeSchemaPathToErrorsMap[typeSp].push(error); } }); }); Object.keys(typeSchemaPathToErrorsMap).forEach(function (typeSp) { var typeErrors = typeSchemaPathToErrorsMap[typeSp]; if (siblings[typeSp] && siblings[typeSp].length > 0) { typeErrors.forEach(function (e) { e.params.__filter.delete = true; }); } else { var typeErrorsByIndex_1 = {}; typeErrors.forEach(function (e) { var index = e.schemaPath.substring(typeSp.length + 1, e.schemaPath.indexOf("/", typeSp.length + 1)); if (!typeErrorsByIndex_1[index]) { typeErrorsByIndex_1[index] = []; } typeErrorsByIndex_1[index].push(e); }); var typeErrorSchemaPathsByIndex_1 = {}; Object.keys(typeErrorsByIndex_1).forEach(function (index) { var schemaPathWithIndexLength = "".concat(typeSp, "/").concat(index, "/").length; typeErrorSchemaPathsByIndex_1[index] = uniq(typeErrorsByIndex_1[index].map(function (e) { return e.schemaPath.substring(schemaPathWithIndexLength, e.schemaPath.indexOf("/", schemaPathWithIndexLength)); })); }); var allIndexes = Object.keys(typeErrorSchemaPathsByIndex_1); var indexWithMinimumErrors_1 = allIndexes[0]; allIndexes.forEach(function (i) { if (typeErrorSchemaPathsByIndex_1[i].length < typeErrorSchemaPathsByIndex_1[indexWithMinimumErrors_1].length) { indexWithMinimumErrors_1 = i; } }); allIndexes.forEach(function (i) { if (i != indexWithMinimumErrors_1) { typeErrorsByIndex_1[i].forEach(function (e) { e.params.__filter.delete = true; }); } }); } }); }; var deleteErrorsForKey = function (errors, key) { errors.forEach(function (e) { if (e.keyword == key) { e.params.__filter.delete = true; } }); };