UNPKG

4.27 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.AjvSchema = void 0;
4const fs = require("fs");
5const js_lib_1 = require("@naturalcycles/js-lib");
6const index_1 = require("../../index");
7const ajvValidationError_1 = require("./ajvValidationError");
8const getAjv_1 = require("./getAjv");
9/**
10 * On creation - compiles ajv validation function.
11 * Provides convenient methods, error reporting, etc.
12 *
13 * @experimental
14 */
15class AjvSchema {
16 constructor(schema, cfg = {}) {
17 this.schema = schema;
18 this.cfg = {
19 logErrors: true,
20 logger: console,
21 separator: '\n',
22 ...cfg,
23 ajv: cfg.ajv ||
24 (0, getAjv_1.getAjv)({
25 schemas: cfg.schemas?.map(s => {
26 if (s instanceof AjvSchema)
27 return s.schema;
28 if (s instanceof js_lib_1.JsonSchemaAnyBuilder)
29 return s.build();
30 return s;
31 }),
32 coerceTypes: cfg.coerceTypes || false,
33 // verbose: true,
34 }),
35 // Auto-detecting "ObjectName" from $id of the schema (e.g "Address.schema.json")
36 objectName: cfg.objectName || (schema.$id ? (0, js_lib_1._substringBefore)(schema.$id, '.') : undefined),
37 };
38 this.validateFunction = this.cfg.ajv.compile(schema);
39 }
40 /**
41 * Conveniently allows to pass either JsonSchema or JsonSchemaBuilder, or existing AjvSchema.
42 * If it's already an AjvSchema - it'll just return it without any processing.
43 * If it's a Builder - will call `build` before proceeding.
44 * Otherwise - will construct AjvSchema instance ready to be used.
45 *
46 * Implementation note: JsonSchemaBuilder goes first in the union type, otherwise TypeScript fails to infer <T> type
47 * correctly for some reason.
48 */
49 static create(schema, cfg = {}) {
50 if (schema instanceof AjvSchema)
51 return schema;
52 if (schema instanceof js_lib_1.JsonSchemaAnyBuilder) {
53 return new AjvSchema(schema.build(), cfg);
54 }
55 return new AjvSchema(schema, cfg);
56 }
57 /**
58 * Create AjvSchema directly from a filePath of json schema.
59 * Convenient method that just does fs.readFileSync for you.
60 */
61 static readJsonSync(filePath, cfg = {}) {
62 (0, index_1.requireFileToExist)(filePath);
63 const schema = JSON.parse(fs.readFileSync(filePath, 'utf8'));
64 return new AjvSchema(schema, cfg);
65 }
66 /**
67 * It returns the original object just for convenience.
68 * Reminder: Ajv will MUTATE your object under 2 circumstances:
69 * 1. `useDefaults` option (enabled by default!), which will set missing/empty values that have `default` set in the schema.
70 * 2. `coerceTypes` (false by default).
71 *
72 * Returned object is always the same object (`===`) that was passed, so it is returned just for convenience.
73 */
74 validate(obj, opt = {}) {
75 const err = this.getValidationError(obj, opt);
76 if (err)
77 throw err;
78 return obj;
79 }
80 getValidationError(obj, opt = {}) {
81 if (this.isValid(obj))
82 return;
83 const errors = this.validateFunction.errors;
84 const { objectId = (0, js_lib_1._isObject)(obj) ? obj['id'] : undefined, objectName = this.cfg.objectName, logErrors = this.cfg.logErrors, separator = this.cfg.separator, } = opt;
85 const name = [objectName || 'Object', objectId].filter(Boolean).join('.');
86 let message = this.cfg.ajv.errorsText(errors, {
87 dataVar: name,
88 separator,
89 });
90 const strValue = (0, index_1.inspectAny)(obj, { maxLen: 1000 });
91 message = [message, 'Input: ' + strValue].join(separator);
92 if (logErrors) {
93 this.cfg.logger.error(errors);
94 }
95 return new ajvValidationError_1.AjvValidationError(message, (0, js_lib_1._filterNullishValues)({
96 errors,
97 userFriendly: true,
98 objectName,
99 objectId,
100 }));
101 }
102 isValid(obj) {
103 return this.validateFunction(obj);
104 }
105}
106exports.AjvSchema = AjvSchema;