if.ts 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. import type {
  2. CodeKeywordDefinition,
  3. ErrorObject,
  4. KeywordErrorDefinition,
  5. AnySchema,
  6. } from "../../types"
  7. import type {SchemaObjCxt} from "../../compile"
  8. import type KeywordCxt from "../../compile/context"
  9. import {_, str, not, Name} from "../../compile/codegen"
  10. import {alwaysValidSchema} from "../../compile/util"
  11. import {checkStrictMode} from "../../compile/validate"
  12. export type IfKeywordError = ErrorObject<"if", {failingKeyword: string}, AnySchema>
  13. const error: KeywordErrorDefinition = {
  14. message: ({params}) => str`should match "${params.ifClause}" schema`,
  15. params: ({params}) => _`{failingKeyword: ${params.ifClause}}`,
  16. }
  17. const def: CodeKeywordDefinition = {
  18. keyword: "if",
  19. schemaType: ["object", "boolean"],
  20. trackErrors: true,
  21. error,
  22. code(cxt: KeywordCxt) {
  23. const {gen, parentSchema, it} = cxt
  24. if (parentSchema.then === undefined && parentSchema.else === undefined) {
  25. checkStrictMode(it, '"if" without "then" and "else" is ignored')
  26. }
  27. const hasThen = hasSchema(it, "then")
  28. const hasElse = hasSchema(it, "else")
  29. if (!hasThen && !hasElse) return
  30. const valid = gen.let("valid", true)
  31. const schValid = gen.name("_valid")
  32. validateIf()
  33. cxt.reset()
  34. if (hasThen && hasElse) {
  35. const ifClause = gen.let("ifClause")
  36. cxt.setParams({ifClause})
  37. gen.if(schValid, validateClause("then", ifClause), validateClause("else", ifClause))
  38. } else if (hasThen) {
  39. gen.if(schValid, validateClause("then"))
  40. } else {
  41. gen.if(not(schValid), validateClause("else"))
  42. }
  43. cxt.pass(valid, () => cxt.error(true))
  44. function validateIf(): void {
  45. const schCxt = cxt.subschema(
  46. {
  47. keyword: "if",
  48. compositeRule: true,
  49. createErrors: false,
  50. allErrors: false,
  51. },
  52. schValid
  53. )
  54. cxt.mergeEvaluated(schCxt)
  55. }
  56. function validateClause(keyword: string, ifClause?: Name): () => void {
  57. return () => {
  58. const schCxt = cxt.subschema({keyword}, schValid)
  59. gen.assign(valid, schValid)
  60. cxt.mergeValidEvaluated(schCxt, valid)
  61. if (ifClause) gen.assign(ifClause, _`${keyword}`)
  62. else cxt.setParams({ifClause: keyword})
  63. }
  64. }
  65. },
  66. }
  67. function hasSchema(it: SchemaObjCxt, keyword: string): boolean {
  68. const schema = it.schema[keyword]
  69. return schema !== undefined && !alwaysValidSchema(it, schema)
  70. }
  71. export default def