if.ts 2.3 KB

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