source: imaps-frontend/node_modules/ajv/dist/compile/validate/index.js@ 79a0317

main
Last change on this file since 79a0317 was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 3 days ago

F4 Finalna Verzija

  • Property mode set to 100644
File size: 20.1 KB
Line 
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.getData = exports.KeywordCxt = exports.validateFunctionCode = void 0;
4const boolSchema_1 = require("./boolSchema");
5const dataType_1 = require("./dataType");
6const applicability_1 = require("./applicability");
7const dataType_2 = require("./dataType");
8const defaults_1 = require("./defaults");
9const keyword_1 = require("./keyword");
10const subschema_1 = require("./subschema");
11const codegen_1 = require("../codegen");
12const names_1 = require("../names");
13const resolve_1 = require("../resolve");
14const util_1 = require("../util");
15const errors_1 = require("../errors");
16// schema compilation - generates validation function, subschemaCode (below) is used for subschemas
17function validateFunctionCode(it) {
18 if (isSchemaObj(it)) {
19 checkKeywords(it);
20 if (schemaCxtHasRules(it)) {
21 topSchemaObjCode(it);
22 return;
23 }
24 }
25 validateFunction(it, () => (0, boolSchema_1.topBoolOrEmptySchema)(it));
26}
27exports.validateFunctionCode = validateFunctionCode;
28function validateFunction({ gen, validateName, schema, schemaEnv, opts }, body) {
29 if (opts.code.es5) {
30 gen.func(validateName, (0, codegen_1._) `${names_1.default.data}, ${names_1.default.valCxt}`, schemaEnv.$async, () => {
31 gen.code((0, codegen_1._) `"use strict"; ${funcSourceUrl(schema, opts)}`);
32 destructureValCxtES5(gen, opts);
33 gen.code(body);
34 });
35 }
36 else {
37 gen.func(validateName, (0, codegen_1._) `${names_1.default.data}, ${destructureValCxt(opts)}`, schemaEnv.$async, () => gen.code(funcSourceUrl(schema, opts)).code(body));
38 }
39}
40function destructureValCxt(opts) {
41 return (0, codegen_1._) `{${names_1.default.instancePath}="", ${names_1.default.parentData}, ${names_1.default.parentDataProperty}, ${names_1.default.rootData}=${names_1.default.data}${opts.dynamicRef ? (0, codegen_1._) `, ${names_1.default.dynamicAnchors}={}` : codegen_1.nil}}={}`;
42}
43function destructureValCxtES5(gen, opts) {
44 gen.if(names_1.default.valCxt, () => {
45 gen.var(names_1.default.instancePath, (0, codegen_1._) `${names_1.default.valCxt}.${names_1.default.instancePath}`);
46 gen.var(names_1.default.parentData, (0, codegen_1._) `${names_1.default.valCxt}.${names_1.default.parentData}`);
47 gen.var(names_1.default.parentDataProperty, (0, codegen_1._) `${names_1.default.valCxt}.${names_1.default.parentDataProperty}`);
48 gen.var(names_1.default.rootData, (0, codegen_1._) `${names_1.default.valCxt}.${names_1.default.rootData}`);
49 if (opts.dynamicRef)
50 gen.var(names_1.default.dynamicAnchors, (0, codegen_1._) `${names_1.default.valCxt}.${names_1.default.dynamicAnchors}`);
51 }, () => {
52 gen.var(names_1.default.instancePath, (0, codegen_1._) `""`);
53 gen.var(names_1.default.parentData, (0, codegen_1._) `undefined`);
54 gen.var(names_1.default.parentDataProperty, (0, codegen_1._) `undefined`);
55 gen.var(names_1.default.rootData, names_1.default.data);
56 if (opts.dynamicRef)
57 gen.var(names_1.default.dynamicAnchors, (0, codegen_1._) `{}`);
58 });
59}
60function topSchemaObjCode(it) {
61 const { schema, opts, gen } = it;
62 validateFunction(it, () => {
63 if (opts.$comment && schema.$comment)
64 commentKeyword(it);
65 checkNoDefault(it);
66 gen.let(names_1.default.vErrors, null);
67 gen.let(names_1.default.errors, 0);
68 if (opts.unevaluated)
69 resetEvaluated(it);
70 typeAndKeywords(it);
71 returnResults(it);
72 });
73 return;
74}
75function resetEvaluated(it) {
76 // TODO maybe some hook to execute it in the end to check whether props/items are Name, as in assignEvaluated
77 const { gen, validateName } = it;
78 it.evaluated = gen.const("evaluated", (0, codegen_1._) `${validateName}.evaluated`);
79 gen.if((0, codegen_1._) `${it.evaluated}.dynamicProps`, () => gen.assign((0, codegen_1._) `${it.evaluated}.props`, (0, codegen_1._) `undefined`));
80 gen.if((0, codegen_1._) `${it.evaluated}.dynamicItems`, () => gen.assign((0, codegen_1._) `${it.evaluated}.items`, (0, codegen_1._) `undefined`));
81}
82function funcSourceUrl(schema, opts) {
83 const schId = typeof schema == "object" && schema[opts.schemaId];
84 return schId && (opts.code.source || opts.code.process) ? (0, codegen_1._) `/*# sourceURL=${schId} */` : codegen_1.nil;
85}
86// schema compilation - this function is used recursively to generate code for sub-schemas
87function subschemaCode(it, valid) {
88 if (isSchemaObj(it)) {
89 checkKeywords(it);
90 if (schemaCxtHasRules(it)) {
91 subSchemaObjCode(it, valid);
92 return;
93 }
94 }
95 (0, boolSchema_1.boolOrEmptySchema)(it, valid);
96}
97function schemaCxtHasRules({ schema, self }) {
98 if (typeof schema == "boolean")
99 return !schema;
100 for (const key in schema)
101 if (self.RULES.all[key])
102 return true;
103 return false;
104}
105function isSchemaObj(it) {
106 return typeof it.schema != "boolean";
107}
108function subSchemaObjCode(it, valid) {
109 const { schema, gen, opts } = it;
110 if (opts.$comment && schema.$comment)
111 commentKeyword(it);
112 updateContext(it);
113 checkAsyncSchema(it);
114 const errsCount = gen.const("_errs", names_1.default.errors);
115 typeAndKeywords(it, errsCount);
116 // TODO var
117 gen.var(valid, (0, codegen_1._) `${errsCount} === ${names_1.default.errors}`);
118}
119function checkKeywords(it) {
120 (0, util_1.checkUnknownRules)(it);
121 checkRefsAndKeywords(it);
122}
123function typeAndKeywords(it, errsCount) {
124 if (it.opts.jtd)
125 return schemaKeywords(it, [], false, errsCount);
126 const types = (0, dataType_1.getSchemaTypes)(it.schema);
127 const checkedTypes = (0, dataType_1.coerceAndCheckDataType)(it, types);
128 schemaKeywords(it, types, !checkedTypes, errsCount);
129}
130function checkRefsAndKeywords(it) {
131 const { schema, errSchemaPath, opts, self } = it;
132 if (schema.$ref && opts.ignoreKeywordsWithRef && (0, util_1.schemaHasRulesButRef)(schema, self.RULES)) {
133 self.logger.warn(`$ref: keywords ignored in schema at path "${errSchemaPath}"`);
134 }
135}
136function checkNoDefault(it) {
137 const { schema, opts } = it;
138 if (schema.default !== undefined && opts.useDefaults && opts.strictSchema) {
139 (0, util_1.checkStrictMode)(it, "default is ignored in the schema root");
140 }
141}
142function updateContext(it) {
143 const schId = it.schema[it.opts.schemaId];
144 if (schId)
145 it.baseId = (0, resolve_1.resolveUrl)(it.opts.uriResolver, it.baseId, schId);
146}
147function checkAsyncSchema(it) {
148 if (it.schema.$async && !it.schemaEnv.$async)
149 throw new Error("async schema in sync schema");
150}
151function commentKeyword({ gen, schemaEnv, schema, errSchemaPath, opts }) {
152 const msg = schema.$comment;
153 if (opts.$comment === true) {
154 gen.code((0, codegen_1._) `${names_1.default.self}.logger.log(${msg})`);
155 }
156 else if (typeof opts.$comment == "function") {
157 const schemaPath = (0, codegen_1.str) `${errSchemaPath}/$comment`;
158 const rootName = gen.scopeValue("root", { ref: schemaEnv.root });
159 gen.code((0, codegen_1._) `${names_1.default.self}.opts.$comment(${msg}, ${schemaPath}, ${rootName}.schema)`);
160 }
161}
162function returnResults(it) {
163 const { gen, schemaEnv, validateName, ValidationError, opts } = it;
164 if (schemaEnv.$async) {
165 // TODO assign unevaluated
166 gen.if((0, codegen_1._) `${names_1.default.errors} === 0`, () => gen.return(names_1.default.data), () => gen.throw((0, codegen_1._) `new ${ValidationError}(${names_1.default.vErrors})`));
167 }
168 else {
169 gen.assign((0, codegen_1._) `${validateName}.errors`, names_1.default.vErrors);
170 if (opts.unevaluated)
171 assignEvaluated(it);
172 gen.return((0, codegen_1._) `${names_1.default.errors} === 0`);
173 }
174}
175function assignEvaluated({ gen, evaluated, props, items }) {
176 if (props instanceof codegen_1.Name)
177 gen.assign((0, codegen_1._) `${evaluated}.props`, props);
178 if (items instanceof codegen_1.Name)
179 gen.assign((0, codegen_1._) `${evaluated}.items`, items);
180}
181function schemaKeywords(it, types, typeErrors, errsCount) {
182 const { gen, schema, data, allErrors, opts, self } = it;
183 const { RULES } = self;
184 if (schema.$ref && (opts.ignoreKeywordsWithRef || !(0, util_1.schemaHasRulesButRef)(schema, RULES))) {
185 gen.block(() => keywordCode(it, "$ref", RULES.all.$ref.definition)); // TODO typecast
186 return;
187 }
188 if (!opts.jtd)
189 checkStrictTypes(it, types);
190 gen.block(() => {
191 for (const group of RULES.rules)
192 groupKeywords(group);
193 groupKeywords(RULES.post);
194 });
195 function groupKeywords(group) {
196 if (!(0, applicability_1.shouldUseGroup)(schema, group))
197 return;
198 if (group.type) {
199 gen.if((0, dataType_2.checkDataType)(group.type, data, opts.strictNumbers));
200 iterateKeywords(it, group);
201 if (types.length === 1 && types[0] === group.type && typeErrors) {
202 gen.else();
203 (0, dataType_2.reportTypeError)(it);
204 }
205 gen.endIf();
206 }
207 else {
208 iterateKeywords(it, group);
209 }
210 // TODO make it "ok" call?
211 if (!allErrors)
212 gen.if((0, codegen_1._) `${names_1.default.errors} === ${errsCount || 0}`);
213 }
214}
215function iterateKeywords(it, group) {
216 const { gen, schema, opts: { useDefaults }, } = it;
217 if (useDefaults)
218 (0, defaults_1.assignDefaults)(it, group.type);
219 gen.block(() => {
220 for (const rule of group.rules) {
221 if ((0, applicability_1.shouldUseRule)(schema, rule)) {
222 keywordCode(it, rule.keyword, rule.definition, group.type);
223 }
224 }
225 });
226}
227function checkStrictTypes(it, types) {
228 if (it.schemaEnv.meta || !it.opts.strictTypes)
229 return;
230 checkContextTypes(it, types);
231 if (!it.opts.allowUnionTypes)
232 checkMultipleTypes(it, types);
233 checkKeywordTypes(it, it.dataTypes);
234}
235function checkContextTypes(it, types) {
236 if (!types.length)
237 return;
238 if (!it.dataTypes.length) {
239 it.dataTypes = types;
240 return;
241 }
242 types.forEach((t) => {
243 if (!includesType(it.dataTypes, t)) {
244 strictTypesError(it, `type "${t}" not allowed by context "${it.dataTypes.join(",")}"`);
245 }
246 });
247 narrowSchemaTypes(it, types);
248}
249function checkMultipleTypes(it, ts) {
250 if (ts.length > 1 && !(ts.length === 2 && ts.includes("null"))) {
251 strictTypesError(it, "use allowUnionTypes to allow union type keyword");
252 }
253}
254function checkKeywordTypes(it, ts) {
255 const rules = it.self.RULES.all;
256 for (const keyword in rules) {
257 const rule = rules[keyword];
258 if (typeof rule == "object" && (0, applicability_1.shouldUseRule)(it.schema, rule)) {
259 const { type } = rule.definition;
260 if (type.length && !type.some((t) => hasApplicableType(ts, t))) {
261 strictTypesError(it, `missing type "${type.join(",")}" for keyword "${keyword}"`);
262 }
263 }
264 }
265}
266function hasApplicableType(schTs, kwdT) {
267 return schTs.includes(kwdT) || (kwdT === "number" && schTs.includes("integer"));
268}
269function includesType(ts, t) {
270 return ts.includes(t) || (t === "integer" && ts.includes("number"));
271}
272function narrowSchemaTypes(it, withTypes) {
273 const ts = [];
274 for (const t of it.dataTypes) {
275 if (includesType(withTypes, t))
276 ts.push(t);
277 else if (withTypes.includes("integer") && t === "number")
278 ts.push("integer");
279 }
280 it.dataTypes = ts;
281}
282function strictTypesError(it, msg) {
283 const schemaPath = it.schemaEnv.baseId + it.errSchemaPath;
284 msg += ` at "${schemaPath}" (strictTypes)`;
285 (0, util_1.checkStrictMode)(it, msg, it.opts.strictTypes);
286}
287class KeywordCxt {
288 constructor(it, def, keyword) {
289 (0, keyword_1.validateKeywordUsage)(it, def, keyword);
290 this.gen = it.gen;
291 this.allErrors = it.allErrors;
292 this.keyword = keyword;
293 this.data = it.data;
294 this.schema = it.schema[keyword];
295 this.$data = def.$data && it.opts.$data && this.schema && this.schema.$data;
296 this.schemaValue = (0, util_1.schemaRefOrVal)(it, this.schema, keyword, this.$data);
297 this.schemaType = def.schemaType;
298 this.parentSchema = it.schema;
299 this.params = {};
300 this.it = it;
301 this.def = def;
302 if (this.$data) {
303 this.schemaCode = it.gen.const("vSchema", getData(this.$data, it));
304 }
305 else {
306 this.schemaCode = this.schemaValue;
307 if (!(0, keyword_1.validSchemaType)(this.schema, def.schemaType, def.allowUndefined)) {
308 throw new Error(`${keyword} value must be ${JSON.stringify(def.schemaType)}`);
309 }
310 }
311 if ("code" in def ? def.trackErrors : def.errors !== false) {
312 this.errsCount = it.gen.const("_errs", names_1.default.errors);
313 }
314 }
315 result(condition, successAction, failAction) {
316 this.failResult((0, codegen_1.not)(condition), successAction, failAction);
317 }
318 failResult(condition, successAction, failAction) {
319 this.gen.if(condition);
320 if (failAction)
321 failAction();
322 else
323 this.error();
324 if (successAction) {
325 this.gen.else();
326 successAction();
327 if (this.allErrors)
328 this.gen.endIf();
329 }
330 else {
331 if (this.allErrors)
332 this.gen.endIf();
333 else
334 this.gen.else();
335 }
336 }
337 pass(condition, failAction) {
338 this.failResult((0, codegen_1.not)(condition), undefined, failAction);
339 }
340 fail(condition) {
341 if (condition === undefined) {
342 this.error();
343 if (!this.allErrors)
344 this.gen.if(false); // this branch will be removed by gen.optimize
345 return;
346 }
347 this.gen.if(condition);
348 this.error();
349 if (this.allErrors)
350 this.gen.endIf();
351 else
352 this.gen.else();
353 }
354 fail$data(condition) {
355 if (!this.$data)
356 return this.fail(condition);
357 const { schemaCode } = this;
358 this.fail((0, codegen_1._) `${schemaCode} !== undefined && (${(0, codegen_1.or)(this.invalid$data(), condition)})`);
359 }
360 error(append, errorParams, errorPaths) {
361 if (errorParams) {
362 this.setParams(errorParams);
363 this._error(append, errorPaths);
364 this.setParams({});
365 return;
366 }
367 this._error(append, errorPaths);
368 }
369 _error(append, errorPaths) {
370 ;
371 (append ? errors_1.reportExtraError : errors_1.reportError)(this, this.def.error, errorPaths);
372 }
373 $dataError() {
374 (0, errors_1.reportError)(this, this.def.$dataError || errors_1.keyword$DataError);
375 }
376 reset() {
377 if (this.errsCount === undefined)
378 throw new Error('add "trackErrors" to keyword definition');
379 (0, errors_1.resetErrorsCount)(this.gen, this.errsCount);
380 }
381 ok(cond) {
382 if (!this.allErrors)
383 this.gen.if(cond);
384 }
385 setParams(obj, assign) {
386 if (assign)
387 Object.assign(this.params, obj);
388 else
389 this.params = obj;
390 }
391 block$data(valid, codeBlock, $dataValid = codegen_1.nil) {
392 this.gen.block(() => {
393 this.check$data(valid, $dataValid);
394 codeBlock();
395 });
396 }
397 check$data(valid = codegen_1.nil, $dataValid = codegen_1.nil) {
398 if (!this.$data)
399 return;
400 const { gen, schemaCode, schemaType, def } = this;
401 gen.if((0, codegen_1.or)((0, codegen_1._) `${schemaCode} === undefined`, $dataValid));
402 if (valid !== codegen_1.nil)
403 gen.assign(valid, true);
404 if (schemaType.length || def.validateSchema) {
405 gen.elseIf(this.invalid$data());
406 this.$dataError();
407 if (valid !== codegen_1.nil)
408 gen.assign(valid, false);
409 }
410 gen.else();
411 }
412 invalid$data() {
413 const { gen, schemaCode, schemaType, def, it } = this;
414 return (0, codegen_1.or)(wrong$DataType(), invalid$DataSchema());
415 function wrong$DataType() {
416 if (schemaType.length) {
417 /* istanbul ignore if */
418 if (!(schemaCode instanceof codegen_1.Name))
419 throw new Error("ajv implementation error");
420 const st = Array.isArray(schemaType) ? schemaType : [schemaType];
421 return (0, codegen_1._) `${(0, dataType_2.checkDataTypes)(st, schemaCode, it.opts.strictNumbers, dataType_2.DataType.Wrong)}`;
422 }
423 return codegen_1.nil;
424 }
425 function invalid$DataSchema() {
426 if (def.validateSchema) {
427 const validateSchemaRef = gen.scopeValue("validate$data", { ref: def.validateSchema }); // TODO value.code for standalone
428 return (0, codegen_1._) `!${validateSchemaRef}(${schemaCode})`;
429 }
430 return codegen_1.nil;
431 }
432 }
433 subschema(appl, valid) {
434 const subschema = (0, subschema_1.getSubschema)(this.it, appl);
435 (0, subschema_1.extendSubschemaData)(subschema, this.it, appl);
436 (0, subschema_1.extendSubschemaMode)(subschema, appl);
437 const nextContext = { ...this.it, ...subschema, items: undefined, props: undefined };
438 subschemaCode(nextContext, valid);
439 return nextContext;
440 }
441 mergeEvaluated(schemaCxt, toName) {
442 const { it, gen } = this;
443 if (!it.opts.unevaluated)
444 return;
445 if (it.props !== true && schemaCxt.props !== undefined) {
446 it.props = util_1.mergeEvaluated.props(gen, schemaCxt.props, it.props, toName);
447 }
448 if (it.items !== true && schemaCxt.items !== undefined) {
449 it.items = util_1.mergeEvaluated.items(gen, schemaCxt.items, it.items, toName);
450 }
451 }
452 mergeValidEvaluated(schemaCxt, valid) {
453 const { it, gen } = this;
454 if (it.opts.unevaluated && (it.props !== true || it.items !== true)) {
455 gen.if(valid, () => this.mergeEvaluated(schemaCxt, codegen_1.Name));
456 return true;
457 }
458 }
459}
460exports.KeywordCxt = KeywordCxt;
461function keywordCode(it, keyword, def, ruleType) {
462 const cxt = new KeywordCxt(it, def, keyword);
463 if ("code" in def) {
464 def.code(cxt, ruleType);
465 }
466 else if (cxt.$data && def.validate) {
467 (0, keyword_1.funcKeywordCode)(cxt, def);
468 }
469 else if ("macro" in def) {
470 (0, keyword_1.macroKeywordCode)(cxt, def);
471 }
472 else if (def.compile || def.validate) {
473 (0, keyword_1.funcKeywordCode)(cxt, def);
474 }
475}
476const JSON_POINTER = /^\/(?:[^~]|~0|~1)*$/;
477const RELATIVE_JSON_POINTER = /^([0-9]+)(#|\/(?:[^~]|~0|~1)*)?$/;
478function getData($data, { dataLevel, dataNames, dataPathArr }) {
479 let jsonPointer;
480 let data;
481 if ($data === "")
482 return names_1.default.rootData;
483 if ($data[0] === "/") {
484 if (!JSON_POINTER.test($data))
485 throw new Error(`Invalid JSON-pointer: ${$data}`);
486 jsonPointer = $data;
487 data = names_1.default.rootData;
488 }
489 else {
490 const matches = RELATIVE_JSON_POINTER.exec($data);
491 if (!matches)
492 throw new Error(`Invalid JSON-pointer: ${$data}`);
493 const up = +matches[1];
494 jsonPointer = matches[2];
495 if (jsonPointer === "#") {
496 if (up >= dataLevel)
497 throw new Error(errorMsg("property/index", up));
498 return dataPathArr[dataLevel - up];
499 }
500 if (up > dataLevel)
501 throw new Error(errorMsg("data", up));
502 data = dataNames[dataLevel - up];
503 if (!jsonPointer)
504 return data;
505 }
506 let expr = data;
507 const segments = jsonPointer.split("/");
508 for (const segment of segments) {
509 if (segment) {
510 data = (0, codegen_1._) `${data}${(0, codegen_1.getProperty)((0, util_1.unescapeJsonPointer)(segment))}`;
511 expr = (0, codegen_1._) `${expr} && ${data}`;
512 }
513 }
514 return expr;
515 function errorMsg(pointerType, up) {
516 return `Cannot access ${pointerType} ${up} levels up, current level is ${dataLevel}`;
517 }
518}
519exports.getData = getData;
520//# sourceMappingURL=index.js.map
Note: See TracBrowser for help on using the repository browser.