enum.ts 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. import type {CodeKeywordDefinition, ErrorObject, KeywordErrorDefinition} from "../../types"
  2. import type {KeywordCxt} from "../../compile/validate"
  3. import {_, or, Name, Code} from "../../compile/codegen"
  4. import {useFunc} from "../../compile/util"
  5. import equal from "../../runtime/equal"
  6. export type EnumError = ErrorObject<"enum", {allowedValues: any[]}, any[] | {$data: string}>
  7. const error: KeywordErrorDefinition = {
  8. message: "must be equal to one of the allowed values",
  9. params: ({schemaCode}) => _`{allowedValues: ${schemaCode}}`,
  10. }
  11. const def: CodeKeywordDefinition = {
  12. keyword: "enum",
  13. schemaType: "array",
  14. $data: true,
  15. error,
  16. code(cxt: KeywordCxt) {
  17. const {gen, data, $data, schema, schemaCode, it} = cxt
  18. if (!$data && schema.length === 0) throw new Error("enum must have non-empty array")
  19. const useLoop = schema.length >= it.opts.loopEnum
  20. let eql: Name | undefined
  21. const getEql = (): Name => (eql ??= useFunc(gen, equal))
  22. let valid: Code
  23. if (useLoop || $data) {
  24. valid = gen.let("valid")
  25. cxt.block$data(valid, loopEnum)
  26. } else {
  27. /* istanbul ignore if */
  28. if (!Array.isArray(schema)) throw new Error("ajv implementation error")
  29. const vSchema = gen.const("vSchema", schemaCode)
  30. valid = or(...schema.map((_x: unknown, i: number) => equalCode(vSchema, i)))
  31. }
  32. cxt.pass(valid)
  33. function loopEnum(): void {
  34. gen.assign(valid, false)
  35. gen.forOf("v", schemaCode as Code, (v) =>
  36. gen.if(_`${getEql()}(${data}, ${v})`, () => gen.assign(valid, true).break())
  37. )
  38. }
  39. function equalCode(vSchema: Name, i: number): Code {
  40. const sch = schema[i]
  41. return typeof sch === "object" && sch !== null
  42. ? _`${getEql()}(${data}, ${vSchema}[${i}])`
  43. : _`${data} === ${sch}`
  44. }
  45. },
  46. }
  47. export default def