Buckets:
| ; | |
| Object.defineProperty(exports, "__esModule", { value: true }); | |
| exports.getData = exports.KeywordCxt = exports.validateFunctionCode = void 0; | |
| const boolSchema_1 = require("./boolSchema"); | |
| const dataType_1 = require("./dataType"); | |
| const applicability_1 = require("./applicability"); | |
| const dataType_2 = require("./dataType"); | |
| const defaults_1 = require("./defaults"); | |
| const keyword_1 = require("./keyword"); | |
| const subschema_1 = require("./subschema"); | |
| const codegen_1 = require("../codegen"); | |
| const names_1 = require("../names"); | |
| const resolve_1 = require("../resolve"); | |
| const util_1 = require("../util"); | |
| const errors_1 = require("../errors"); | |
| // 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, () => (0, boolSchema_1.topBoolOrEmptySchema)(it)); | |
| } | |
| exports.validateFunctionCode = validateFunctionCode; | |
| function validateFunction({ gen, validateName, schema, schemaEnv, opts }, body) { | |
| if (opts.code.es5) { | |
| gen.func(validateName, (0, codegen_1._) `${names_1.default.data}, ${names_1.default.valCxt}`, schemaEnv.$async, () => { | |
| gen.code((0, codegen_1._) `"use strict"; ${funcSourceUrl(schema, opts)}`); | |
| destructureValCxtES5(gen, opts); | |
| gen.code(body); | |
| }); | |
| } | |
| else { | |
| gen.func(validateName, (0, codegen_1._) `${names_1.default.data}, ${destructureValCxt(opts)}`, schemaEnv.$async, () => gen.code(funcSourceUrl(schema, opts)).code(body)); | |
| } | |
| } | |
| function destructureValCxt(opts) { | |
| 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}}={}`; | |
| } | |
| function destructureValCxtES5(gen, opts) { | |
| gen.if(names_1.default.valCxt, () => { | |
| gen.var(names_1.default.instancePath, (0, codegen_1._) `${names_1.default.valCxt}.${names_1.default.instancePath}`); | |
| gen.var(names_1.default.parentData, (0, codegen_1._) `${names_1.default.valCxt}.${names_1.default.parentData}`); | |
| gen.var(names_1.default.parentDataProperty, (0, codegen_1._) `${names_1.default.valCxt}.${names_1.default.parentDataProperty}`); | |
| gen.var(names_1.default.rootData, (0, codegen_1._) `${names_1.default.valCxt}.${names_1.default.rootData}`); | |
| if (opts.dynamicRef) | |
| gen.var(names_1.default.dynamicAnchors, (0, codegen_1._) `${names_1.default.valCxt}.${names_1.default.dynamicAnchors}`); | |
| }, () => { | |
| gen.var(names_1.default.instancePath, (0, codegen_1._) `""`); | |
| gen.var(names_1.default.parentData, (0, codegen_1._) `undefined`); | |
| gen.var(names_1.default.parentDataProperty, (0, codegen_1._) `undefined`); | |
| gen.var(names_1.default.rootData, names_1.default.data); | |
| if (opts.dynamicRef) | |
| gen.var(names_1.default.dynamicAnchors, (0, 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", (0, codegen_1._) `${validateName}.evaluated`); | |
| gen.if((0, codegen_1._) `${it.evaluated}.dynamicProps`, () => gen.assign((0, codegen_1._) `${it.evaluated}.props`, (0, codegen_1._) `undefined`)); | |
| gen.if((0, codegen_1._) `${it.evaluated}.dynamicItems`, () => gen.assign((0, codegen_1._) `${it.evaluated}.items`, (0, codegen_1._) `undefined`)); | |
| } | |
| function funcSourceUrl(schema, opts) { | |
| const schId = typeof schema == "object" && schema[opts.schemaId]; | |
| return schId && (opts.code.source || opts.code.process) ? (0, codegen_1._) `/*# sourceURL=${schId} */` : 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; | |
| } | |
| } | |
| (0, boolSchema_1.boolOrEmptySchema)(it, valid); | |
| } | |
| function schemaCxtHasRules({ schema, self }) { | |
| if (typeof schema == "boolean") | |
| return !schema; | |
| for (const key in schema) | |
| if (self.RULES.all[key]) | |
| return true; | |
| return false; | |
| } | |
| 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); | |
| checkAsyncSchema(it); | |
| const errsCount = gen.const("_errs", names_1.default.errors); | |
| typeAndKeywords(it, errsCount); | |
| // TODO var | |
| gen.var(valid, (0, codegen_1._) `${errsCount} === ${names_1.default.errors}`); | |
| } | |
| function checkKeywords(it) { | |
| (0, util_1.checkUnknownRules)(it); | |
| checkRefsAndKeywords(it); | |
| } | |
| function typeAndKeywords(it, errsCount) { | |
| if (it.opts.jtd) | |
| return schemaKeywords(it, [], false, errsCount); | |
| const types = (0, dataType_1.getSchemaTypes)(it.schema); | |
| const checkedTypes = (0, dataType_1.coerceAndCheckDataType)(it, types); | |
| schemaKeywords(it, types, !checkedTypes, errsCount); | |
| } | |
| function checkRefsAndKeywords(it) { | |
| const { schema, errSchemaPath, opts, self } = it; | |
| if (schema.$ref && opts.ignoreKeywordsWithRef && (0, 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.strictSchema) { | |
| (0, util_1.checkStrictMode)(it, "default is ignored in the schema root"); | |
| } | |
| } | |
| function updateContext(it) { | |
| const schId = it.schema[it.opts.schemaId]; | |
| if (schId) | |
| it.baseId = (0, resolve_1.resolveUrl)(it.opts.uriResolver, it.baseId, schId); | |
| } | |
| function checkAsyncSchema(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((0, codegen_1._) `${names_1.default.self}.logger.log(${msg})`); | |
| } | |
| else if (typeof opts.$comment == "function") { | |
| const schemaPath = (0, codegen_1.str) `${errSchemaPath}/$comment`; | |
| const rootName = gen.scopeValue("root", { ref: schemaEnv.root }); | |
| gen.code((0, 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((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})`)); | |
| } | |
| else { | |
| gen.assign((0, codegen_1._) `${validateName}.errors`, names_1.default.vErrors); | |
| if (opts.unevaluated) | |
| assignEvaluated(it); | |
| gen.return((0, codegen_1._) `${names_1.default.errors} === 0`); | |
| } | |
| } | |
| function assignEvaluated({ gen, evaluated, props, items }) { | |
| if (props instanceof codegen_1.Name) | |
| gen.assign((0, codegen_1._) `${evaluated}.props`, props); | |
| if (items instanceof codegen_1.Name) | |
| gen.assign((0, codegen_1._) `${evaluated}.items`, items); | |
| } | |
| function schemaKeywords(it, types, typeErrors, errsCount) { | |
| const { gen, schema, data, allErrors, opts, self } = it; | |
| const { RULES } = self; | |
| if (schema.$ref && (opts.ignoreKeywordsWithRef || !(0, util_1.schemaHasRulesButRef)(schema, RULES))) { | |
| gen.block(() => keywordCode(it, "$ref", RULES.all.$ref.definition)); // TODO typecast | |
| return; | |
| } | |
| if (!opts.jtd) | |
| checkStrictTypes(it, types); | |
| gen.block(() => { | |
| for (const group of RULES.rules) | |
| groupKeywords(group); | |
| groupKeywords(RULES.post); | |
| }); | |
| function groupKeywords(group) { | |
| if (!(0, applicability_1.shouldUseGroup)(schema, group)) | |
| return; | |
| if (group.type) { | |
| gen.if((0, dataType_2.checkDataType)(group.type, data, opts.strictNumbers)); | |
| iterateKeywords(it, group); | |
| if (types.length === 1 && types[0] === group.type && typeErrors) { | |
| gen.else(); | |
| (0, dataType_2.reportTypeError)(it); | |
| } | |
| gen.endIf(); | |
| } | |
| else { | |
| iterateKeywords(it, group); | |
| } | |
| // TODO make it "ok" call? | |
| if (!allErrors) | |
| gen.if((0, codegen_1._) `${names_1.default.errors} === ${errsCount || 0}`); | |
| } | |
| } | |
| function iterateKeywords(it, group) { | |
| const { gen, schema, opts: { useDefaults }, } = it; | |
| if (useDefaults) | |
| (0, defaults_1.assignDefaults)(it, group.type); | |
| gen.block(() => { | |
| for (const rule of group.rules) { | |
| if ((0, applicability_1.shouldUseRule)(schema, rule)) { | |
| keywordCode(it, rule.keyword, rule.definition, group.type); | |
| } | |
| } | |
| }); | |
| } | |
| function checkStrictTypes(it, types) { | |
| if (it.schemaEnv.meta || !it.opts.strictTypes) | |
| return; | |
| checkContextTypes(it, types); | |
| if (!it.opts.allowUnionTypes) | |
| checkMultipleTypes(it, types); | |
| checkKeywordTypes(it, it.dataTypes); | |
| } | |
| function checkContextTypes(it, types) { | |
| if (!types.length) | |
| return; | |
| if (!it.dataTypes.length) { | |
| it.dataTypes = types; | |
| return; | |
| } | |
| types.forEach((t) => { | |
| if (!includesType(it.dataTypes, t)) { | |
| strictTypesError(it, `type "${t}" not allowed by context "${it.dataTypes.join(",")}"`); | |
| } | |
| }); | |
| narrowSchemaTypes(it, types); | |
| } | |
| function checkMultipleTypes(it, ts) { | |
| if (ts.length > 1 && !(ts.length === 2 && ts.includes("null"))) { | |
| strictTypesError(it, "use allowUnionTypes to allow union type keyword"); | |
| } | |
| } | |
| function checkKeywordTypes(it, ts) { | |
| const rules = it.self.RULES.all; | |
| for (const keyword in rules) { | |
| const rule = rules[keyword]; | |
| if (typeof rule == "object" && (0, applicability_1.shouldUseRule)(it.schema, rule)) { | |
| const { type } = rule.definition; | |
| if (type.length && !type.some((t) => hasApplicableType(ts, t))) { | |
| strictTypesError(it, `missing type "${type.join(",")}" for keyword "${keyword}"`); | |
| } | |
| } | |
| } | |
| } | |
| function hasApplicableType(schTs, kwdT) { | |
| return schTs.includes(kwdT) || (kwdT === "number" && schTs.includes("integer")); | |
| } | |
| function includesType(ts, t) { | |
| return ts.includes(t) || (t === "integer" && ts.includes("number")); | |
| } | |
| function narrowSchemaTypes(it, withTypes) { | |
| const ts = []; | |
| for (const t of it.dataTypes) { | |
| if (includesType(withTypes, t)) | |
| ts.push(t); | |
| else if (withTypes.includes("integer") && t === "number") | |
| ts.push("integer"); | |
| } | |
| it.dataTypes = ts; | |
| } | |
| function strictTypesError(it, msg) { | |
| const schemaPath = it.schemaEnv.baseId + it.errSchemaPath; | |
| msg += ` at "${schemaPath}" (strictTypes)`; | |
| (0, util_1.checkStrictMode)(it, msg, it.opts.strictTypes); | |
| } | |
| class KeywordCxt { | |
| constructor(it, def, keyword) { | |
| (0, keyword_1.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 = (0, 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 (!(0, keyword_1.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.failResult((0, codegen_1.not)(condition), successAction, failAction); | |
| } | |
| failResult(condition, successAction, failAction) { | |
| this.gen.if(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.failResult((0, codegen_1.not)(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((0, codegen_1._) `${schemaCode} !== undefined && (${(0, codegen_1.or)(this.invalid$data(), condition)})`); | |
| } | |
| error(append, errorParams, errorPaths) { | |
| if (errorParams) { | |
| this.setParams(errorParams); | |
| this._error(append, errorPaths); | |
| this.setParams({}); | |
| return; | |
| } | |
| this._error(append, errorPaths); | |
| } | |
| _error(append, errorPaths) { | |
| ; | |
| (append ? errors_1.reportExtraError : errors_1.reportError)(this, this.def.error, errorPaths); | |
| } | |
| $dataError() { | |
| (0, errors_1.reportError)(this, this.def.$dataError || errors_1.keyword$DataError); | |
| } | |
| reset() { | |
| if (this.errsCount === undefined) | |
| throw new Error('add "trackErrors" to keyword definition'); | |
| (0, 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((0, codegen_1.or)((0, 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 (0, 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 (0, codegen_1._) `${(0, dataType_2.checkDataTypes)(st, schemaCode, it.opts.strictNumbers, dataType_2.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 (0, codegen_1._) `!${validateSchemaRef}(${schemaCode})`; | |
| } | |
| return codegen_1.nil; | |
| } | |
| } | |
| subschema(appl, valid) { | |
| const subschema = (0, subschema_1.getSubschema)(this.it, appl); | |
| (0, subschema_1.extendSubschemaData)(subschema, this.it, appl); | |
| (0, subschema_1.extendSubschemaMode)(subschema, appl); | |
| const nextContext = { ...this.it, ...subschema, items: undefined, props: undefined }; | |
| subschemaCode(nextContext, valid); | |
| return nextContext; | |
| } | |
| 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.KeywordCxt = KeywordCxt; | |
| function keywordCode(it, keyword, def, ruleType) { | |
| const cxt = new KeywordCxt(it, def, keyword); | |
| if ("code" in def) { | |
| def.code(cxt, ruleType); | |
| } | |
| else if (cxt.$data && def.validate) { | |
| (0, keyword_1.funcKeywordCode)(cxt, def); | |
| } | |
| else if ("macro" in def) { | |
| (0, keyword_1.macroKeywordCode)(cxt, def); | |
| } | |
| else if (def.compile || def.validate) { | |
| (0, keyword_1.funcKeywordCode)(cxt, def); | |
| } | |
| } | |
| 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 = (0, codegen_1._) `${data}${(0, codegen_1.getProperty)((0, util_1.unescapeJsonPointer)(segment))}`; | |
| expr = (0, codegen_1._) `${expr} && ${data}`; | |
| } | |
| } | |
| return expr; | |
| function errorMsg(pointerType, up) { | |
| return `Cannot access ${pointerType} ${up} levels up, current level is ${dataLevel}`; | |
| } | |
| } | |
| exports.getData = getData; | |
| //# sourceMappingURL=index.js.map |
Xet Storage Details
- Size:
- 20.6 kB
- Xet hash:
- 0f0ec464df19c730e1cfecd381ca8a518e994bcdc624ed7b55227d93feda466e
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.