UNPKG

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