UNPKG

decorated-ajv

Version:

AJV decorated with error handling and formats

266 lines (265 loc) 10.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.validate = exports.getCompiledValidator = exports.getValidator = exports.getAjv = void 0; var tslib_1 = require("tslib"); var ajv_1 = tslib_1.__importDefault(require("ajv")); var ajv_errors_1 = tslib_1.__importDefault(require("ajv-errors")); var ajv_formats_1 = tslib_1.__importDefault(require("ajv-formats")); var standalone_1 = tslib_1.__importDefault(require("ajv/dist/standalone")); var lodash_1 = require("lodash"); var cross_fetch_1 = tslib_1.__importDefault(require("cross-fetch")); var downloadSchemaFromWeb = function (url) { return tslib_1.__awaiter(void 0, void 0, void 0, function () { var response; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, (0, cross_fetch_1.default)(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 tslib_1.__awaiter(void 0, void 0, void 0, function () { var _a, _b; return tslib_1.__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]]; } }); }); }; var getAjv = function (options) { var ajv = new ajv_1.default(tslib_1.__assign(tslib_1.__assign({ loadSchema: loadSchema }, options), { allErrors: true })); (0, ajv_formats_1.default)(ajv); (0, ajv_errors_1.default)(ajv); return ajv; }; exports.getAjv = getAjv; var getValidator = function (schema, ajv) { return tslib_1.__awaiter(void 0, void 0, void 0, function () { var _ajv, validator; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: _ajv = ajv || (0, exports.getAjv)(); return [4 /*yield*/, _ajv.compileAsync(schema)]; case 1: validator = _a.sent(); return [2 /*return*/, validator]; } }); }); }; exports.getValidator = getValidator; var getCompiledValidator = function (schema, options) { if (options === void 0) { options = {}; } return tslib_1.__awaiter(void 0, void 0, void 0, function () { var _options, ajv, validate, moduleCode; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: _options = tslib_1.__assign({}, options); if (_options.code === undefined) { _options.code = {}; } _options.code.source = true; ajv = (0, exports.getAjv)(_options); return [4 /*yield*/, (0, exports.getValidator)(schema, ajv)]; case 1: validate = _a.sent(); moduleCode = (0, standalone_1.default)(ajv, validate); return [2 /*return*/, moduleCode]; } }); }); }; exports.getCompiledValidator = getCompiledValidator; /** * @param schema a valid JSON Schema. is ignored if validate function is passed * @param data * @param validate */ var validate = function (schema, data, validate) { return tslib_1.__awaiter(void 0, void 0, void 0, function () { var _validate, _a, _b, violations; return tslib_1.__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*/, (0, exports.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*/, []]; } }); }); }; exports.validate = validate; 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 = tslib_1.__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 = (0, lodash_1.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] = (0, lodash_1.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; } }); };