diff --git a/README.md b/README.md index 886712dd76..41a15a8a7b 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,8 @@ import { IsInt, Length, IsEmail, + IsNotBlank, + IsString, IsFQDN, IsDate, Min, @@ -83,6 +85,10 @@ export class Post { @IsEmail() email: string; + @IsString() + @IsNotBlank() + username: string; + @IsFQDN() site: string; diff --git a/src/decorator/common/IsNotBlank.ts b/src/decorator/common/IsNotBlank.ts new file mode 100644 index 0000000000..0eab1cd8cf --- /dev/null +++ b/src/decorator/common/IsNotBlank.ts @@ -0,0 +1,44 @@ +import { ValidationOptions } from '../ValidationOptions'; +import { buildMessage, ValidateBy } from './ValidateBy'; + +export const IS_NOT_BLANK = 'isNotBlank'; + +/** + * @param value The value to be checked + * @returns true if the value is not blank, false otherwise + * @description + * The value is considered blank if it is null, undefined or empty string + * @description + * Non-string values is considered not blank + */ +export function isNotBlank(value: unknown): boolean { + if (value == null) return false; + + if (typeof value === 'string') return value.trim().length > 0; + + return true; +} + +/** + * @param validationOptions The validation options + * @returns {PropertyDecorator} + * + * @description + * The decorator checks if the value is not blank + * @description + * The value is considered blank if it is null, undefined or empty string + * @description + * Non-string values is considered not blank + */ +export function IsNotBlank(validationOptions?: ValidationOptions): PropertyDecorator { + return ValidateBy( + { + name: IS_NOT_BLANK, + validator: { + validate: (value): boolean => isNotBlank(value), + defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property should not be blank', validationOptions), + }, + }, + validationOptions + ); +} diff --git a/src/decorator/decorators.ts b/src/decorator/decorators.ts index d449e9301a..eb50537356 100644 --- a/src/decorator/decorators.ts +++ b/src/decorator/decorators.ts @@ -21,6 +21,7 @@ export * from './common/Equals'; export * from './common/NotEquals'; export * from './common/IsEmpty'; export * from './common/IsNotEmpty'; +export * from './common/IsNotBlank'; export * from './common/IsIn'; export * from './common/IsNotIn'; diff --git a/test/functional/validation-functions-and-decorators.spec.ts b/test/functional/validation-functions-and-decorators.spec.ts index 9f938616c4..b66d1e78ff 100644 --- a/test/functional/validation-functions-and-decorators.spec.ts +++ b/test/functional/validation-functions-and-decorators.spec.ts @@ -124,6 +124,8 @@ import { notEquals, isEmpty, isNotEmpty, + IsNotBlank, + isNotBlank, isIn, isNotIn, isDateString, @@ -422,7 +424,7 @@ describe('IsEmpty', () => { }); describe('IsNotEmpty', () => { - const validValues = ['a', 'abc']; + const validValues = ['a', 'abc', ' ', 0, 1]; const invalidValues = ['', undefined, null]; class MyClass { @@ -453,6 +455,38 @@ describe('IsNotEmpty', () => { }); }); +describe('IsNotBlank', () => { + const validValues = ['a', 'abc', 0, 1, new Object(), [], new Date(), true, false]; + const invalidValues = ['', undefined, null, ' ']; + + class MyClass { + @IsNotBlank() + someProperty: string; + } + + it('should not fail if validator.validate said that its valid', () => { + return checkValidValues(new MyClass(), validValues); + }); + + it('should fail if validator.validate said that its invalid', () => { + return checkInvalidValues(new MyClass(), invalidValues); + }); + + it('should not fail if method in validator said that its valid', () => { + validValues.forEach(value => expect(isNotBlank(value)).toBeTruthy()); + }); + + it('should fail if method in validator said that its invalid', () => { + invalidValues.forEach(value => expect(isNotBlank(value)).toBeFalsy()); + }); + + it('should return error object with proper data', () => { + const validationType = 'isNotBlank'; + const message = 'someProperty should not be blank'; + return checkReturnedError(new MyClass(), invalidValues, validationType, message); + }); +}); + describe('IsIn', () => { const constraint = ['foo', 'bar'] as const; const validValues = ['foo', 'bar'];