From e73512638a4a57a924972537c80c526ddbf1fdd4 Mon Sep 17 00:00:00 2001 From: Gabriel Logan Date: Fri, 24 Jan 2025 15:10:17 -0300 Subject: [PATCH 1/6] feat: add IsNotBlank decorator and corresponding tests --- src/decorator/common/IsNotBlank.ts | 28 +++++++++++++++ src/decorator/decorators.ts | 1 + ...alidation-functions-and-decorators.spec.ts | 36 ++++++++++++++++++- 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 src/decorator/common/IsNotBlank.ts diff --git a/src/decorator/common/IsNotBlank.ts b/src/decorator/common/IsNotBlank.ts new file mode 100644 index 0000000000..c6e799d531 --- /dev/null +++ b/src/decorator/common/IsNotBlank.ts @@ -0,0 +1,28 @@ +import { ValidationOptions } from '../ValidationOptions'; +import { buildMessage, ValidateBy } from './ValidateBy'; + +export const IS_NOT_BLANK = "isNotBlank"; + +export function isNotBlank(value: unknown): boolean { + return ( + !!value && typeof value === "string" && value.trim().length > 0 + ); +} + +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..1c8a12359e 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', ' ']; const invalidValues = ['', undefined, null]; class MyClass { @@ -453,6 +455,38 @@ describe('IsNotEmpty', () => { }); }); +describe('IsNotBlank', () => { + const validValues = ['a', 'abc']; + 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']; From 881cabd8c817cfefd3f20ace795c6a94240086e6 Mon Sep 17 00:00:00 2001 From: Gabriel Logan Date: Fri, 24 Jan 2025 15:13:26 -0300 Subject: [PATCH 2/6] refactor: lint and prettier and clean up IsNotBlank decorator --- src/decorator/common/IsNotBlank.ts | 17 +++++------------ .../validation-functions-and-decorators.spec.ts | 2 +- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/decorator/common/IsNotBlank.ts b/src/decorator/common/IsNotBlank.ts index c6e799d531..b1afeb8c01 100644 --- a/src/decorator/common/IsNotBlank.ts +++ b/src/decorator/common/IsNotBlank.ts @@ -1,28 +1,21 @@ import { ValidationOptions } from '../ValidationOptions'; import { buildMessage, ValidateBy } from './ValidateBy'; -export const IS_NOT_BLANK = "isNotBlank"; +export const IS_NOT_BLANK = 'isNotBlank'; export function isNotBlank(value: unknown): boolean { - return ( - !!value && typeof value === "string" && value.trim().length > 0 - ); + return !!value && typeof value === 'string' && value.trim().length > 0; } -export function IsNotBlank( - validationOptions?: ValidationOptions, -): PropertyDecorator { +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, - ), + defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property should not be blank', validationOptions), }, }, - validationOptions, + validationOptions ); } diff --git a/test/functional/validation-functions-and-decorators.spec.ts b/test/functional/validation-functions-and-decorators.spec.ts index 1c8a12359e..644d9a077f 100644 --- a/test/functional/validation-functions-and-decorators.spec.ts +++ b/test/functional/validation-functions-and-decorators.spec.ts @@ -485,7 +485,7 @@ describe('IsNotBlank', () => { const message = 'someProperty should not be blank'; return checkReturnedError(new MyClass(), invalidValues, validationType, message); }); -}) +}); describe('IsIn', () => { const constraint = ['foo', 'bar'] as const; From 70e321021d5fa5707a66759cb28c6eefc75ca156 Mon Sep 17 00:00:00 2001 From: Gabriel Logan Date: Fri, 24 Jan 2025 15:15:20 -0300 Subject: [PATCH 3/6] feat: add IsNotBlank validation to username field in Post class README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 886712dd76..bfaca1f26a 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,7 @@ import { IsInt, Length, IsEmail, + IsNotBlank, IsFQDN, IsDate, Min, @@ -83,6 +84,9 @@ export class Post { @IsEmail() email: string; + @IsNotBlank() + username: string; + @IsFQDN() site: string; From 58e908ee88f27779949308f792952312163e698d Mon Sep 17 00:00:00 2001 From: Gabriel Logan Date: Fri, 24 Jan 2025 17:13:46 -0300 Subject: [PATCH 4/6] feat: enhance IsNotBlank validation to include numbers and handle null/undefined --- src/decorator/common/IsNotBlank.ts | 21 ++++++++++++++++++- ...alidation-functions-and-decorators.spec.ts | 6 +++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/decorator/common/IsNotBlank.ts b/src/decorator/common/IsNotBlank.ts index b1afeb8c01..8c7bee9578 100644 --- a/src/decorator/common/IsNotBlank.ts +++ b/src/decorator/common/IsNotBlank.ts @@ -3,10 +3,29 @@ 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 + */ export function isNotBlank(value: unknown): boolean { - return !!value && typeof value === 'string' && value.trim().length > 0; + if (value == null) return false; // Verify if the value is null or undefined + + if (typeof value === 'string') return value.trim().length > 0; + + if (typeof value === 'number') return !isNaN(value); + + return false; // Any other type is considered invalid } +/** + * @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, empty string or NaN + */ export function IsNotBlank(validationOptions?: ValidationOptions): PropertyDecorator { return ValidateBy( { diff --git a/test/functional/validation-functions-and-decorators.spec.ts b/test/functional/validation-functions-and-decorators.spec.ts index 644d9a077f..30cc9d9160 100644 --- a/test/functional/validation-functions-and-decorators.spec.ts +++ b/test/functional/validation-functions-and-decorators.spec.ts @@ -424,7 +424,7 @@ describe('IsEmpty', () => { }); describe('IsNotEmpty', () => { - const validValues = ['a', 'abc', ' ']; + const validValues = ['a', 'abc', ' ', 0, 1]; const invalidValues = ['', undefined, null]; class MyClass { @@ -456,8 +456,8 @@ describe('IsNotEmpty', () => { }); describe('IsNotBlank', () => { - const validValues = ['a', 'abc']; - const invalidValues = ['', undefined, null, ' ']; + const validValues = ['a', 'abc', 0, 1]; + const invalidValues = ['', undefined, null, ' ', new Object()]; class MyClass { @IsNotBlank() From 33f245e9baa1d02a68614fbf30bb354077f01c2c Mon Sep 17 00:00:00 2001 From: Gabriel Logan Date: Fri, 24 Jan 2025 17:24:45 -0300 Subject: [PATCH 5/6] feat: add IsString validation to username field in Post class --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index bfaca1f26a..41a15a8a7b 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,7 @@ import { Length, IsEmail, IsNotBlank, + IsString, IsFQDN, IsDate, Min, @@ -84,6 +85,7 @@ export class Post { @IsEmail() email: string; + @IsString() @IsNotBlank() username: string; From 1bccd18118013b953e189482e4f06f316a677dc0 Mon Sep 17 00:00:00 2001 From: Gabriel Logan Date: Fri, 24 Jan 2025 17:46:03 -0300 Subject: [PATCH 6/6] feat: update IsNotBlank decorator to handle non-string values and improve validation logic --- src/decorator/common/IsNotBlank.ts | 14 +++++++++----- .../validation-functions-and-decorators.spec.ts | 4 ++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/decorator/common/IsNotBlank.ts b/src/decorator/common/IsNotBlank.ts index 8c7bee9578..0eab1cd8cf 100644 --- a/src/decorator/common/IsNotBlank.ts +++ b/src/decorator/common/IsNotBlank.ts @@ -6,15 +6,17 @@ 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; // Verify if the value is null or undefined + if (value == null) return false; if (typeof value === 'string') return value.trim().length > 0; - if (typeof value === 'number') return !isNaN(value); - - return false; // Any other type is considered invalid + return true; } /** @@ -24,7 +26,9 @@ export function isNotBlank(value: unknown): boolean { * @description * The decorator checks if the value is not blank * @description - * The value is considered blank if it is null, undefined, empty string or NaN + * 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( diff --git a/test/functional/validation-functions-and-decorators.spec.ts b/test/functional/validation-functions-and-decorators.spec.ts index 30cc9d9160..b66d1e78ff 100644 --- a/test/functional/validation-functions-and-decorators.spec.ts +++ b/test/functional/validation-functions-and-decorators.spec.ts @@ -456,8 +456,8 @@ describe('IsNotEmpty', () => { }); describe('IsNotBlank', () => { - const validValues = ['a', 'abc', 0, 1]; - const invalidValues = ['', undefined, null, ' ', new Object()]; + const validValues = ['a', 'abc', 0, 1, new Object(), [], new Date(), true, false]; + const invalidValues = ['', undefined, null, ' ']; class MyClass { @IsNotBlank()