2023-10-03 11:14:36 +08:00
|
|
|
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
|
exports.getData = void 0;
|
|
|
|
const dataType_1 = require("./validate/dataType");
|
|
|
|
const util_1 = require("./util");
|
|
|
|
const errors_1 = require("./errors");
|
|
|
|
const codegen_1 = require("./codegen");
|
|
|
|
const names_1 = require("./names");
|
|
|
|
const subschema_1 = require("./subschema");
|
|
|
|
class KeywordCxt {
|
|
|
|
constructor(it, def, keyword) {
|
|
|
|
validateKeywordUsage(it, def, keyword);
|
|
|
|
this.gen = it.gen;
|
|
|
|
this.allErrors = it.allErrors;
|
|
|
|
this.keyword = keyword;
|
|
|
|
this.data = it.data;
|
|
|
|
this.schema = it.schema[keyword];
|
|
|
|
this.$data = def.$data && it.opts.$data && this.schema && this.schema.$data;
|
|
|
|
this.schemaValue = util_1.schemaRefOrVal(it, this.schema, keyword, this.$data);
|
|
|
|
this.schemaType = def.schemaType;
|
|
|
|
this.parentSchema = it.schema;
|
|
|
|
this.params = {};
|
|
|
|
this.it = it;
|
|
|
|
this.def = def;
|
|
|
|
if (this.$data) {
|
|
|
|
this.schemaCode = it.gen.const("vSchema", getData(this.$data, it));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this.schemaCode = this.schemaValue;
|
|
|
|
if (!validSchemaType(this.schema, def.schemaType, def.allowUndefined)) {
|
|
|
|
throw new Error(`${keyword} value must be ${JSON.stringify(def.schemaType)}`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ("code" in def ? def.trackErrors : def.errors !== false) {
|
|
|
|
this.errsCount = it.gen.const("_errs", names_1.default.errors);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
result(condition, successAction, failAction) {
|
|
|
|
this.gen.if(codegen_1.not(condition));
|
|
|
|
if (failAction)
|
|
|
|
failAction();
|
|
|
|
else
|
|
|
|
this.error();
|
|
|
|
if (successAction) {
|
|
|
|
this.gen.else();
|
|
|
|
successAction();
|
|
|
|
if (this.allErrors)
|
|
|
|
this.gen.endIf();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (this.allErrors)
|
|
|
|
this.gen.endIf();
|
|
|
|
else
|
|
|
|
this.gen.else();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pass(condition, failAction) {
|
|
|
|
this.result(condition, undefined, failAction);
|
|
|
|
}
|
|
|
|
fail(condition) {
|
|
|
|
if (condition === undefined) {
|
|
|
|
this.error();
|
|
|
|
if (!this.allErrors)
|
|
|
|
this.gen.if(false); // this branch will be removed by gen.optimize
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.gen.if(condition);
|
|
|
|
this.error();
|
|
|
|
if (this.allErrors)
|
|
|
|
this.gen.endIf();
|
|
|
|
else
|
|
|
|
this.gen.else();
|
|
|
|
}
|
|
|
|
fail$data(condition) {
|
|
|
|
if (!this.$data)
|
|
|
|
return this.fail(condition);
|
|
|
|
const { schemaCode } = this;
|
|
|
|
this.fail(codegen_1._ `${schemaCode} !== undefined && (${codegen_1.or(this.invalid$data(), condition)})`);
|
|
|
|
}
|
|
|
|
error(append) {
|
|
|
|
;
|
|
|
|
(append ? errors_1.reportExtraError : errors_1.reportError)(this, this.def.error);
|
|
|
|
}
|
|
|
|
$dataError() {
|
|
|
|
errors_1.reportError(this, this.def.$dataError || errors_1.keyword$DataError);
|
|
|
|
}
|
|
|
|
reset() {
|
|
|
|
if (this.errsCount === undefined)
|
|
|
|
throw new Error('add "trackErrors" to keyword definition');
|
|
|
|
errors_1.resetErrorsCount(this.gen, this.errsCount);
|
|
|
|
}
|
|
|
|
ok(cond) {
|
|
|
|
if (!this.allErrors)
|
|
|
|
this.gen.if(cond);
|
|
|
|
}
|
|
|
|
setParams(obj, assign) {
|
|
|
|
if (assign)
|
|
|
|
Object.assign(this.params, obj);
|
|
|
|
else
|
|
|
|
this.params = obj;
|
|
|
|
}
|
|
|
|
block$data(valid, codeBlock, $dataValid = codegen_1.nil) {
|
|
|
|
this.gen.block(() => {
|
|
|
|
this.check$data(valid, $dataValid);
|
|
|
|
codeBlock();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
check$data(valid = codegen_1.nil, $dataValid = codegen_1.nil) {
|
|
|
|
if (!this.$data)
|
|
|
|
return;
|
|
|
|
const { gen, schemaCode, schemaType, def } = this;
|
|
|
|
gen.if(codegen_1.or(codegen_1._ `${schemaCode} === undefined`, $dataValid));
|
|
|
|
if (valid !== codegen_1.nil)
|
|
|
|
gen.assign(valid, true);
|
|
|
|
if (schemaType.length || def.validateSchema) {
|
|
|
|
gen.elseIf(this.invalid$data());
|
|
|
|
this.$dataError();
|
|
|
|
if (valid !== codegen_1.nil)
|
|
|
|
gen.assign(valid, false);
|
|
|
|
}
|
|
|
|
gen.else();
|
|
|
|
}
|
|
|
|
invalid$data() {
|
|
|
|
const { gen, schemaCode, schemaType, def, it } = this;
|
|
|
|
return codegen_1.or(wrong$DataType(), invalid$DataSchema());
|
|
|
|
function wrong$DataType() {
|
|
|
|
if (schemaType.length) {
|
|
|
|
/* istanbul ignore if */
|
|
|
|
if (!(schemaCode instanceof codegen_1.Name))
|
|
|
|
throw new Error("ajv implementation error");
|
|
|
|
const st = Array.isArray(schemaType) ? schemaType : [schemaType];
|
|
|
|
return codegen_1._ `${dataType_1.checkDataTypes(st, schemaCode, it.opts.strict, dataType_1.DataType.Wrong)}`;
|
|
|
|
}
|
|
|
|
return codegen_1.nil;
|
|
|
|
}
|
|
|
|
function invalid$DataSchema() {
|
|
|
|
if (def.validateSchema) {
|
|
|
|
const validateSchemaRef = gen.scopeValue("validate$data", { ref: def.validateSchema }); // TODO value.code for standalone
|
|
|
|
return codegen_1._ `!${validateSchemaRef}(${schemaCode})`;
|
|
|
|
}
|
|
|
|
return codegen_1.nil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
subschema(appl, valid) {
|
|
|
|
return subschema_1.applySubschema(this.it, appl, valid);
|
|
|
|
}
|
|
|
|
mergeEvaluated(schemaCxt, toName) {
|
|
|
|
const { it, gen } = this;
|
|
|
|
if (!it.opts.unevaluated)
|
|
|
|
return;
|
|
|
|
if (it.props !== true && schemaCxt.props !== undefined) {
|
|
|
|
it.props = util_1.mergeEvaluated.props(gen, schemaCxt.props, it.props, toName);
|
|
|
|
}
|
|
|
|
if (it.items !== true && schemaCxt.items !== undefined) {
|
|
|
|
it.items = util_1.mergeEvaluated.items(gen, schemaCxt.items, it.items, toName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mergeValidEvaluated(schemaCxt, valid) {
|
|
|
|
const { it, gen } = this;
|
|
|
|
if (it.opts.unevaluated && (it.props !== true || it.items !== true)) {
|
|
|
|
gen.if(valid, () => this.mergeEvaluated(schemaCxt, codegen_1.Name));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
exports.default = KeywordCxt;
|
|
|
|
function validSchemaType(schema, schemaType, allowUndefined = false) {
|
|
|
|
// TODO add tests
|
|
|
|
return (!schemaType.length ||
|
|
|
|
schemaType.some((st) => st === "array"
|
|
|
|
? Array.isArray(schema)
|
|
|
|
: st === "object"
|
|
|
|
? schema && typeof schema == "object" && !Array.isArray(schema)
|
|
|
|
: typeof schema == st || (allowUndefined && typeof schema == "undefined")));
|
|
|
|
}
|
|
|
|
function validateKeywordUsage({ schema, opts, self }, def, keyword) {
|
|
|
|
/* istanbul ignore if */
|
|
|
|
if (Array.isArray(def.keyword) ? !def.keyword.includes(keyword) : def.keyword !== keyword) {
|
|
|
|
throw new Error("ajv implementation error");
|
|
|
|
}
|
|
|
|
const deps = def.dependencies;
|
|
|
|
if (deps === null || deps === void 0 ? void 0 : deps.some((kwd) => !Object.prototype.hasOwnProperty.call(schema, kwd))) {
|
|
|
|
throw new Error(`parent schema must have dependencies of ${keyword}: ${deps.join(",")}`);
|
|
|
|
}
|
|
|
|
if (def.validateSchema) {
|
|
|
|
const valid = def.validateSchema(schema[keyword]);
|
|
|
|
if (!valid) {
|
|
|
|
const msg = "keyword value is invalid: " + self.errorsText(def.validateSchema.errors);
|
|
|
|
if (opts.validateSchema === "log")
|
|
|
|
self.logger.error(msg);
|
|
|
|
else
|
|
|
|
throw new Error(msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const JSON_POINTER = /^\/(?:[^~]|~0|~1)*$/;
|
|
|
|
const RELATIVE_JSON_POINTER = /^([0-9]+)(#|\/(?:[^~]|~0|~1)*)?$/;
|
|
|
|
function getData($data, { dataLevel, dataNames, dataPathArr }) {
|
|
|
|
let jsonPointer;
|
|
|
|
let data;
|
|
|
|
if ($data === "")
|
|
|
|
return names_1.default.rootData;
|
|
|
|
if ($data[0] === "/") {
|
|
|
|
if (!JSON_POINTER.test($data))
|
|
|
|
throw new Error(`Invalid JSON-pointer: ${$data}`);
|
|
|
|
jsonPointer = $data;
|
|
|
|
data = names_1.default.rootData;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
const matches = RELATIVE_JSON_POINTER.exec($data);
|
|
|
|
if (!matches)
|
|
|
|
throw new Error(`Invalid JSON-pointer: ${$data}`);
|
|
|
|
const up = +matches[1];
|
|
|
|
jsonPointer = matches[2];
|
|
|
|
if (jsonPointer === "#") {
|
|
|
|
if (up >= dataLevel)
|
|
|
|
throw new Error(errorMsg("property/index", up));
|
|
|
|
return dataPathArr[dataLevel - up];
|
|
|
|
}
|
|
|
|
if (up > dataLevel)
|
|
|
|
throw new Error(errorMsg("data", up));
|
|
|
|
data = dataNames[dataLevel - up];
|
|
|
|
if (!jsonPointer)
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
let expr = data;
|
|
|
|
const segments = jsonPointer.split("/");
|
|
|
|
for (const segment of segments) {
|
|
|
|
if (segment) {
|
|
|
|
data = codegen_1._ `${data}${codegen_1.getProperty(util_1.unescapeJsonPointer(segment))}`;
|
|
|
|
expr = codegen_1._ `${expr} && ${data}`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return expr;
|
|
|
|
function errorMsg(pointerType, up) {
|
|
|
|
return `Cannot access ${pointerType} ${up} levels up, current level is ${dataLevel}`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
exports.getData = getData;
|
2023-09-25 15:58:56 +08:00
|
|
|
//# sourceMappingURL=context.js.map
|