decorated-ajv
Version:
AJV decorated with error handling and formats
266 lines (265 loc) • 10.9 kB
JavaScript
;
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;
}
});
};