@naturalcycles/nodejs-lib
Version:
Standard library for Node.js
107 lines (106 loc) • 4.27 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.AjvSchema = void 0;
const fs = require("fs");
const js_lib_1 = require("@naturalcycles/js-lib");
const index_1 = require("../../index");
const ajvValidationError_1 = require("./ajvValidationError");
const getAjv_1 = require("./getAjv");
/**
* On creation - compiles ajv validation function.
* Provides convenient methods, error reporting, etc.
*
* @experimental
*/
class AjvSchema {
constructor(schema, cfg = {}) {
this.schema = schema;
this.cfg = {
logErrors: true,
logger: console,
separator: '\n',
...cfg,
ajv: cfg.ajv ||
(0, getAjv_1.getAjv)({
schemas: cfg.schemas?.map(s => {
if (s instanceof AjvSchema)
return s.schema;
if (s instanceof js_lib_1.JsonSchemaAnyBuilder)
return s.build();
return s;
}),
coerceTypes: cfg.coerceTypes || false,
// verbose: true,
}),
// Auto-detecting "ObjectName" from $id of the schema (e.g "Address.schema.json")
objectName: cfg.objectName || (schema.$id ? (0, js_lib_1._substringBefore)(schema.$id, '.') : undefined),
};
this.validateFunction = this.cfg.ajv.compile(schema);
}
/**
* Conveniently allows to pass either JsonSchema or JsonSchemaBuilder, or existing AjvSchema.
* If it's already an AjvSchema - it'll just return it without any processing.
* If it's a Builder - will call `build` before proceeding.
* Otherwise - will construct AjvSchema instance ready to be used.
*
* Implementation note: JsonSchemaBuilder goes first in the union type, otherwise TypeScript fails to infer <T> type
* correctly for some reason.
*/
static create(schema, cfg = {}) {
if (schema instanceof AjvSchema)
return schema;
if (schema instanceof js_lib_1.JsonSchemaAnyBuilder) {
return new AjvSchema(schema.build(), cfg);
}
return new AjvSchema(schema, cfg);
}
/**
* Create AjvSchema directly from a filePath of json schema.
* Convenient method that just does fs.readFileSync for you.
*/
static readJsonSync(filePath, cfg = {}) {
(0, index_1.requireFileToExist)(filePath);
const schema = JSON.parse(fs.readFileSync(filePath, 'utf8'));
return new AjvSchema(schema, cfg);
}
/**
* It returns the original object just for convenience.
* Reminder: Ajv will MUTATE your object under 2 circumstances:
* 1. `useDefaults` option (enabled by default!), which will set missing/empty values that have `default` set in the schema.
* 2. `coerceTypes` (false by default).
*
* Returned object is always the same object (`===`) that was passed, so it is returned just for convenience.
*/
validate(obj, opt = {}) {
const err = this.getValidationError(obj, opt);
if (err)
throw err;
return obj;
}
getValidationError(obj, opt = {}) {
if (this.isValid(obj))
return;
const errors = this.validateFunction.errors;
const { objectId = (0, js_lib_1._isObject)(obj) ? obj['id'] : undefined, objectName = this.cfg.objectName, logErrors = this.cfg.logErrors, separator = this.cfg.separator, } = opt;
const name = [objectName || 'Object', objectId].filter(Boolean).join('.');
let message = this.cfg.ajv.errorsText(errors, {
dataVar: name,
separator,
});
const strValue = (0, index_1.inspectAny)(obj, { maxLen: 1000 });
message = [message, 'Input: ' + strValue].join(separator);
if (logErrors) {
this.cfg.logger.error(errors);
}
return new ajvValidationError_1.AjvValidationError(message, (0, js_lib_1._filterNullishValues)({
errors,
userFriendly: true,
objectName,
objectId,
}));
}
isValid(obj) {
return this.validateFunction(obj);
}
}
exports.AjvSchema = AjvSchema;
;