Skip to content

Commit

Permalink
Improved error messages for class-validator
Browse files Browse the repository at this point in the history
  • Loading branch information
decs committed Oct 13, 2024
1 parent 0f28135 commit d7e9ade
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 54 deletions.
7 changes: 7 additions & 0 deletions .changeset/lovely-bobcats-hang.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@typeschema/class-validator': minor
'@typeschema/main': patch
'@typeschema/all': patch
---

Improved error messages for class-validator
36 changes: 18 additions & 18 deletions README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

61 changes: 57 additions & 4 deletions packages/all/src/__tests__/class-validator.test.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 11 additions & 9 deletions packages/class-validator/src/__tests__/class-validator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,13 @@ describe('class-validator', () => {
@IsDateString()
updatedAt!: string;

@IsOptional()
@ValidateNested()
nested!: NestedSchema;
nested?: NestedSchema;

@IsOptional()
@ValidateNested()
nestedArray?: NestedSchema[];
nestedArray?: Array<NestedSchema>;
}
const schema = Schema;

Expand All @@ -67,7 +69,7 @@ describe('class-validator', () => {
email: '[email protected]',
id: 'c4a760a8-dbcf-4e14-9f39-645a8e933d74',
name: 'John Doe',
updatedAt: '2021-01-01T00:00:00.000Z'
updatedAt: '2021-01-01T00:00:00.000Z',
};

const badNestedData = {
Expand Down Expand Up @@ -100,7 +102,7 @@ describe('class-validator', () => {
{
message: 'age must be an integer number',
path: ['age'],
}
},
],
success: false,
});
Expand All @@ -109,20 +111,20 @@ describe('class-validator', () => {
issues: [
{
message: 'value should not be empty',
path: ['nested.value'],
path: ['nested', 'value'],
},
{
message: 'value must be a string',
path: ['nested.value'],
path: ['nested', 'value'],
},
{
message: 'value should not be empty',
path: ['nestedArray[0].value'],
path: ['nestedArray', 0, 'value'],
},
{
message: 'value must be a string',
path: ['nestedArray[0].value'],
}
path: ['nestedArray', 0, 'value'],
},
],
success: false,
});
Expand Down
36 changes: 17 additions & 19 deletions packages/class-validator/src/validation.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,34 @@
/* eslint-disable prettier/prettier */
import type {AdapterResolver} from './resolver';
import type {ValidationAdapter, ValidationIssue} from '@typeschema/core';

import {memoize} from '@typeschema/core';
import { ValidationError } from "class-validator";
import {ValidationError} from 'class-validator';

const importValidationModule = memoize(async () => {
const {validate} = await import('class-validator');
return {validate};
});

function getIssues(
error: ValidationError,
parentPath: Array<PropertyKey>,
): Array<ValidationIssue> {
const path = [
...parentPath,
Number.isInteger(+error.property) ? +error.property : error.property,
];
return Object.values(error.constraints ?? {})
.map((message): ValidationIssue => ({message, path}))
.concat(
error.children?.flatMap(childError => getIssues(childError, path)) ?? [],
);
}

export const validationAdapter: ValidationAdapter<
AdapterResolver
> = async schema => {
const {validate} = await importValidationModule();
return async data => {
function getIssues(error: ValidationError, parentPath = ""): ValidationIssue[] {
const currentPath = parentPath
? Number.isInteger(+error.property) ? `${parentPath}[${error.property}]` : `${parentPath}.${error.property}`
: error.property;
const constraints = error.constraints ? Object.values(error.constraints) : [];
const childIssues = error.children ? error.children.flatMap(childError => getIssues(childError, currentPath)) : [];

return [
...constraints.map((message) => ({
message: message,
path: [currentPath],
})),
...childIssues
];
}

const errors = await validate(Object.assign(new schema(), data));
if (errors.length === 0) {
return {
Expand All @@ -40,7 +38,7 @@ export const validationAdapter: ValidationAdapter<
};
}
return {
issues: errors.flatMap(error => getIssues(error)),
issues: errors.flatMap(error => getIssues(error, [])),
success: false,
};
};
Expand Down
Loading

0 comments on commit d7e9ade

Please sign in to comment.