UNPKG

@naturalcycles/nodejs-lib

Version:
107 lines (106 loc) 4.27 kB
"use strict"; 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;