diff --git a/.changeset/three-planets-follow.md b/.changeset/three-planets-follow.md new file mode 100644 index 00000000..82398de9 --- /dev/null +++ b/.changeset/three-planets-follow.md @@ -0,0 +1,5 @@ +--- +'better-ajv-errors': minor +--- + +Add support for "unevaluatedProperties" keyword #182. Prints the same details as for the "additionalProperties" keyword. diff --git a/src/helpers.js b/src/helpers.js index 13e30fad..3194c8e7 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -10,6 +10,7 @@ import { } from './utils'; import { AdditionalPropValidationError, + UnevaluatedPropValidationError, RequiredValidationError, EnumValidationError, DefaultValidationError, @@ -140,6 +141,10 @@ export function createErrorInstances(root, options) { return ret.concat( new AdditionalPropValidationError(error, options) ); + case 'unevaluatedProperties': + return ret.concat( + new UnevaluatedPropValidationError(error, options) + ); case 'required': return ret.concat(new RequiredValidationError(error, options)); default: diff --git a/src/validation-errors/__fixtures__/unevaluatedProperties/data.json b/src/validation-errors/__fixtures__/unevaluatedProperties/data.json new file mode 100644 index 00000000..d6672673 --- /dev/null +++ b/src/validation-errors/__fixtures__/unevaluatedProperties/data.json @@ -0,0 +1,5 @@ +{ + "foo": "bar", + "bar": 2, + "baz": [] +} diff --git a/src/validation-errors/__fixtures__/unevaluatedProperties/schema.json b/src/validation-errors/__fixtures__/unevaluatedProperties/schema.json new file mode 100644 index 00000000..6cc567a4 --- /dev/null +++ b/src/validation-errors/__fixtures__/unevaluatedProperties/schema.json @@ -0,0 +1,12 @@ +{ + "type": "object", + "properties": { + "foo": { "type": "string" }, + "bar": { "type": "number" } + }, + "required": [ + "foo", + "bar" + ], + "unevaluatedProperties": false +} diff --git a/src/validation-errors/__tests__/__snapshots__/main.js.snap b/src/validation-errors/__tests__/__snapshots__/main.js.snap index 5458ad74..5a2b3827 100644 --- a/src/validation-errors/__tests__/__snapshots__/main.js.snap +++ b/src/validation-errors/__tests__/__snapshots__/main.js.snap @@ -71,3 +71,22 @@ exports[`Main > should support js output format for required errors 1`] = ` }, ] `; + +exports[`Main > should support js output format for unevaluatedProperties errors 1`] = ` +[ + { + "end": { + "column": 27, + "line": 1, + "offset": 26, + }, + "error": " Property baz is not expected to be here", + "path": "", + "start": { + "column": 22, + "line": 1, + "offset": 21, + }, + }, +] +`; diff --git a/src/validation-errors/__tests__/main.js b/src/validation-errors/__tests__/main.js index 838ca03f..99104aa9 100644 --- a/src/validation-errors/__tests__/main.js +++ b/src/validation-errors/__tests__/main.js @@ -1,5 +1,6 @@ import { describe, it, expect } from 'vitest'; import Ajv from 'ajv'; +import Ajv2020 from 'ajv/dist/2020'; import betterAjvErrors from '../../'; import { getSchemaAndData } from '../../test-helpers'; @@ -49,6 +50,23 @@ describe('Main', () => { expect(res).toMatchSnapshot(); }); + it('should support js output format for unevaluatedProperties errors', async () => { + const [schema, data] = await getSchemaAndData( + 'unevaluatedProperties', + __dirname + ); + + const ajv = new Ajv2020(); + const validate = ajv.compile(schema); + const valid = validate(data); + expect(valid).toBeFalsy(); + + const res = betterAjvErrors(schema, data, validate.errors, { + format: 'js', + }); + expect(res).toMatchSnapshot(); + }); + it('should support js output format for enum errors', async () => { const [schema, data] = await getSchemaAndData('enum', __dirname); diff --git a/src/validation-errors/index.js b/src/validation-errors/index.js index 39ff94b8..03d5a744 100644 --- a/src/validation-errors/index.js +++ b/src/validation-errors/index.js @@ -1,4 +1,5 @@ export { default as RequiredValidationError } from './required'; export { default as AdditionalPropValidationError } from './additional-prop'; +export { default as UnevaluatedPropValidationError } from './unevaluated-prop'; export { default as EnumValidationError } from './enum'; export { default as DefaultValidationError } from './default'; diff --git a/src/validation-errors/unevaluated-prop.js b/src/validation-errors/unevaluated-prop.js new file mode 100644 index 00000000..3b01d8d5 --- /dev/null +++ b/src/validation-errors/unevaluated-prop.js @@ -0,0 +1,33 @@ +import chalk from 'chalk'; +import BaseValidationError from './base'; + +export default class UnevaluatedPropValidationError extends BaseValidationError { + constructor(...args) { + super(...args); + this.options.isIdentifierLocation = true; + } + + print() { + const { message, params } = this.options; + const output = [chalk`{red {bold UNEVALUATED PROPERTY} ${message}}\n`]; + + return output.concat( + this.getCodeFrame( + chalk`😲 {magentaBright ${params.unevaluatedProperty}} is not expected to be here!`, + `${this.instancePath}/${params.unevaluatedProperty}` + ) + ); + } + + getError() { + const { params } = this.options; + + return { + ...this.getLocation(`${this.instancePath}/${params.unevaluatedProperty}`), + error: `${this.getDecoratedPath()} Property ${ + params.unevaluatedProperty + } is not expected to be here`, + path: this.instancePath, + }; + } +}