unevaluatedProperties.ts 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. import type {
  2. CodeKeywordDefinition,
  3. KeywordErrorDefinition,
  4. ErrorObject,
  5. AnySchema,
  6. } from "../../types"
  7. import {_, not, and, Name, Code} from "../../compile/codegen"
  8. import {alwaysValidSchema} from "../../compile/util"
  9. import N from "../../compile/names"
  10. import {Type} from "../../compile/subschema"
  11. export type UnevaluatedPropertiesError = ErrorObject<
  12. "unevaluatedProperties",
  13. {unevaluatedProperty: string},
  14. AnySchema
  15. >
  16. const error: KeywordErrorDefinition = {
  17. message: "should NOT have unevaluated properties",
  18. params: ({params}) => _`{unevaluatedProperty: ${params.unevaluatedProperty}}`,
  19. }
  20. const def: CodeKeywordDefinition = {
  21. keyword: "unevaluatedProperties",
  22. type: "object",
  23. schemaType: ["boolean", "object"],
  24. trackErrors: true,
  25. error,
  26. code(cxt) {
  27. const {gen, schema, data, errsCount, it} = cxt
  28. /* istanbul ignore if */
  29. if (!errsCount) throw new Error("ajv implementation error")
  30. const {allErrors, props} = it
  31. if (props instanceof Name) {
  32. gen.if(_`${props} !== true`, () =>
  33. gen.forIn("key", data, (key: Name) =>
  34. gen.if(unevaluatedDynamic(props, key), () => unevaluatedPropCode(key))
  35. )
  36. )
  37. } else if (props !== true) {
  38. gen.forIn("key", data, (key: Name) =>
  39. props === undefined
  40. ? unevaluatedPropCode(key)
  41. : gen.if(unevaluatedStatic(props, key), () => unevaluatedPropCode(key))
  42. )
  43. }
  44. it.props = true
  45. cxt.ok(_`${errsCount} === ${N.errors}`)
  46. function unevaluatedPropCode(key: Name): void {
  47. if (schema === false) {
  48. cxt.setParams({unevaluatedProperty: key})
  49. cxt.error()
  50. if (!allErrors) gen.break()
  51. return
  52. }
  53. if (!alwaysValidSchema(it, schema)) {
  54. const valid = gen.name("valid")
  55. cxt.subschema(
  56. {
  57. keyword: "unevaluatedProperties",
  58. dataProp: key,
  59. dataPropType: Type.Str,
  60. strictSchema: it.strictSchema,
  61. },
  62. valid
  63. )
  64. if (!allErrors) gen.if(not(valid), () => gen.break())
  65. }
  66. }
  67. function unevaluatedDynamic(evaluatedProps: Name, key: Name): Code {
  68. return _`!${evaluatedProps} || !${evaluatedProps}[${key}]`
  69. }
  70. function unevaluatedStatic(evaluatedProps: {[K in string]?: true}, key: Name): Code {
  71. const ps: Code[] = []
  72. for (const p in evaluatedProps) {
  73. if (evaluatedProps[p] === true) ps.push(_`${key} !== ${p}`)
  74. }
  75. return and(...ps)
  76. }
  77. },
  78. }
  79. export default def