Skip to content
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ import {
IsInt,
Length,
IsEmail,
IsNotBlank,
IsString,
IsFQDN,
IsDate,
Min,
Expand All @@ -83,6 +85,10 @@ export class Post {
@IsEmail()
email: string;

@IsString()
@IsNotBlank()
username: string;

@IsFQDN()
site: string;

Expand Down
44 changes: 44 additions & 0 deletions src/decorator/common/IsNotBlank.ts
Original file line number Diff line number Diff line change
@@ -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
);
}
1 change: 1 addition & 0 deletions src/decorator/decorators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down
36 changes: 35 additions & 1 deletion test/functional/validation-functions-and-decorators.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ import {
notEquals,
isEmpty,
isNotEmpty,
IsNotBlank,
isNotBlank,
isIn,
isNotIn,
isDateString,
Expand Down Expand Up @@ -422,7 +424,7 @@ describe('IsEmpty', () => {
});

describe('IsNotEmpty', () => {
const validValues = ['a', 'abc'];
const validValues = ['a', 'abc', ' ', 0, 1];
const invalidValues = ['', undefined, null];

class MyClass {
Expand Down Expand Up @@ -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'];
Expand Down