ajv
Version:
Another JSON Schema Validator
73 lines (67 loc) • 2.3 kB
text/typescript
import type {CodeKeywordDefinition, AnySchema} from "../../types"
import type KeywordCxt from "../../compile/context"
import {_, not} from "../../compile/codegen"
import {Type} from "../../compile/subschema"
import {alwaysValidSchema, mergeEvaluated} from "../../compile/util"
import {checkStrictMode} from "../../compile/validate"
const def: CodeKeywordDefinition = {
keyword: "items",
type: "array",
schemaType: ["object", "array", "boolean"],
before: "uniqueItems",
code(cxt: KeywordCxt) {
const {gen, schema, parentSchema, data, it} = cxt
const len = gen.const("len", _`${data}.length`)
if (Array.isArray(schema)) {
if (it.opts.unevaluated && schema.length && it.items !== true) {
it.items = mergeEvaluated.items(gen, schema.length, it.items)
}
validateTuple(schema)
} else {
it.items = true
if (!alwaysValidSchema(it, schema)) validateArray()
}
function validateTuple(schArr: AnySchema[]): void {
if (it.opts.strictTuples && !fullTupleSchema(schema.length, parentSchema)) {
const msg = `"items" is ${schArr.length}-tuple, but minItems or maxItems/additionalItems are not specified or different`
checkStrictMode(it, msg, it.opts.strictTuples)
}
const valid = gen.name("valid")
schArr.forEach((sch: AnySchema, i: number) => {
if (alwaysValidSchema(it, sch)) return
gen.if(_`${len} > ${i}`, () =>
cxt.subschema(
{
keyword: "items",
schemaProp: i,
dataProp: i,
strictSchema: it.strictSchema,
},
valid
)
)
cxt.ok(valid)
})
}
function validateArray(): void {
const valid = gen.name("valid")
gen.forRange("i", 0, len, (i) => {
cxt.subschema(
{
keyword: "items",
dataProp: i,
dataPropType: Type.Num,
strictSchema: it.strictSchema,
},
valid
)
if (!it.allErrors) gen.if(not(valid), () => gen.break())
})
cxt.ok(valid)
}
},
}
function fullTupleSchema(len: number, sch: any): boolean {
return len === sch.minItems && (len === sch.maxItems || sch.additionalItems === false)
}
export default def