2023-10-03 11:14:36 +08:00
|
|
|
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
|
exports.checkStrictMode = exports.schemaCxtHasRules = exports.subschemaCode = exports.validateFunctionCode = void 0;
|
|
|
|
const boolSchema_1 = require("./boolSchema");
|
|
|
|
const dataType_1 = require("./dataType");
|
|
|
|
const iterate_1 = require("./iterate");
|
|
|
|
const codegen_1 = require("../codegen");
|
|
|
|
const names_1 = require("../names");
|
|
|
|
const resolve_1 = require("../resolve");
|
|
|
|
const util_1 = require("../util");
|
|
|
|
// schema compilation - generates validation function, subschemaCode (below) is used for subschemas
|
|
|
|
function validateFunctionCode(it) {
|
|
|
|
if (isSchemaObj(it)) {
|
|
|
|
checkKeywords(it);
|
|
|
|
if (schemaCxtHasRules(it)) {
|
|
|
|
topSchemaObjCode(it);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
validateFunction(it, () => boolSchema_1.topBoolOrEmptySchema(it));
|
|
|
|
}
|
|
|
|
exports.validateFunctionCode = validateFunctionCode;
|
|
|
|
function validateFunction({ gen, validateName, schema, schemaEnv, opts }, body) {
|
|
|
|
if (opts.code.es5) {
|
|
|
|
gen.func(validateName, codegen_1._ `${names_1.default.data}, ${names_1.default.valCxt}`, schemaEnv.$async, () => {
|
|
|
|
gen.code(codegen_1._ `"use strict"; ${funcSourceUrl(schema, opts)}`);
|
|
|
|
destructureValCxtES5(gen, opts);
|
|
|
|
gen.code(body);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
gen.func(validateName, codegen_1._ `${names_1.default.data}, ${destructureValCxt(opts)}`, schemaEnv.$async, () => gen.code(funcSourceUrl(schema, opts)).code(body));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function destructureValCxt(opts) {
|
|
|
|
return codegen_1._ `{${names_1.default.dataPath}="", ${names_1.default.parentData}, ${names_1.default.parentDataProperty}, ${names_1.default.rootData}=${names_1.default.data}${opts.dynamicRef ? codegen_1._ `, ${names_1.default.dynamicAnchors}={}` : codegen_1.nil}}={}`;
|
|
|
|
}
|
|
|
|
function destructureValCxtES5(gen, opts) {
|
|
|
|
gen.if(names_1.default.valCxt, () => {
|
|
|
|
gen.var(names_1.default.dataPath, codegen_1._ `${names_1.default.valCxt}.${names_1.default.dataPath}`);
|
|
|
|
gen.var(names_1.default.parentData, codegen_1._ `${names_1.default.valCxt}.${names_1.default.parentData}`);
|
|
|
|
gen.var(names_1.default.parentDataProperty, codegen_1._ `${names_1.default.valCxt}.${names_1.default.parentDataProperty}`);
|
|
|
|
gen.var(names_1.default.rootData, codegen_1._ `${names_1.default.valCxt}.${names_1.default.rootData}`);
|
|
|
|
if (opts.dynamicRef)
|
|
|
|
gen.var(names_1.default.dynamicAnchors, codegen_1._ `${names_1.default.valCxt}.${names_1.default.dynamicAnchors}`);
|
|
|
|
}, () => {
|
|
|
|
gen.var(names_1.default.dataPath, codegen_1._ `""`);
|
|
|
|
gen.var(names_1.default.parentData, codegen_1._ `undefined`);
|
|
|
|
gen.var(names_1.default.parentDataProperty, codegen_1._ `undefined`);
|
|
|
|
gen.var(names_1.default.rootData, names_1.default.data);
|
|
|
|
if (opts.dynamicRef)
|
|
|
|
gen.var(names_1.default.dynamicAnchors, codegen_1._ `{}`);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
function topSchemaObjCode(it) {
|
|
|
|
const { schema, opts, gen } = it;
|
|
|
|
validateFunction(it, () => {
|
|
|
|
if (opts.$comment && schema.$comment)
|
|
|
|
commentKeyword(it);
|
|
|
|
checkNoDefault(it);
|
|
|
|
gen.let(names_1.default.vErrors, null);
|
|
|
|
gen.let(names_1.default.errors, 0);
|
|
|
|
if (opts.unevaluated)
|
|
|
|
resetEvaluated(it);
|
|
|
|
typeAndKeywords(it);
|
|
|
|
returnResults(it);
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
function resetEvaluated(it) {
|
|
|
|
// TODO maybe some hook to execute it in the end to check whether props/items are Name, as in assignEvaluated
|
|
|
|
const { gen, validateName } = it;
|
|
|
|
it.evaluated = gen.const("evaluated", codegen_1._ `${validateName}.evaluated`);
|
|
|
|
gen.if(codegen_1._ `${it.evaluated}.dynamicProps`, () => gen.assign(codegen_1._ `${it.evaluated}.props`, codegen_1._ `undefined`));
|
|
|
|
gen.if(codegen_1._ `${it.evaluated}.dynamicItems`, () => gen.assign(codegen_1._ `${it.evaluated}.items`, codegen_1._ `undefined`));
|
|
|
|
}
|
|
|
|
function funcSourceUrl(schema, opts) {
|
|
|
|
return typeof schema == "object" && schema.$id && (opts.code.source || opts.code.process)
|
|
|
|
? codegen_1._ `/*# sourceURL=${schema.$id} */`
|
|
|
|
: codegen_1.nil;
|
|
|
|
}
|
|
|
|
// schema compilation - this function is used recursively to generate code for sub-schemas
|
|
|
|
function subschemaCode(it, valid) {
|
|
|
|
if (isSchemaObj(it)) {
|
|
|
|
checkKeywords(it);
|
|
|
|
if (schemaCxtHasRules(it)) {
|
|
|
|
subSchemaObjCode(it, valid);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
boolSchema_1.boolOrEmptySchema(it, valid);
|
|
|
|
}
|
|
|
|
exports.subschemaCode = subschemaCode;
|
|
|
|
function schemaCxtHasRules({ schema, self }) {
|
|
|
|
if (typeof schema == "boolean")
|
|
|
|
return !schema;
|
|
|
|
for (const key in schema)
|
|
|
|
if (self.RULES.all[key])
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
exports.schemaCxtHasRules = schemaCxtHasRules;
|
|
|
|
function isSchemaObj(it) {
|
|
|
|
return typeof it.schema != "boolean";
|
|
|
|
}
|
|
|
|
function subSchemaObjCode(it, valid) {
|
|
|
|
const { schema, gen, opts } = it;
|
|
|
|
if (opts.$comment && schema.$comment)
|
|
|
|
commentKeyword(it);
|
|
|
|
updateContext(it);
|
|
|
|
checkAsync(it);
|
|
|
|
const errsCount = gen.const("_errs", names_1.default.errors);
|
|
|
|
typeAndKeywords(it, errsCount);
|
|
|
|
// TODO var
|
|
|
|
gen.var(valid, codegen_1._ `${errsCount} === ${names_1.default.errors}`);
|
|
|
|
}
|
|
|
|
function checkKeywords(it) {
|
|
|
|
util_1.checkUnknownRules(it);
|
|
|
|
checkRefsAndKeywords(it);
|
|
|
|
}
|
|
|
|
function typeAndKeywords(it, errsCount) {
|
|
|
|
if (it.opts.jtd)
|
|
|
|
return iterate_1.schemaKeywords(it, [], false, errsCount);
|
|
|
|
const types = dataType_1.getSchemaTypes(it.schema);
|
|
|
|
const checkedTypes = dataType_1.coerceAndCheckDataType(it, types);
|
|
|
|
iterate_1.schemaKeywords(it, types, !checkedTypes, errsCount);
|
|
|
|
}
|
|
|
|
function checkRefsAndKeywords(it) {
|
|
|
|
const { schema, errSchemaPath, opts, self } = it;
|
|
|
|
if (schema.$ref && opts.ignoreKeywordsWithRef && util_1.schemaHasRulesButRef(schema, self.RULES)) {
|
|
|
|
self.logger.warn(`$ref: keywords ignored in schema at path "${errSchemaPath}"`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function checkNoDefault(it) {
|
|
|
|
const { schema, opts } = it;
|
|
|
|
if (schema.default !== undefined && opts.useDefaults && opts.strict) {
|
|
|
|
checkStrictMode(it, "default is ignored in the schema root");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function updateContext(it) {
|
|
|
|
if (it.schema.$id)
|
|
|
|
it.baseId = resolve_1.resolveUrl(it.baseId, it.schema.$id);
|
|
|
|
}
|
|
|
|
function checkAsync(it) {
|
|
|
|
if (it.schema.$async && !it.schemaEnv.$async)
|
|
|
|
throw new Error("async schema in sync schema");
|
|
|
|
}
|
|
|
|
function commentKeyword({ gen, schemaEnv, schema, errSchemaPath, opts }) {
|
|
|
|
const msg = schema.$comment;
|
|
|
|
if (opts.$comment === true) {
|
|
|
|
gen.code(codegen_1._ `${names_1.default.self}.logger.log(${msg})`);
|
|
|
|
}
|
|
|
|
else if (typeof opts.$comment == "function") {
|
|
|
|
const schemaPath = codegen_1.str `${errSchemaPath}/$comment`;
|
|
|
|
const rootName = gen.scopeValue("root", { ref: schemaEnv.root });
|
|
|
|
gen.code(codegen_1._ `${names_1.default.self}.opts.$comment(${msg}, ${schemaPath}, ${rootName}.schema)`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function returnResults(it) {
|
|
|
|
const { gen, schemaEnv, validateName, ValidationError, opts } = it;
|
|
|
|
if (schemaEnv.$async) {
|
|
|
|
// TODO assign unevaluated
|
|
|
|
gen.if(codegen_1._ `${names_1.default.errors} === 0`, () => gen.return(names_1.default.data), () => gen.throw(codegen_1._ `new ${ValidationError}(${names_1.default.vErrors})`));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
gen.assign(codegen_1._ `${validateName}.errors`, names_1.default.vErrors);
|
|
|
|
if (opts.unevaluated)
|
|
|
|
assignEvaluated(it);
|
|
|
|
gen.return(codegen_1._ `${names_1.default.errors} === 0`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function assignEvaluated({ gen, evaluated, props, items }) {
|
|
|
|
if (props instanceof codegen_1.Name)
|
|
|
|
gen.assign(codegen_1._ `${evaluated}.props`, props);
|
|
|
|
if (items instanceof codegen_1.Name)
|
|
|
|
gen.assign(codegen_1._ `${evaluated}.items`, items);
|
|
|
|
}
|
|
|
|
function checkStrictMode(it, msg, mode = it.opts.strict) {
|
|
|
|
if (!mode)
|
|
|
|
return;
|
|
|
|
msg = `strict mode: ${msg}`;
|
|
|
|
if (mode === true)
|
|
|
|
throw new Error(msg);
|
|
|
|
it.self.logger.warn(msg);
|
|
|
|
}
|
|
|
|
exports.checkStrictMode = checkStrictMode;
|
2023-09-25 15:58:56 +08:00
|
|
|
//# sourceMappingURL=index.js.map
|