Skip to content

Commit a78c7ee

Browse files
author
Ballinette
committed
Add IsIpRange validator (fix #727)
1 parent 63fe9c5 commit a78c7ee

File tree

4 files changed

+101
-0
lines changed

4 files changed

+101
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,7 @@ isBoolean(value);
860860
| `@IsOctal()` | Checks if the string is a octal number. |
861861
| `@IsMACAddress(options?: IsMACAddressOptions)` | Checks if the string is a MAC Address. |
862862
| `@IsIP(version?: "4"\|"6")` | Checks if the string is an IP (version 4 or 6). |
863+
| `@IsIPRange(version?: "4"\|"6")` | Checks if the string is an IP Range (version 4 or 6). |
863864
| `@IsPort()` | Checks if the string is a valid port number. |
864865
| `@IsISBN(version?: "10"\|"13")` | Checks if the string is an ISBN (version 10 or 13). |
865866
| `@IsEAN()` | Checks if the string is an if the string is an EAN (European Article Number). |

src/decorator/decorators.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export * from './string/IsHexColor';
6464
export * from './string/IsHexadecimal';
6565
export * from './string/IsMacAddress';
6666
export * from './string/IsIP';
67+
export * from './string/IsIPRange';
6768
export * from './string/IsPort';
6869
export * from './string/IsISBN';
6970
export * from './string/IsISIN';

src/decorator/string/IsIPRange.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { ValidationOptions } from '../ValidationOptions';
2+
import { buildMessage, ValidateBy } from '../common/ValidateBy';
3+
import isIPRangeValidator from 'validator/lib/isIPRange';
4+
5+
export type IsIpRangeVersion = '4' | '6' | 4 | 6;
6+
7+
export const IS_IP_RANGE = 'isIpRange';
8+
9+
/**
10+
* Checks if the string is an IP Range (version 4 or 6).
11+
* If given value is not a string, then it returns false.
12+
*/
13+
export function isIPRange(value: unknown, version?: IsIpRangeVersion): boolean {
14+
/* eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion */
15+
const versionStr = version ? (`${version}` as '4' | '6') : undefined;
16+
return typeof value === 'string' && isIPRangeValidator(value, versionStr);
17+
}
18+
19+
/**
20+
* Checks if the string is an IP Range (version 4 or 6).
21+
* If given value is not a string, then it returns false.
22+
*/
23+
export function IsIPRange(version?: IsIpRangeVersion, validationOptions?: ValidationOptions): PropertyDecorator {
24+
return ValidateBy(
25+
{
26+
name: IS_IP_RANGE,
27+
constraints: [version],
28+
validator: {
29+
validate: (value, args): boolean => isIP(value, args?.constraints[0]),
30+
defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be an ip range', validationOptions),
31+
},
32+
},
33+
validationOptions
34+
);
35+
}

test/functional/validation-functions-and-decorators.spec.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929
IsHexColor,
3030
IsHexadecimal,
3131
IsIP,
32+
IsIPRange,
3233
IsISBN,
3334
IsISO8601,
3435
IsIn,
@@ -108,6 +109,7 @@ import {
108109
isISBN,
109110
isISO8601,
110111
isIP,
112+
isIPRange,
111113
isJSON,
112114
isJWT,
113115
isLowercase,
@@ -2857,6 +2859,68 @@ describe('IsIP', () => {
28572859
});
28582860
});
28592861

2862+
describe('IsIPRange', () => {
2863+
const validValues = [
2864+
'127.0.0.1/24',
2865+
'0.0.0.0/0',
2866+
'255.255.255.0/32',
2867+
'::/0',
2868+
'::/128',
2869+
'2001::/128',
2870+
'2001:800::/128',
2871+
'::ffff:127.0.0.1/128',
2872+
];
2873+
const invalidValues = [
2874+
null,
2875+
undefined,
2876+
'abc',
2877+
'127.200.230.1/35',
2878+
'127.200.230.1/-1',
2879+
'1.1.1.1/011',
2880+
'1.1.1/24.1',
2881+
'1.1.1.1/01',
2882+
'1.1.1.1/1.1',
2883+
'1.1.1.1/1.',
2884+
'1.1.1.1/1/1',
2885+
'1.1.1.1',
2886+
'::1',
2887+
'::1/164',
2888+
'2001::/240',
2889+
'2001::/-1',
2890+
'2001::/001',
2891+
'2001::/24.1',
2892+
'2001:db8:0000:1:1:1:1:1',
2893+
'::ffff:127.0.0.1',
2894+
];
2895+
2896+
class MyClass {
2897+
@IsIP()
2898+
someProperty: string;
2899+
}
2900+
2901+
it('should not fail if validator.validate said that its valid', () => {
2902+
return checkValidValues(new MyClass(), validValues);
2903+
});
2904+
2905+
it('should fail if validator.validate said that its invalid', () => {
2906+
return checkInvalidValues(new MyClass(), invalidValues);
2907+
});
2908+
2909+
it('should not fail if method in validator said that its valid', () => {
2910+
validValues.forEach(value => expect(isIPRange(value)).toBeTruthy());
2911+
});
2912+
2913+
it('should fail if method in validator said that its invalid', () => {
2914+
invalidValues.forEach(value => expect(isIPRange(value)).toBeFalsy());
2915+
});
2916+
2917+
it('should return error object with proper data', () => {
2918+
const validationType = 'isIpRange';
2919+
const message = 'someProperty must be an ip range';
2920+
return checkReturnedError(new MyClass(), invalidValues, validationType, message);
2921+
});
2922+
});
2923+
28602924
describe('IsISBN version 10', () => {
28612925
const validValues = [
28622926
'3836221195',

0 commit comments

Comments
 (0)