Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/tidy-pointers-smile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'better-ajv-errors': patch
---

Preserve validation errors for Unicode JSON Pointer paths.
11 changes: 11 additions & 0 deletions src/__tests__/helpers/make-tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ describe('makeTree', () => {
`);
});

it('preserves escaped and Unicode JSON pointer segments', async () => {
const error = { instancePath: '/root/~0tilde/~1slash/名前' };
const tree = makeTree([error]);

expect(
tree.children['/root'].children['/~0tilde'].children['/~1slash'].children[
'/名前'
].errors
).toEqual([error]);
});

it('works on array dataPath', async () => {
expect(
makeTree([{ dataPath: '/root/child/0' }, { dataPath: '/root/child/1' }])
Expand Down
32 changes: 30 additions & 2 deletions src/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ describe('Main', () => {
});

it('should output errors for multiple required values', async () => {
const [schema, data, json] = await getSchemaAndData('multiple-required', __dirname);
const [schema, data, json] = await getSchemaAndData(
'multiple-required',
__dirname
);
const ajv = new Ajv({ allErrors: true });
const validate = ajv.compile(schema);
const valid = validate(data);
Expand All @@ -45,5 +48,30 @@ describe('Main', () => {
});

expect(res).toMatchSnapshot();
});
});

it('should output errors for Unicode property paths', async () => {
const schema = {
type: 'object',
properties: { 名前: { type: 'string', minLength: 2 } },
};
const data = { 名前: '' };
const ajv = new Ajv();
const validate = ajv.compile(schema);
const valid = validate(data);
expect(valid).toBeFalsy();

const res = betterAjvErrors(schema, data, validate.errors, {
format: 'js',
});

expect(validate.errors).toEqual([
expect.objectContaining({ instancePath: '/名前' }),
]);
expect(res).toEqual([
expect.objectContaining({
error: '/名前: minLength must NOT have fewer than 2 characters',
}),
]);
});
});
12 changes: 6 additions & 6 deletions src/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
DefaultValidationError,
} from './validation-errors/index';

const JSON_POINTERS_REGEX = /\/[\w_-]+(\/\d+)?/g;
const JSON_POINTERS_REGEX = /\/[^/]*(\/\d+)?/g;

// Make a tree of errors from ajv errors array
export function makeTree(ajvErrors = []) {
Expand Down Expand Up @@ -43,8 +43,8 @@ export function makeTree(ajvErrors = []) {

export function filterRedundantErrors(root, parent, key) {
/**
* Partition out the errors by kind for ease of proceessing
*/
* Partition out the errors by kind for ease of proceessing
*/
const { anyOfErrors, enumErrors, requiredErrors } = getErrors(root).reduce(
(acc, error) => {
if (isRequiredError(error)) {
Expand All @@ -63,14 +63,14 @@ export function filterRedundantErrors(root, parent, key) {

return acc;
},
{ anyOfErrors: [], enumErrors: [], requiredErrors: [] },
{ anyOfErrors: [], enumErrors: [], requiredErrors: [] }
);

/**
* If there is are `required` errors then we can just drop every non-required error.
* And, also `required` should have more priority than `anyOf`. @see #8
*/

if (requiredErrors.length > 0) {
root.errors = requiredErrors;
root.children = {};
Expand All @@ -93,7 +93,7 @@ export function filterRedundantErrors(root, parent, key) {
/**
* If all errors are `enum` and siblings have any error then we can safely
* ignore the node. As we return early if there's required errors, we only
* need to check anyofErrors length
* need to check anyofErrors length
*
* **CAUTION**
* Need explicit `root.errors` check because `[].every(fn) === true`
Expand Down