items.ts 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. import type {CodeKeywordDefinition, AnySchema} from "../../types"
  2. import type KeywordCxt from "../../compile/context"
  3. import {_, not} from "../../compile/codegen"
  4. import {Type} from "../../compile/subschema"
  5. import {alwaysValidSchema, mergeEvaluated} from "../../compile/util"
  6. import {checkStrictMode} from "../../compile/validate"
  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, parentSchema, data, it} = cxt
  14. const len = gen.const("len", _`${data}.length`)
  15. if (Array.isArray(schema)) {
  16. if (it.opts.unevaluated && schema.length && it.items !== true) {
  17. it.items = mergeEvaluated.items(gen, schema.length, it.items)
  18. }
  19. validateTuple(schema)
  20. } else {
  21. it.items = true
  22. if (!alwaysValidSchema(it, schema)) validateArray()
  23. }
  24. function validateTuple(schArr: AnySchema[]): void {
  25. if (it.opts.strictTuples && !fullTupleSchema(schema.length, parentSchema)) {
  26. const msg = `"items" is ${schArr.length}-tuple, but minItems or maxItems/additionalItems are not specified or different`
  27. checkStrictMode(it, msg, it.opts.strictTuples)
  28. }
  29. const valid = gen.name("valid")
  30. schArr.forEach((sch: AnySchema, i: number) => {
  31. if (alwaysValidSchema(it, sch)) return
  32. gen.if(_`${len} > ${i}`, () =>
  33. cxt.subschema(
  34. {
  35. keyword: "items",
  36. schemaProp: i,
  37. dataProp: i,
  38. strictSchema: it.strictSchema,
  39. },
  40. valid
  41. )
  42. )
  43. cxt.ok(valid)
  44. })
  45. }
  46. function validateArray(): void {
  47. const valid = gen.name("valid")
  48. gen.forRange("i", 0, len, (i) => {
  49. cxt.subschema(
  50. {
  51. keyword: "items",
  52. dataProp: i,
  53. dataPropType: Type.Num,
  54. strictSchema: it.strictSchema,
  55. },
  56. valid
  57. )
  58. if (!it.allErrors) gen.if(not(valid), () => gen.break())
  59. })
  60. cxt.ok(valid)
  61. }
  62. },
  63. }
  64. function fullTupleSchema(len: number, sch: any): boolean {
  65. return len === sch.minItems && (len === sch.maxItems || sch.additionalItems === false)
  66. }
  67. export default def