items.ts 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. import type {CodeKeywordDefinition, AnySchema} from "../../types"
  2. import type KeywordCxt from "../../compile/context"
  3. import {_} from "../../compile/codegen"
  4. import {alwaysValidSchema, mergeEvaluated} from "../../compile/util"
  5. import {checkStrictMode} from "../../compile/validate"
  6. import {validateArray} from "../code"
  7. const def: CodeKeywordDefinition = {
  8. keyword: "items",
  9. type: "array",
  10. schemaType: ["object", "array", "boolean"],
  11. before: "uniqueItems",
  12. code(cxt: KeywordCxt) {
  13. const {gen, schema, it} = cxt
  14. if (Array.isArray(schema)) {
  15. if (it.opts.unevaluated && schema.length && it.items !== true) {
  16. it.items = mergeEvaluated.items(gen, schema.length, it.items)
  17. }
  18. validateTuple(schema)
  19. } else {
  20. it.items = true
  21. if (alwaysValidSchema(it, schema)) return
  22. cxt.ok(validateArray(cxt))
  23. }
  24. function validateTuple(schArr: AnySchema[]): void {
  25. const {parentSchema, data} = cxt
  26. if (it.opts.strictTuples && !fullTupleSchema(schArr.length, parentSchema)) {
  27. const msg = `"items" is ${schArr.length}-tuple, but minItems or maxItems/additionalItems are not specified or different`
  28. checkStrictMode(it, msg, it.opts.strictTuples)
  29. }
  30. const valid = gen.name("valid")
  31. const len = gen.const("len", _`${data}.length`)
  32. schArr.forEach((sch: AnySchema, i: number) => {
  33. if (alwaysValidSchema(it, sch)) return
  34. gen.if(_`${len} > ${i}`, () =>
  35. cxt.subschema(
  36. {
  37. keyword: "items",
  38. schemaProp: i,
  39. dataProp: i,
  40. },
  41. valid
  42. )
  43. )
  44. cxt.ok(valid)
  45. })
  46. }
  47. },
  48. }
  49. function fullTupleSchema(len: number, sch: any): boolean {
  50. return len === sch.minItems && (len === sch.maxItems || sch.additionalItems === false)
  51. }
  52. export default def