@geekbears/gb-class-validators 0.0.21 → 0.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/eslint.config.mjs +183 -0
- package/lib/validators/index.d.ts +1 -0
- package/lib/validators/index.js +1 -0
- package/lib/validators/phone-v2.validator.d.ts +2 -0
- package/lib/validators/phone-v2.validator.js +38 -0
- package/package.json +19 -7
- package/src/__tests__/phone-validator-v2.test.ts +64 -0
- package/src/validators/index.ts +1 -0
- package/src/validators/phone-v2.validator.ts +35 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import typescriptEslint from "@typescript-eslint/eslint-plugin";
|
|
2
|
+
import globals from "globals";
|
|
3
|
+
import tsParser from "@typescript-eslint/parser";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import js from "@eslint/js";
|
|
7
|
+
import { FlatCompat } from "@eslint/eslintrc";
|
|
8
|
+
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = path.dirname(__filename);
|
|
11
|
+
const compat = new FlatCompat({
|
|
12
|
+
baseDirectory: __dirname,
|
|
13
|
+
recommendedConfig: js.configs.recommended,
|
|
14
|
+
allConfig: js.configs.all
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
export default [...compat.extends(
|
|
18
|
+
"plugin:@typescript-eslint/recommended",
|
|
19
|
+
"plugin:@typescript-eslint/recommended-requiring-type-checking",
|
|
20
|
+
"prettier",
|
|
21
|
+
), {
|
|
22
|
+
plugins: {
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
"@typescript-eslint": typescriptEslint,
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
languageOptions: {
|
|
29
|
+
globals: {
|
|
30
|
+
...globals.node,
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
parser: tsParser,
|
|
34
|
+
ecmaVersion: 5,
|
|
35
|
+
sourceType: "module",
|
|
36
|
+
|
|
37
|
+
parserOptions: {
|
|
38
|
+
project: "tsconfig.json",
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
rules: {
|
|
43
|
+
"@typescript-eslint/adjacent-overload-signatures": "error",
|
|
44
|
+
|
|
45
|
+
"@typescript-eslint/array-type": ["error", {
|
|
46
|
+
default: "array",
|
|
47
|
+
}],
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
"@typescript-eslint/consistent-type-assertions": "error",
|
|
52
|
+
"@typescript-eslint/dot-notation": "error",
|
|
53
|
+
"@typescript-eslint/explicit-function-return-type": "off",
|
|
54
|
+
"@typescript-eslint/explicit-module-boundary-types": "off",
|
|
55
|
+
"@typescript-eslint/indent": "off",
|
|
56
|
+
|
|
57
|
+
"@typescript-eslint/member-delimiter-style": ["off", {
|
|
58
|
+
multiline: {
|
|
59
|
+
delimiter: "none",
|
|
60
|
+
requireLast: true,
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
singleline: {
|
|
64
|
+
delimiter: "semi",
|
|
65
|
+
requireLast: false,
|
|
66
|
+
},
|
|
67
|
+
}],
|
|
68
|
+
|
|
69
|
+
"@typescript-eslint/naming-convention": ["error", {
|
|
70
|
+
selector: "variable",
|
|
71
|
+
format: ["camelCase", "UPPER_CASE", "PascalCase"],
|
|
72
|
+
leadingUnderscore: "allow",
|
|
73
|
+
trailingUnderscore: "forbid",
|
|
74
|
+
}],
|
|
75
|
+
|
|
76
|
+
"@typescript-eslint/no-empty-function": "error",
|
|
77
|
+
"@typescript-eslint/no-empty-interface": "error",
|
|
78
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
79
|
+
"@typescript-eslint/no-misused-new": "error",
|
|
80
|
+
"@typescript-eslint/no-namespace": "error",
|
|
81
|
+
"@typescript-eslint/no-parameter-properties": "off",
|
|
82
|
+
|
|
83
|
+
"@typescript-eslint/no-shadow": ["error", {
|
|
84
|
+
hoist: "all",
|
|
85
|
+
}],
|
|
86
|
+
|
|
87
|
+
"@typescript-eslint/no-unused-expressions": "error",
|
|
88
|
+
"@typescript-eslint/no-use-before-define": "off",
|
|
89
|
+
"@typescript-eslint/no-var-requires": "error",
|
|
90
|
+
"@typescript-eslint/prefer-for-of": "error",
|
|
91
|
+
"@typescript-eslint/prefer-function-type": "error",
|
|
92
|
+
"@typescript-eslint/prefer-namespace-keyword": "error",
|
|
93
|
+
"@typescript-eslint/quotes": "off",
|
|
94
|
+
"@typescript-eslint/semi": ["off", null],
|
|
95
|
+
|
|
96
|
+
"@typescript-eslint/triple-slash-reference": ["error", {
|
|
97
|
+
path: "always",
|
|
98
|
+
types: "prefer-import",
|
|
99
|
+
lib: "always",
|
|
100
|
+
}],
|
|
101
|
+
|
|
102
|
+
"@typescript-eslint/type-annotation-spacing": "off",
|
|
103
|
+
"@typescript-eslint/typedef": "off",
|
|
104
|
+
"@typescript-eslint/unified-signatures": "error",
|
|
105
|
+
"arrow-parens": ["off", "always"],
|
|
106
|
+
"brace-style": ["off", "off"],
|
|
107
|
+
"comma-dangle": "off",
|
|
108
|
+
complexity: "off",
|
|
109
|
+
"constructor-super": "error",
|
|
110
|
+
"dot-notation": "off",
|
|
111
|
+
"eol-last": "off",
|
|
112
|
+
eqeqeq: ["error", "smart"],
|
|
113
|
+
"guard-for-in": "error",
|
|
114
|
+
|
|
115
|
+
"id-denylist": [
|
|
116
|
+
"error",
|
|
117
|
+
"any",
|
|
118
|
+
"Number",
|
|
119
|
+
"number",
|
|
120
|
+
"String",
|
|
121
|
+
"string",
|
|
122
|
+
"Boolean",
|
|
123
|
+
"boolean",
|
|
124
|
+
"Undefined",
|
|
125
|
+
"undefined",
|
|
126
|
+
],
|
|
127
|
+
|
|
128
|
+
"id-match": "error",
|
|
129
|
+
indent: "off",
|
|
130
|
+
"linebreak-style": "off",
|
|
131
|
+
"max-classes-per-file": ["error", 1],
|
|
132
|
+
"max-len": "off",
|
|
133
|
+
"new-parens": "off",
|
|
134
|
+
"newline-per-chained-call": "off",
|
|
135
|
+
"no-bitwise": "error",
|
|
136
|
+
"no-caller": "error",
|
|
137
|
+
"no-cond-assign": "error",
|
|
138
|
+
"no-console": "error",
|
|
139
|
+
"no-debugger": "error",
|
|
140
|
+
"no-empty": "error",
|
|
141
|
+
"no-empty-function": "off",
|
|
142
|
+
"no-eval": "error",
|
|
143
|
+
"no-extra-semi": "off",
|
|
144
|
+
"no-fallthrough": "off",
|
|
145
|
+
"no-invalid-this": "off",
|
|
146
|
+
"no-irregular-whitespace": "off",
|
|
147
|
+
"no-multiple-empty-lines": "off",
|
|
148
|
+
"no-new-wrappers": "error",
|
|
149
|
+
"no-shadow": "off",
|
|
150
|
+
"no-throw-literal": "error",
|
|
151
|
+
"no-trailing-spaces": "off",
|
|
152
|
+
"no-undef-init": "error",
|
|
153
|
+
"no-underscore-dangle": "off",
|
|
154
|
+
"no-unsafe-finally": "error",
|
|
155
|
+
"no-unused-expressions": "off",
|
|
156
|
+
"no-unused-labels": "error",
|
|
157
|
+
"no-use-before-define": "off",
|
|
158
|
+
"no-var": "error",
|
|
159
|
+
"object-shorthand": "error",
|
|
160
|
+
"one-var": ["error", "never"],
|
|
161
|
+
|
|
162
|
+
"padded-blocks": ["off", {
|
|
163
|
+
blocks: "never",
|
|
164
|
+
}, {
|
|
165
|
+
allowSingleLineBlocks: true,
|
|
166
|
+
}],
|
|
167
|
+
"prefer-const": "error",
|
|
168
|
+
"quote-props": "off",
|
|
169
|
+
quotes: "off",
|
|
170
|
+
radix: "error",
|
|
171
|
+
|
|
172
|
+
semi: "off",
|
|
173
|
+
"space-before-function-paren": "off",
|
|
174
|
+
"space-in-parens": ["off", "never"],
|
|
175
|
+
|
|
176
|
+
"spaced-comment": ["error", "always", {
|
|
177
|
+
markers: ["/"],
|
|
178
|
+
}],
|
|
179
|
+
|
|
180
|
+
"use-isnan": "error",
|
|
181
|
+
"valid-typeof": "off",
|
|
182
|
+
},
|
|
183
|
+
}];
|
package/lib/validators/index.js
CHANGED
|
@@ -17,3 +17,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
17
|
__exportStar(require("./exact-match.validator"), exports);
|
|
18
18
|
__exportStar(require("./is-included-in.validator"), exports);
|
|
19
19
|
__exportStar(require("./phone.validator"), exports);
|
|
20
|
+
__exportStar(require("./phone-v2.validator"), exports);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IsGBPhoneNumberV2 = IsGBPhoneNumberV2;
|
|
4
|
+
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
5
|
+
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
|
6
|
+
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
7
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
8
|
+
const class_validator_1 = require("class-validator");
|
|
9
|
+
const google_libphonenumber_1 = require("google-libphonenumber");
|
|
10
|
+
function IsGBPhoneNumberV2(validationOptions) {
|
|
11
|
+
return function (object, propertyName) {
|
|
12
|
+
(0, class_validator_1.registerDecorator)({
|
|
13
|
+
target: object.constructor,
|
|
14
|
+
propertyName,
|
|
15
|
+
options: validationOptions,
|
|
16
|
+
constraints: [],
|
|
17
|
+
validator: {
|
|
18
|
+
validate(value, args) {
|
|
19
|
+
let isValid = false;
|
|
20
|
+
if (typeof value !== 'string')
|
|
21
|
+
return isValid;
|
|
22
|
+
const phoneUtil = google_libphonenumber_1.PhoneNumberUtil.getInstance();
|
|
23
|
+
try {
|
|
24
|
+
const parsedNumber = phoneUtil.parseAndKeepRawInput(value, '');
|
|
25
|
+
isValid = phoneUtil.isValidNumber(parsedNumber);
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
return isValid;
|
|
29
|
+
}
|
|
30
|
+
return isValid;
|
|
31
|
+
},
|
|
32
|
+
defaultMessage(args) {
|
|
33
|
+
return 'The phone number ($value) is not valid!';
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geekbears/gb-class-validators",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.23",
|
|
4
4
|
"description": "Geekbears custom validators using class-validator package.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"prebuild": "rimraf lib",
|
|
10
10
|
"build": "tsc",
|
|
11
11
|
"format": "prettier --write \"src/**/*.ts\"",
|
|
12
|
-
"lint": "
|
|
12
|
+
"lint": "eslint -c eslint.config.mjs src/*.ts --fix",
|
|
13
13
|
"prepare": "npm run build",
|
|
14
14
|
"prepublishOnly": "npm test && npm run lint",
|
|
15
15
|
"preversion": "npm run lint",
|
|
@@ -37,6 +37,10 @@
|
|
|
37
37
|
{
|
|
38
38
|
"email": "ivan@geekbears.com",
|
|
39
39
|
"name": "Ivan Rangel"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"email": "jorge.davalos@geekbears.com",
|
|
43
|
+
"name": "Jorge Dávalos"
|
|
40
44
|
}
|
|
41
45
|
],
|
|
42
46
|
"license": "MIT",
|
|
@@ -45,19 +49,27 @@
|
|
|
45
49
|
},
|
|
46
50
|
"homepage": "https://gitlab.com/geekbears/utilities/backend/gb-class-validators#readme",
|
|
47
51
|
"devDependencies": {
|
|
48
|
-
"@
|
|
49
|
-
"@
|
|
52
|
+
"@eslint/eslintrc": "^3.2.0",
|
|
53
|
+
"@eslint/js": "^9.15.0",
|
|
54
|
+
"@types/google-libphonenumber": "^7.4.30",
|
|
55
|
+
"@types/jest": "^29.5.14",
|
|
56
|
+
"@types/lodash": "^4.17.13",
|
|
50
57
|
"@types/validator": "^13.12.2",
|
|
58
|
+
"@typescript-eslint/eslint-plugin": "^8.16.0",
|
|
59
|
+
"@typescript-eslint/parser": "^8.15.0",
|
|
60
|
+
"eslint": "^9.15.0",
|
|
61
|
+
"eslint-config-prettier": "^9.1.0",
|
|
62
|
+
"eslint-plugin-prettier": "^5.2.1",
|
|
63
|
+
"globals": "^15.12.0",
|
|
51
64
|
"jest": "^29.7.0",
|
|
52
65
|
"prettier": "^3.3.3",
|
|
53
66
|
"rimraf": "^6.0.1",
|
|
54
67
|
"ts-jest": "^29.2.5",
|
|
55
|
-
"
|
|
56
|
-
"tslint-config-prettier": "^1.18.0",
|
|
57
|
-
"typescript": "^5.6.2"
|
|
68
|
+
"typescript": "^5.7.2"
|
|
58
69
|
},
|
|
59
70
|
"dependencies": {
|
|
60
71
|
"class-validator": "^0.14.1",
|
|
72
|
+
"google-libphonenumber": "^3.2.39",
|
|
61
73
|
"lodash": "^4.17.21"
|
|
62
74
|
}
|
|
63
75
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Validator } from 'class-validator';
|
|
2
|
+
import { IsGBPhoneNumberV2 } from '../validators';
|
|
3
|
+
|
|
4
|
+
class TestClass {
|
|
5
|
+
@IsGBPhoneNumberV2()
|
|
6
|
+
phone: any;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
describe('Phone Validator V2', () => {
|
|
10
|
+
let validator: Validator;
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
validator = new Validator();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test('should fail when not a string', async () => {
|
|
17
|
+
const model = new TestClass();
|
|
18
|
+
model.phone = 98234;
|
|
19
|
+
const errors = await validator.validate(model);
|
|
20
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('should fail when providing a non-international phone number (missing country code)', async () => {
|
|
24
|
+
const model = new TestClass();
|
|
25
|
+
model.phone = '2025550115';
|
|
26
|
+
const errors = await validator.validate(model);
|
|
27
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('should fail when providing an invalid phone number (incorrect format)', async () => {
|
|
31
|
+
const model = new TestClass();
|
|
32
|
+
model.phone = '98234';
|
|
33
|
+
const errors = await validator.validate(model);
|
|
34
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('should fail when providing a phone number with an invalid country code', async () => {
|
|
38
|
+
const model = new TestClass();
|
|
39
|
+
model.phone = '+535522626391';
|
|
40
|
+
const errors = await validator.validate(model);
|
|
41
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('should pass when providing a valid phone number with an international code', async () => {
|
|
45
|
+
const model = new TestClass();
|
|
46
|
+
model.phone = '+44 7911 123456';
|
|
47
|
+
const errors = await validator.validate(model);
|
|
48
|
+
expect(errors.length).toEqual(0);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("should fail when providing a phone number that can't be parsed by google-libphonenumber", async () => {
|
|
52
|
+
const model = new TestClass();
|
|
53
|
+
model.phone = '+12345';
|
|
54
|
+
const errors = await validator.validate(model);
|
|
55
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('should fail when providing an incomplete phone number', async () => {
|
|
59
|
+
const model = new TestClass();
|
|
60
|
+
model.phone = '+44 791';
|
|
61
|
+
const errors = await validator.validate(model);
|
|
62
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
63
|
+
});
|
|
64
|
+
});
|
package/src/validators/index.ts
CHANGED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
4
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
5
|
+
import { ValidationOptions, registerDecorator, ValidationArguments } from 'class-validator';
|
|
6
|
+
import { PhoneNumberUtil } from 'google-libphonenumber';
|
|
7
|
+
|
|
8
|
+
export function IsGBPhoneNumberV2(validationOptions?: ValidationOptions) {
|
|
9
|
+
return function (object: object, propertyName: string) {
|
|
10
|
+
registerDecorator({
|
|
11
|
+
target: object.constructor,
|
|
12
|
+
propertyName,
|
|
13
|
+
options: validationOptions,
|
|
14
|
+
constraints: [],
|
|
15
|
+
validator: {
|
|
16
|
+
validate(value: any, args: ValidationArguments) {
|
|
17
|
+
let isValid = false;
|
|
18
|
+
if (typeof value !== 'string') return isValid;
|
|
19
|
+
const phoneUtil = PhoneNumberUtil.getInstance();
|
|
20
|
+
try {
|
|
21
|
+
const parsedNumber = phoneUtil.parseAndKeepRawInput(value, '');
|
|
22
|
+
isValid = phoneUtil.isValidNumber(parsedNumber);
|
|
23
|
+
} catch (error) {
|
|
24
|
+
return isValid;
|
|
25
|
+
}
|
|
26
|
+
return isValid;
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
defaultMessage(args: ValidationArguments) {
|
|
30
|
+
return 'The phone number ($value) is not valid!';
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
}
|