-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
BREAKING CHANGE: Rich validation report was removed from the exception itself and rich object containing abstract report was added in it's place. Register method doesn't throw validation exception and returns it if one occurs. To utilize previous behavior use registerOrReject method.
- Loading branch information
Showing
18 changed files
with
228 additions
and
180 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
50 changes: 50 additions & 0 deletions
50
packages/core/lib/validator/__snapshots__/config.validator.spec.ts.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`ConfigValidator should structure validation errors 1`] = ` | ||
[ | ||
{ | ||
"errors": [ | ||
{ | ||
"currentValue": undefined, | ||
"failedConstraints": [ | ||
{ | ||
"details": "port must be an integer number", | ||
"name": "isInt", | ||
}, | ||
], | ||
"property": "port", | ||
"source": "PORT", | ||
}, | ||
{ | ||
"children": [ | ||
{ | ||
"currentValue": undefined, | ||
"failedConstraints": [ | ||
{ | ||
"details": "url must be a string", | ||
"name": "isString", | ||
}, | ||
], | ||
"property": "url", | ||
"source": "DB_URL", | ||
}, | ||
{ | ||
"currentValue": undefined, | ||
"failedConstraints": [ | ||
{ | ||
"details": "password must be a string", | ||
"name": "isString", | ||
}, | ||
], | ||
"property": "password", | ||
"source": "DB_PASSWORD", | ||
}, | ||
], | ||
"failedConstraints": undefined, | ||
"property": "db", | ||
}, | ||
], | ||
"template": [Function], | ||
}, | ||
] | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { ValidationError } from 'class-validator'; | ||
import { DbConfigMock, TemplateMock } from '../core.mocks'; | ||
|
||
export const mockFailedValidation: ValidationError[] = [ | ||
{ | ||
target: new TemplateMock(), | ||
property: 'port', | ||
children: [] as any[], | ||
constraints: { isInt: 'port must be an integer number' }, | ||
}, | ||
{ | ||
target: new TemplateMock(), | ||
value: {}, | ||
property: 'db', | ||
children: [ | ||
{ | ||
target: new DbConfigMock(), | ||
property: 'url', | ||
children: [] as any[], | ||
constraints: { isString: 'url must be a string' }, | ||
}, | ||
{ | ||
target: new DbConfigMock(), | ||
property: 'password', | ||
children: [], | ||
constraints: { isString: 'password must be a string' }, | ||
}, | ||
], | ||
}, | ||
{ | ||
target: new TemplateMock(), | ||
value: {}, | ||
property: 'db2', | ||
children: [ | ||
{ | ||
target: new DbConfigMock(), | ||
property: 'url', | ||
children: [] as any[], | ||
constraints: { isDefined: 'url must be a defined', isString: 'url must be a string' }, | ||
}, | ||
{ | ||
target: new DbConfigMock(), | ||
property: 'subdb', | ||
children: [ | ||
{ | ||
target: new DbConfigMock(), | ||
property: 'url', | ||
children: [] as any[], | ||
constraints: { isString: 'url must be a string' }, | ||
}, | ||
{ | ||
target: new DbConfigMock(), | ||
property: 'password', | ||
children: [], | ||
constraints: { isString: 'password must be a string' }, | ||
}, | ||
], | ||
constraints: { isString: 'password must be a string' }, | ||
}, | ||
], | ||
}, | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,57 @@ | ||
import { validateSync } from 'class-validator'; | ||
import { validateSync, ValidationError } from 'class-validator'; | ||
import { PROPERTIES_MAPPING_METADATA } from '../loader/constants'; | ||
import { PropertiesMapping } from '../loader/types'; | ||
import { Type } from '../utils/type.interface'; | ||
import { ConfigValidationException } from './exception/config.validation.exception'; | ||
import { ConfigValidationExceptionOptions } from './exception/config.validation.exception.options'; | ||
import { ConfigPropertyValidationError } from './errors/config.property.validation.error'; | ||
import { ConfigSubtemplateValidationError } from './errors/config.subtemplate.validation.error'; | ||
import { ConfigTemplateValidationError } from './errors/config.template.validation.error'; | ||
import { ConfigValidationException } from './errors/config.validation.exception'; | ||
|
||
export class ConfigValidator { | ||
validate(configs: object[]) { | ||
const failedValidations = configs | ||
.map<ConfigValidationExceptionOptions>((config) => ({ | ||
template: config.constructor as Type, | ||
errors: validateSync(config, { skipMissingProperties: false }), | ||
})) | ||
.map((config) => this.validateTemplate(config)) | ||
.filter(({ errors }) => errors.length > 0); | ||
|
||
if (failedValidations.length > 0) { | ||
throw new ConfigValidationException(failedValidations); | ||
return new ConfigValidationException(failedValidations); | ||
} | ||
} | ||
|
||
private validateTemplate(config: object): ConfigTemplateValidationError { | ||
return { | ||
template: config.constructor as Type, | ||
errors: validateSync(config, { skipMissingProperties: false }).map((error) => this.toPropertyError(error)), | ||
}; | ||
} | ||
|
||
private toPropertyError(error: ValidationError): ConfigPropertyValidationError | ConfigSubtemplateValidationError { | ||
if (error.children && error.children.length > 0) { | ||
return { | ||
property: error.property, | ||
failedConstraints: this.toFailedConstraints(error.constraints), | ||
children: error.children.map((child) => this.toPropertyError(child)), | ||
} satisfies ConfigSubtemplateValidationError; | ||
} | ||
|
||
const propertiesMapping: PropertiesMapping = error.target | ||
? Reflect.getMetadata(PROPERTIES_MAPPING_METADATA, error.target.constructor) | ||
: undefined; | ||
return { | ||
property: error.property, | ||
source: propertiesMapping?.get(error.property), | ||
currentValue: error.value, | ||
failedConstraints: this.toFailedConstraints(error.constraints) ?? [], | ||
} satisfies ConfigPropertyValidationError; | ||
} | ||
|
||
private toFailedConstraints(constraints: ValidationError['constraints']) { | ||
if (!constraints) { | ||
return; | ||
} | ||
const constraintsKeys = Object.keys(constraints); | ||
if (constraintsKeys.length === 0) { | ||
return; | ||
} | ||
return constraintsKeys.map((name) => ({ name, details: constraints[name] })); | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
packages/core/lib/validator/errors/config.property.validation.error.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { PropertySource, PropertyTarget } from '../../loader/types'; | ||
import { FailedConstraint } from './failed-constraint'; | ||
|
||
export interface ConfigPropertyValidationError { | ||
readonly property: PropertyTarget; | ||
readonly source?: PropertySource; | ||
readonly currentValue: any; | ||
readonly failedConstraints: FailedConstraint[]; | ||
} |
9 changes: 9 additions & 0 deletions
9
packages/core/lib/validator/errors/config.subtemplate.validation.error.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { PropertyTarget } from '../../loader/types'; | ||
import { ConfigPropertyValidationError } from './config.property.validation.error'; | ||
import { FailedConstraint } from './failed-constraint'; | ||
|
||
export interface ConfigSubtemplateValidationError { | ||
readonly property: PropertyTarget; | ||
readonly failedConstraints?: FailedConstraint[]; | ||
readonly children: (ConfigPropertyValidationError | ConfigSubtemplateValidationError)[]; | ||
} |
8 changes: 8 additions & 0 deletions
8
packages/core/lib/validator/errors/config.template.validation.error.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { Type } from '../../utils/type.interface'; | ||
import { ConfigPropertyValidationError } from './config.property.validation.error'; | ||
import { ConfigSubtemplateValidationError } from './config.subtemplate.validation.error'; | ||
|
||
export interface ConfigTemplateValidationError { | ||
readonly template: Type; | ||
readonly errors: (ConfigPropertyValidationError | ConfigSubtemplateValidationError)[]; | ||
} |
11 changes: 11 additions & 0 deletions
11
packages/core/lib/validator/errors/config.validation.exception.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { ConfigTemplateValidationError } from './config.template.validation.error'; | ||
|
||
export class ConfigValidationException extends Error { | ||
readonly errors: ConfigTemplateValidationError[]; | ||
|
||
constructor(errors: ConfigTemplateValidationError[]) { | ||
super(); | ||
this.errors = errors; | ||
this.message = 'Following templates failed validation: ' + errors.map(({ template }) => template.name).join(', '); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export interface FailedConstraint { | ||
readonly name: string; | ||
readonly details?: string; | ||
} |
File renamed without changes.
7 changes: 0 additions & 7 deletions
7
packages/core/lib/validator/exception/config.validation.exception.options.ts
This file was deleted.
Oops, something went wrong.
15 changes: 0 additions & 15 deletions
15
packages/core/lib/validator/exception/config.validation.exception.spec.ts
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.