select.ts 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. import type {KeywordDefinition, KeywordErrorDefinition, KeywordCxt, ErrorObject} from "ajv"
  2. import {_, str, nil, Name} from "ajv/dist/compile/codegen"
  3. import type {DefinitionOptions} from "./_types"
  4. import {metaSchemaRef} from "./_util"
  5. export type SelectError = ErrorObject<"select", {failingCase?: string; failingDefault?: true}>
  6. const error: KeywordErrorDefinition = {
  7. message: ({params: {schemaProp}}) =>
  8. schemaProp
  9. ? str`should match case "${schemaProp}" schema`
  10. : str`should match default case schema`,
  11. params: ({params: {schemaProp}}) =>
  12. schemaProp ? _`{failingCase: ${schemaProp}}` : _`{failingDefault: true}`,
  13. }
  14. export default function getDef(opts?: DefinitionOptions): KeywordDefinition[] {
  15. const metaSchema = metaSchemaRef(opts)
  16. return [
  17. {
  18. keyword: "select",
  19. schemaType: ["string", "number", "boolean", "null"],
  20. $data: true,
  21. error,
  22. dependencies: ["selectCases"],
  23. code(cxt: KeywordCxt) {
  24. const {gen, schemaCode, parentSchema} = cxt
  25. cxt.block$data(nil, () => {
  26. const valid = gen.let("valid", true)
  27. const schValid = gen.name("_valid")
  28. const value = gen.const("value", _`${schemaCode} === null ? "null" : ${schemaCode}`)
  29. gen.if(false) // optimizer should remove it from generated code
  30. for (const schemaProp in parentSchema.selectCases) {
  31. cxt.setParams({schemaProp})
  32. gen.elseIf(_`"" + ${value} == ${schemaProp}`) // intentional ==, to match numbers and booleans
  33. const schCxt = cxt.subschema({keyword: "selectCases", schemaProp}, schValid)
  34. cxt.mergeEvaluated(schCxt, Name)
  35. gen.assign(valid, schValid)
  36. }
  37. gen.else()
  38. if (parentSchema.selectDefault !== undefined) {
  39. cxt.setParams({schemaProp: undefined})
  40. const schCxt = cxt.subschema({keyword: "selectDefault"}, schValid)
  41. cxt.mergeEvaluated(schCxt, Name)
  42. gen.assign(valid, schValid)
  43. }
  44. gen.endIf()
  45. cxt.pass(valid)
  46. })
  47. },
  48. },
  49. {
  50. keyword: "selectCases",
  51. dependencies: ["select"],
  52. metaSchema: {
  53. type: "object",
  54. additionalProperties: metaSchema,
  55. },
  56. },
  57. {
  58. keyword: "selectDefault",
  59. dependencies: ["select", "selectCases"],
  60. metaSchema,
  61. },
  62. ]
  63. }
  64. module.exports = getDef