1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.resolveSchema = exports.getCompilingSchema = exports.resolveRef = exports.compileSchema = exports.SchemaEnv = void 0;
|
4 | const codegen_1 = require("./codegen");
|
5 | const validation_error_1 = require("../runtime/validation_error");
|
6 | const names_1 = require("./names");
|
7 | const resolve_1 = require("./resolve");
|
8 | const util_1 = require("./util");
|
9 | const validate_1 = require("./validate");
|
10 | const URI = require("uri-js");
|
11 | class SchemaEnv {
|
12 | constructor(env) {
|
13 | var _a;
|
14 | this.refs = {};
|
15 | this.dynamicAnchors = {};
|
16 | let schema;
|
17 | if (typeof env.schema == "object")
|
18 | schema = env.schema;
|
19 | this.schema = env.schema;
|
20 | this.schemaId = env.schemaId;
|
21 | this.root = env.root || this;
|
22 | this.baseId = (_a = env.baseId) !== null && _a !== void 0 ? _a : resolve_1.normalizeId(schema === null || schema === void 0 ? void 0 : schema[env.schemaId || "$id"]);
|
23 | this.schemaPath = env.schemaPath;
|
24 | this.localRefs = env.localRefs;
|
25 | this.meta = env.meta;
|
26 | this.$async = schema === null || schema === void 0 ? void 0 : schema.$async;
|
27 | this.refs = {};
|
28 | }
|
29 | }
|
30 | exports.SchemaEnv = SchemaEnv;
|
31 |
|
32 |
|
33 |
|
34 | function compileSchema(sch) {
|
35 |
|
36 | const _sch = getCompilingSchema.call(this, sch);
|
37 | if (_sch)
|
38 | return _sch;
|
39 | const rootId = resolve_1.getFullPath(sch.root.baseId);
|
40 | const { es5, lines } = this.opts.code;
|
41 | const { ownProperties } = this.opts;
|
42 | const gen = new codegen_1.CodeGen(this.scope, { es5, lines, ownProperties });
|
43 | let _ValidationError;
|
44 | if (sch.$async) {
|
45 | _ValidationError = gen.scopeValue("Error", {
|
46 | ref: validation_error_1.default,
|
47 | code: codegen_1._ `require("ajv/dist/runtime/validation_error").default`,
|
48 | });
|
49 | }
|
50 | const validateName = gen.scopeName("validate");
|
51 | sch.validateName = validateName;
|
52 | const schemaCxt = {
|
53 | gen,
|
54 | allErrors: this.opts.allErrors,
|
55 | data: names_1.default.data,
|
56 | parentData: names_1.default.parentData,
|
57 | parentDataProperty: names_1.default.parentDataProperty,
|
58 | dataNames: [names_1.default.data],
|
59 | dataPathArr: [codegen_1.nil],
|
60 | dataLevel: 0,
|
61 | dataTypes: [],
|
62 | definedProperties: new Set(),
|
63 | topSchemaRef: gen.scopeValue("schema", this.opts.code.source === true
|
64 | ? { ref: sch.schema, code: codegen_1.stringify(sch.schema) }
|
65 | : { ref: sch.schema }),
|
66 | validateName,
|
67 | ValidationError: _ValidationError,
|
68 | schema: sch.schema,
|
69 | schemaEnv: sch,
|
70 | rootId,
|
71 | baseId: sch.baseId || rootId,
|
72 | schemaPath: codegen_1.nil,
|
73 | errSchemaPath: sch.schemaPath || (this.opts.jtd ? "" : "#"),
|
74 | errorPath: codegen_1._ `""`,
|
75 | opts: this.opts,
|
76 | self: this,
|
77 | };
|
78 | let sourceCode;
|
79 | try {
|
80 | this._compilations.add(sch);
|
81 | validate_1.validateFunctionCode(schemaCxt);
|
82 | gen.optimize(this.opts.code.optimize);
|
83 |
|
84 | const validateCode = gen.toString();
|
85 | sourceCode = `${gen.scopeRefs(names_1.default.scope)}return ${validateCode}`;
|
86 |
|
87 | if (this.opts.code.process)
|
88 | sourceCode = this.opts.code.process(sourceCode, sch);
|
89 |
|
90 | const makeValidate = new Function(`${names_1.default.self}`, `${names_1.default.scope}`, sourceCode);
|
91 | const validate = makeValidate(this, this.scope.get());
|
92 | this.scope.value(validateName, { ref: validate });
|
93 | validate.errors = null;
|
94 | validate.schema = sch.schema;
|
95 | validate.schemaEnv = sch;
|
96 | if (sch.$async)
|
97 | validate.$async = true;
|
98 | if (this.opts.code.source === true) {
|
99 | validate.source = { validateName, validateCode, scopeValues: gen._values };
|
100 | }
|
101 | if (this.opts.unevaluated) {
|
102 | const { props, items } = schemaCxt;
|
103 | validate.evaluated = {
|
104 | props: props instanceof codegen_1.Name ? undefined : props,
|
105 | items: items instanceof codegen_1.Name ? undefined : items,
|
106 | dynamicProps: props instanceof codegen_1.Name,
|
107 | dynamicItems: items instanceof codegen_1.Name,
|
108 | };
|
109 | if (validate.source)
|
110 | validate.source.evaluated = codegen_1.stringify(validate.evaluated);
|
111 | }
|
112 | sch.validate = validate;
|
113 | return sch;
|
114 | }
|
115 | catch (e) {
|
116 | delete sch.validate;
|
117 | delete sch.validateName;
|
118 | if (sourceCode)
|
119 | this.logger.error("Error compiling schema, function code:", sourceCode);
|
120 |
|
121 | throw e;
|
122 | }
|
123 | finally {
|
124 | this._compilations.delete(sch);
|
125 | }
|
126 | }
|
127 | exports.compileSchema = compileSchema;
|
128 | function resolveRef(root, baseId, ref) {
|
129 | var _a;
|
130 | ref = resolve_1.resolveUrl(baseId, ref);
|
131 | const schOrFunc = root.refs[ref];
|
132 | if (schOrFunc)
|
133 | return schOrFunc;
|
134 | let _sch = resolve.call(this, root, ref);
|
135 | if (_sch === undefined) {
|
136 | const schema = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
|
137 | const { schemaId } = this.opts;
|
138 | if (schema)
|
139 | _sch = new SchemaEnv({ schema, schemaId, root, baseId });
|
140 | }
|
141 | if (_sch === undefined)
|
142 | return;
|
143 | return (root.refs[ref] = inlineOrCompile.call(this, _sch));
|
144 | }
|
145 | exports.resolveRef = resolveRef;
|
146 | function inlineOrCompile(sch) {
|
147 | if (resolve_1.inlineRef(sch.schema, this.opts.inlineRefs))
|
148 | return sch.schema;
|
149 | return sch.validate ? sch : compileSchema.call(this, sch);
|
150 | }
|
151 |
|
152 | function getCompilingSchema(schEnv) {
|
153 | for (const sch of this._compilations) {
|
154 | if (sameSchemaEnv(sch, schEnv))
|
155 | return sch;
|
156 | }
|
157 | }
|
158 | exports.getCompilingSchema = getCompilingSchema;
|
159 | function sameSchemaEnv(s1, s2) {
|
160 | return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
161 | }
|
162 |
|
163 |
|
164 | function resolve(root, // information about the root schema for the current schema
|
165 | ref // reference to resolve
|
166 | ) {
|
167 | let sch;
|
168 | while (typeof (sch = this.refs[ref]) == "string")
|
169 | ref = sch;
|
170 | return sch || this.schemas[ref] || resolveSchema.call(this, root, ref);
|
171 | }
|
172 |
|
173 | function resolveSchema(root, // root object with properties schema, refs TODO below SchemaEnv is assigned to it
|
174 | ref // reference to resolve
|
175 | ) {
|
176 | const p = URI.parse(ref);
|
177 | const refPath = resolve_1._getFullPath(p);
|
178 | let baseId = resolve_1.getFullPath(root.baseId);
|
179 |
|
180 | if (Object.keys(root.schema).length > 0 && refPath === baseId) {
|
181 | return getJsonPointer.call(this, p, root);
|
182 | }
|
183 | const id = resolve_1.normalizeId(refPath);
|
184 | const schOrRef = this.refs[id] || this.schemas[id];
|
185 | if (typeof schOrRef == "string") {
|
186 | const sch = resolveSchema.call(this, root, schOrRef);
|
187 | if (typeof (sch === null || sch === void 0 ? void 0 : sch.schema) !== "object")
|
188 | return;
|
189 | return getJsonPointer.call(this, p, sch);
|
190 | }
|
191 | if (typeof (schOrRef === null || schOrRef === void 0 ? void 0 : schOrRef.schema) !== "object")
|
192 | return;
|
193 | if (!schOrRef.validate)
|
194 | compileSchema.call(this, schOrRef);
|
195 | if (id === resolve_1.normalizeId(ref)) {
|
196 | const { schema } = schOrRef;
|
197 | const { schemaId } = this.opts;
|
198 | const schId = schema[schemaId];
|
199 | if (schId)
|
200 | baseId = resolve_1.resolveUrl(baseId, schId);
|
201 | return new SchemaEnv({ schema, schemaId, root, baseId });
|
202 | }
|
203 | return getJsonPointer.call(this, p, schOrRef);
|
204 | }
|
205 | exports.resolveSchema = resolveSchema;
|
206 | const PREVENT_SCOPE_CHANGE = new Set([
|
207 | "properties",
|
208 | "patternProperties",
|
209 | "enum",
|
210 | "dependencies",
|
211 | "definitions",
|
212 | ]);
|
213 | function getJsonPointer(parsedRef, { baseId, schema, root }) {
|
214 | var _a;
|
215 | if (((_a = parsedRef.fragment) === null || _a === void 0 ? void 0 : _a[0]) !== "/")
|
216 | return;
|
217 | for (const part of parsedRef.fragment.slice(1).split("/")) {
|
218 | if (typeof schema == "boolean")
|
219 | return;
|
220 | schema = schema[util_1.unescapeFragment(part)];
|
221 | if (schema === undefined)
|
222 | return;
|
223 |
|
224 | const schId = typeof schema == "object" && schema[this.opts.schemaId];
|
225 | if (!PREVENT_SCOPE_CHANGE.has(part) && schId) {
|
226 | baseId = resolve_1.resolveUrl(baseId, schId);
|
227 | }
|
228 | }
|
229 | let env;
|
230 | if (typeof schema != "boolean" && schema.$ref && !util_1.schemaHasRulesButRef(schema, this.RULES)) {
|
231 | const $ref = resolve_1.resolveUrl(baseId, schema.$ref);
|
232 | env = resolveSchema.call(this, root, $ref);
|
233 | }
|
234 |
|
235 |
|
236 | const { schemaId } = this.opts;
|
237 | env = env || new SchemaEnv({ schema, schemaId, root, baseId });
|
238 | if (env.schema !== env.root.schema)
|
239 | return env;
|
240 | return undefined;
|
241 | }
|
242 |
|
\ | No newline at end of file |