Skip to content

Commit

Permalink
feat: add validationErrors to schema mismatch errors
Browse files Browse the repository at this point in the history
  • Loading branch information
MoLow committed Aug 20, 2023
1 parent 920317f commit fe701e4
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 4 deletions.
6 changes: 5 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,20 +122,24 @@ function build (schema, options) {

let contextFunctionCode

const resetValidatorErrors = (context.validatorSchemasIds.size > 0) ? 'validator.resetErrors();' : ''

// If we have only the invocation of the 'anonymous0' function, we would
// basically just wrap the 'anonymous0' function in the 'main' function and
// and the overhead of the intermediate variable 'json'. We can avoid the
// wrapping and the unnecessary memory allocation by aliasing 'anonymous0' to
// 'main'
if (code === 'json += anonymous0(input)') {
contextFunctionCode = `
${resetValidatorErrors}
${context.functions.join('\n')}
const main = anonymous0
return main
`
} else {
contextFunctionCode = `
function main (input) {
${resetValidatorErrors}
let json = ''
${code}
return json
Expand Down Expand Up @@ -896,7 +900,7 @@ function buildValue (context, location, input) {
}

code += `
else throw new TypeError(\`The value of '${schemaRef}' does not match schema definition.\`)
else validator.throwAccumulatedErrors("${schemaRef}");
`
if (schema.type === 'object') {
code += `
Expand Down
15 changes: 14 additions & 1 deletion lib/validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class Validator {
}
})

this._errors = []
this._ajvSchemas = {}
this._ajvOptions = ajvOptions || {}
}
Expand All @@ -47,8 +48,20 @@ class Validator {
}
}

resetErrors () {
this._errors = []
}

validate (schemaRef, data) {
return this.ajv.validate(schemaRef, data)
const result = this.ajv.validate(schemaRef, data)
if (this.ajv.errors) this._errors.push(...this.ajv.errors)
return result
}

throwAccumulatedErrors (schemaRef) {
const error = new TypeError(`The value of '${schemaRef}' does not match schema definition.`)
error.validationErrors = this._errors
throw error
}

// Ajv does not support js date format. In order to properly validate objects containing a date,
Expand Down
14 changes: 12 additions & 2 deletions test/any.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,12 @@ test('should throw a TypeError with the path to the key of the invalid value /1'

const stringify = build(schema)

t.throws(() => stringify({ kind: 'Baz', value: 1 }), new TypeError('The value of \'#\' does not match schema definition.'))
t.throws(() => stringify({ kind: 'Baz', value: 1 }), Object.assign(new TypeError('The value of \'#\' does not match schema definition.'), {
validationErrors: [
{ message: 'must be equal to one of the allowed values', schemaPath: '#/properties/kind/enum', instancePath: '/kind' },
{ message: 'must be equal to one of the allowed values', schemaPath: '#/properties/kind/enum', instancePath: '/kind' }
]
}))
})

test('should throw a TypeError with the path to the key of the invalid value /2', (t) => {
Expand Down Expand Up @@ -227,5 +232,10 @@ test('should throw a TypeError with the path to the key of the invalid value /2'

const stringify = build(schema)

t.throws(() => stringify({ data: { kind: 'Baz', value: 1 } }), new TypeError('The value of \'#/properties/data\' does not match schema definition.'))
t.throws(() => stringify({ data: { kind: 'Baz', value: 1 } }), Object.assign(new TypeError('The value of \'#/properties/data\' does not match schema definition.'), {
validationErrors: [
{ message: 'must be equal to one of the allowed values', schemaPath: '#/properties/kind/enum', instancePath: '/kind' },
{ message: 'must be equal to one of the allowed values', schemaPath: '#/properties/kind/enum', instancePath: '/kind' }
]
}))
})

0 comments on commit fe701e4

Please sign in to comment.