express-generator-typescript 2.1.1 → 2.1.3
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/lib/project-files/spec/tests/users.spec.ts +17 -5
- package/lib/project-files/src/models/user-model.ts +5 -1
- package/lib/project-files/src/routes/auth-router.ts +14 -10
- package/lib/project-files/src/routes/middleware.ts +106 -3
- package/lib/project-files/src/routes/user-router.ts +26 -19
- package/lib/project-files/src/services/auth-service.ts +2 -2
- package/lib/project-files/src/shared/errors.ts +2 -13
- package/lib/project-files/src/shared/types.ts +5 -0
- package/package.json +1 -1
- package/lib/project-files/src/routes/validators.ts +0 -63
|
@@ -9,7 +9,8 @@ import User, { IUser } from '@models/user-model';
|
|
|
9
9
|
|
|
10
10
|
import { p as userPaths } from '@routes/user-router';
|
|
11
11
|
import {
|
|
12
|
-
|
|
12
|
+
ParamInvalidError,
|
|
13
|
+
// ParamMissingError,
|
|
13
14
|
UserNotFoundError,
|
|
14
15
|
ValidatorFnError,
|
|
15
16
|
} from '@shared/errors';
|
|
@@ -47,15 +48,15 @@ const msgs = {
|
|
|
47
48
|
addUserSuccess: `should return a status code of "${CREATED}" if the request
|
|
48
49
|
was successful.`,
|
|
49
50
|
addUserFailedMissingParam: `should return a JSON object with an error
|
|
50
|
-
message of "${
|
|
51
|
-
if the user param was missing.`,
|
|
51
|
+
message of "${ValidatorFnError.Msg + 'instanceOf'}" and a status code
|
|
52
|
+
of "${BAD_REQUEST}" if the user param was missing.`,
|
|
52
53
|
addUserFallbackErr: `should return a JSON object with an error message and a
|
|
53
54
|
status code of "${BAD_REQUEST}" if the request was unsuccessful.`,
|
|
54
55
|
updateSuccess: `should return a status code of "${OK}" if the request was
|
|
55
56
|
successful.`,
|
|
56
57
|
updateParamMissing: `should return a JSON object with an error message of
|
|
57
|
-
"${
|
|
58
|
-
user param was missing.`,
|
|
58
|
+
"${ValidatorFnError.Msg + 'instanceOf'}" and a status code of
|
|
59
|
+
"${BAD_REQUEST}" if the user param was missing.`,
|
|
59
60
|
updateUserNotFound: `should return a JSON object with the error message of
|
|
60
61
|
${UserNotFoundError.Msg} and a status code of
|
|
61
62
|
"${UserNotFoundError.HttpStatus}" if the id was not found.`,
|
|
@@ -274,6 +275,17 @@ describe('user-router', () => {
|
|
|
274
275
|
});
|
|
275
276
|
});
|
|
276
277
|
|
|
278
|
+
// Delete, not a valid number error
|
|
279
|
+
it(msgs.deleteUserNotFound, (done) => {
|
|
280
|
+
callApi('horse' as unknown as number)
|
|
281
|
+
.end((err: Error, res: Response) => {
|
|
282
|
+
!!err && logger.err(err);
|
|
283
|
+
expect(res.status).toBe(ParamInvalidError.HttpStatus);
|
|
284
|
+
expect(res.body.error).toBe(ParamInvalidError.Msg);
|
|
285
|
+
done();
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
|
|
277
289
|
// Delete user fallback error
|
|
278
290
|
it(msgs.deleteFallbackErr, (done) => {
|
|
279
291
|
spyOn(userRepo, 'persists').and.returnValue(Promise.resolve(true));
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { TAll } from '@shared/types';
|
|
2
|
+
|
|
3
|
+
|
|
1
4
|
// **** Variables **** //
|
|
2
5
|
|
|
3
6
|
export enum UserRoles {
|
|
@@ -53,8 +56,9 @@ function copy(user: IUser): IUser {
|
|
|
53
56
|
/**
|
|
54
57
|
* See if an object is an instance of User.
|
|
55
58
|
*/
|
|
56
|
-
function instanceOf(arg:
|
|
59
|
+
function instanceOf(arg: TAll): boolean {
|
|
57
60
|
return (
|
|
61
|
+
!!arg &&
|
|
58
62
|
typeof arg === 'object' &&
|
|
59
63
|
'id' in arg &&
|
|
60
64
|
'email' in arg &&
|
|
@@ -4,7 +4,7 @@ import StatusCodes from 'http-status-codes';
|
|
|
4
4
|
import authService from '@services/auth-service';
|
|
5
5
|
import envVars from 'src/shared/env-vars';
|
|
6
6
|
import { IReq, IRes } from '@shared/types';
|
|
7
|
-
import
|
|
7
|
+
import { vld } from './middleware';
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
// **** Types **** //
|
|
@@ -17,8 +17,6 @@ interface ILoginReq {
|
|
|
17
17
|
|
|
18
18
|
// **** Variables **** //
|
|
19
19
|
|
|
20
|
-
const router = Router();
|
|
21
|
-
|
|
22
20
|
// Status codes
|
|
23
21
|
const { OK } = StatusCodes;
|
|
24
22
|
|
|
@@ -30,30 +28,36 @@ export const p = {
|
|
|
30
28
|
} as const;
|
|
31
29
|
|
|
32
30
|
|
|
33
|
-
// ****
|
|
31
|
+
// **** Setup Router **** //
|
|
32
|
+
|
|
33
|
+
const router = Router();
|
|
34
|
+
router.post(p.login, vld('email', 'password'), login);
|
|
35
|
+
router.get(p.logout, logout);
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
// **** Functions **** //
|
|
34
39
|
|
|
35
40
|
/**
|
|
36
41
|
* Login a user.
|
|
37
42
|
*/
|
|
38
|
-
|
|
43
|
+
async function login(req: IReq<ILoginReq>, res: IRes) {
|
|
39
44
|
const { email, password } = req.body;
|
|
40
|
-
validate(email, password);
|
|
41
45
|
// Add jwt to cookie
|
|
42
|
-
const jwt = await authService.
|
|
46
|
+
const jwt = await authService.getJwt(email, password);
|
|
43
47
|
const { key, options } = envVars.cookieProps;
|
|
44
48
|
res.cookie(key, jwt, options);
|
|
45
49
|
// Return
|
|
46
50
|
return res.status(OK).end();
|
|
47
|
-
}
|
|
51
|
+
}
|
|
48
52
|
|
|
49
53
|
/**
|
|
50
54
|
* Logout the user.
|
|
51
55
|
*/
|
|
52
|
-
|
|
56
|
+
function logout(_: IReq, res: IRes) {
|
|
53
57
|
const { key, options } = envVars.cookieProps;
|
|
54
58
|
res.clearCookie(key, options);
|
|
55
59
|
return res.status(OK).end();
|
|
56
|
-
}
|
|
60
|
+
}
|
|
57
61
|
|
|
58
62
|
|
|
59
63
|
// **** Export router **** //
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import StatusCodes from 'http-status-codes';
|
|
2
|
-
import { Request, Response, NextFunction } from 'express';
|
|
2
|
+
import { Request, Response, NextFunction, RequestHandler } from 'express';
|
|
3
3
|
import { JwtPayload } from 'jsonwebtoken';
|
|
4
4
|
|
|
5
|
-
import { IUser, UserRoles } from '@models/user-model';
|
|
6
5
|
import envVars from 'src/shared/env-vars';
|
|
7
6
|
import jwtUtil from '@util/jwt-util';
|
|
7
|
+
import { IUser, UserRoles } from '@models/user-model';
|
|
8
|
+
import { ParamInvalidError, ValidatorFnError } from '@shared/errors';
|
|
9
|
+
import { TAll } from '@shared/types';
|
|
8
10
|
|
|
9
11
|
|
|
10
12
|
// **** Variables **** //
|
|
@@ -15,6 +17,13 @@ const jwtNotPresentErr = 'JWT not present in signed cookie.';
|
|
|
15
17
|
|
|
16
18
|
// **** Types **** //
|
|
17
19
|
|
|
20
|
+
type TValidatorFn = ((arg: TAll) => boolean);
|
|
21
|
+
type TParamArr = {
|
|
22
|
+
0: string,
|
|
23
|
+
1?: string | TValidatorFn,
|
|
24
|
+
2?: 'body' | 'query' | 'params',
|
|
25
|
+
}
|
|
26
|
+
|
|
18
27
|
export interface ISessionUser extends JwtPayload {
|
|
19
28
|
id: number;
|
|
20
29
|
email: string;
|
|
@@ -28,7 +37,11 @@ export interface ISessionUser extends JwtPayload {
|
|
|
28
37
|
/**
|
|
29
38
|
* Middleware to verify if user logged in.
|
|
30
39
|
*/
|
|
31
|
-
export async function adminMw(
|
|
40
|
+
export async function adminMw(
|
|
41
|
+
req: Request,
|
|
42
|
+
res: Response,
|
|
43
|
+
next: NextFunction,
|
|
44
|
+
) {
|
|
32
45
|
try {
|
|
33
46
|
// Extract the token
|
|
34
47
|
const cookieName = envVars.cookieProps.key,
|
|
@@ -55,3 +68,93 @@ export async function adminMw(req: Request, res: Response, next: NextFunction) {
|
|
|
55
68
|
}
|
|
56
69
|
}
|
|
57
70
|
|
|
71
|
+
/**
|
|
72
|
+
* vld stands for 'validate'. This function returns a middleware-function
|
|
73
|
+
* that validates the parameters provided. Each argument can be a string or
|
|
74
|
+
* array. If an array the format is:
|
|
75
|
+
*
|
|
76
|
+
* ['paramName', '(optional) type or validator function (default is string)',
|
|
77
|
+
* '(optional) property on "req" to extract the value from (default is body')]
|
|
78
|
+
*
|
|
79
|
+
* If a string, vld makes sure the param is of type string on req.body. For
|
|
80
|
+
* the array, vld makes sure parameter is of the specified type or that the
|
|
81
|
+
* parameter satifies the validator function. The validator function must
|
|
82
|
+
* return 'true' or 'false'.
|
|
83
|
+
*
|
|
84
|
+
* **NOTE**: For numbers, strings which evalute to (!isNaN('string') => true)
|
|
85
|
+
* are valid for req.query and req.params. But on req.body a number should be
|
|
86
|
+
* 'typeof toCheck === "number"'
|
|
87
|
+
*
|
|
88
|
+
* Sample argument: ['id', 'number'], id is the incoming variable, 'number'
|
|
89
|
+
* is the type, and body is where to extract 'id' from.
|
|
90
|
+
*
|
|
91
|
+
* Example 1: vld('email', ['user', 'object'], ['id', 'number', 'params']) |
|
|
92
|
+
* will check that 'email' is a string in req.body, that user is of type
|
|
93
|
+
* object in req.body, and that 'id' is a boolean in req.params.
|
|
94
|
+
* Example 2: vld('password') | will check that 'password' is a string on
|
|
95
|
+
* req.body.
|
|
96
|
+
* Example 3: vld(['isAdmin', 'boolean']) | will check that 'isAdmin' is a
|
|
97
|
+
* boolean on req.body
|
|
98
|
+
* Example 4: vld(['user', isInstanceOfUser]) | will check that 'user'
|
|
99
|
+
* satifies the 'isInstanceOfUser()' function.
|
|
100
|
+
* Example 5: val(['email']), will check that 'email' is a string in req.body,
|
|
101
|
+
*/
|
|
102
|
+
export function vld(...params: Array<string | TParamArr>): RequestHandler {
|
|
103
|
+
return (req: Request, _: Response, next: NextFunction) => {
|
|
104
|
+
for (const param of params) {
|
|
105
|
+
// Check params
|
|
106
|
+
if (typeof param !== 'string' && !(param instanceof Array)) {
|
|
107
|
+
throw Error('vld() arg must be a string or array');
|
|
108
|
+
}
|
|
109
|
+
// If param is a string, make sure param is of type string on req.body
|
|
110
|
+
if (typeof param === 'string') {
|
|
111
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
112
|
+
if (typeof req.body[param] !== 'string') {
|
|
113
|
+
throw new ParamInvalidError();
|
|
114
|
+
}
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
// Get the value to validate from the express Request object.
|
|
118
|
+
const paramName = param[0];
|
|
119
|
+
const reqObjProp = (param.length >= 3 ? param[2] : 'body');
|
|
120
|
+
// Validate request object property
|
|
121
|
+
if (
|
|
122
|
+
reqObjProp !== 'body' &&
|
|
123
|
+
reqObjProp !== 'params' &&
|
|
124
|
+
reqObjProp !== 'query'
|
|
125
|
+
) {
|
|
126
|
+
throw Error('param[1] must be "body", "query", or "params"');
|
|
127
|
+
}
|
|
128
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
129
|
+
const toValidate = req[reqObjProp][paramName] as TAll;
|
|
130
|
+
// If type is not present, check it's a string by default
|
|
131
|
+
if (param.length === 1) {
|
|
132
|
+
if (typeof toValidate !== 'string') {
|
|
133
|
+
throw new ParamInvalidError();
|
|
134
|
+
}
|
|
135
|
+
// If a validator function is given, validate it with that
|
|
136
|
+
} else if (typeof param[1] === 'function') {
|
|
137
|
+
const fn = param[1];
|
|
138
|
+
if (!fn(toValidate)) {
|
|
139
|
+
throw new ValidatorFnError(fn.name);
|
|
140
|
+
}
|
|
141
|
+
// If type is a number, need to do isNaN() to account for
|
|
142
|
+
// number-strings (i.e. '1243') in req.query or req.params. But in
|
|
143
|
+
// req.body, numbers should be 'typeof toCheck === "number"'
|
|
144
|
+
} else if (param[1] === 'number') {
|
|
145
|
+
if (reqObjProp === 'query' || reqObjProp === 'params') {
|
|
146
|
+
if (isNaN(toValidate as number)) {
|
|
147
|
+
throw new ParamInvalidError();
|
|
148
|
+
}
|
|
149
|
+
} else if (typeof toValidate !== 'number') {
|
|
150
|
+
throw new ParamInvalidError();
|
|
151
|
+
}
|
|
152
|
+
// Check the param is the provided type
|
|
153
|
+
} else if (typeof toValidate !== param[1]) {
|
|
154
|
+
throw new ParamInvalidError();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// Call next() if no errors thrown
|
|
158
|
+
next();
|
|
159
|
+
};
|
|
160
|
+
}
|
|
@@ -4,14 +4,14 @@ import { Router } from 'express';
|
|
|
4
4
|
import userService from '@services/user-service';
|
|
5
5
|
import User, { IUser } from '@models/user-model';
|
|
6
6
|
import { IReq, IRes } from '@shared/types';
|
|
7
|
-
import
|
|
7
|
+
import { vld } from './middleware';
|
|
8
|
+
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
// **** Variables **** //
|
|
11
12
|
|
|
12
13
|
// Misc
|
|
13
|
-
const
|
|
14
|
-
{ CREATED, OK } = StatusCodes;
|
|
14
|
+
const { CREATED, OK } = StatusCodes;
|
|
15
15
|
|
|
16
16
|
// Paths
|
|
17
17
|
export const p = {
|
|
@@ -23,48 +23,55 @@ export const p = {
|
|
|
23
23
|
} as const;
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
// ****
|
|
26
|
+
// **** Setup Router **** //
|
|
27
|
+
|
|
28
|
+
// Validators (place shared or really long ones here)
|
|
29
|
+
const validateUser = vld(['user', User.instanceOf]);
|
|
30
|
+
|
|
31
|
+
// Add routes to express
|
|
32
|
+
const router = Router();
|
|
33
|
+
router.get(p.get, getAll);
|
|
34
|
+
router.post(p.add, validateUser, add);
|
|
35
|
+
router.put(p.update, validateUser, update);
|
|
36
|
+
router.delete(p.delete, vld(['id', 'number', 'params']), _delete);
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
// **** Functions **** //
|
|
27
40
|
|
|
28
41
|
/**
|
|
29
42
|
* Get all users.
|
|
30
43
|
*/
|
|
31
|
-
|
|
44
|
+
async function getAll(_: IReq, res: IRes) {
|
|
32
45
|
const users = await userService.getAll();
|
|
33
46
|
return res.status(OK).json({ users });
|
|
34
|
-
}
|
|
47
|
+
}
|
|
35
48
|
|
|
36
49
|
/**
|
|
37
50
|
* Add one user.
|
|
38
51
|
*/
|
|
39
|
-
|
|
52
|
+
async function add(req: IReq<{user: IUser}>, res: IRes) {
|
|
40
53
|
const { user } = req.body;
|
|
41
|
-
validate([user, User.instanceOf]);
|
|
42
|
-
// Add user
|
|
43
54
|
await userService.addOne(user);
|
|
44
55
|
return res.status(CREATED).end();
|
|
45
|
-
}
|
|
56
|
+
}
|
|
46
57
|
|
|
47
58
|
/**
|
|
48
59
|
* Update one user.
|
|
49
60
|
*/
|
|
50
|
-
|
|
61
|
+
async function update(req: IReq<{user: IUser}>, res: IRes) {
|
|
51
62
|
const { user } = req.body;
|
|
52
|
-
validate([user, User.instanceOf]);
|
|
53
|
-
// Edit user
|
|
54
63
|
await userService.updateOne(user);
|
|
55
64
|
return res.status(OK).end();
|
|
56
|
-
}
|
|
65
|
+
}
|
|
57
66
|
|
|
58
67
|
/**
|
|
59
68
|
* Delete one user.
|
|
60
69
|
*/
|
|
61
|
-
|
|
62
|
-
const id =
|
|
63
|
-
validate([id, 'number']);
|
|
64
|
-
// Delete user
|
|
70
|
+
async function _delete(req: IReq, res: IRes) {
|
|
71
|
+
const id = +req.params.id;
|
|
65
72
|
await userService.delete(id);
|
|
66
73
|
return res.status(OK).end();
|
|
67
|
-
}
|
|
74
|
+
}
|
|
68
75
|
|
|
69
76
|
|
|
70
77
|
// **** Export default **** //
|
|
@@ -10,7 +10,7 @@ import { UnauthorizedError } from '@shared/errors';
|
|
|
10
10
|
/**
|
|
11
11
|
* Login a user.
|
|
12
12
|
*/
|
|
13
|
-
async function
|
|
13
|
+
async function getJwt(email: string, password: string): Promise<string> {
|
|
14
14
|
// Fetch user
|
|
15
15
|
const user = await userRepo.getOne(email);
|
|
16
16
|
if (!user) {
|
|
@@ -35,5 +35,5 @@ async function login(email: string, password: string): Promise<string> {
|
|
|
35
35
|
// **** Export default **** //
|
|
36
36
|
|
|
37
37
|
export default {
|
|
38
|
-
|
|
38
|
+
getJwt,
|
|
39
39
|
} as const;
|
|
@@ -11,17 +11,6 @@ export abstract class CustomError extends Error {
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
export class ParamMissingError extends CustomError {
|
|
15
|
-
|
|
16
|
-
public static readonly Msg = 'One or more of the required parameters ' +
|
|
17
|
-
'was missing.';
|
|
18
|
-
public static readonly HttpStatus = HttpStatusCodes.BAD_REQUEST;
|
|
19
|
-
|
|
20
|
-
constructor() {
|
|
21
|
-
super(ParamMissingError.Msg, ParamMissingError.HttpStatus);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
14
|
export class ParamInvalidError extends CustomError {
|
|
26
15
|
|
|
27
16
|
public static readonly Msg = 'One or more of the required was missing ' +
|
|
@@ -29,7 +18,7 @@ export class ParamInvalidError extends CustomError {
|
|
|
29
18
|
public static readonly HttpStatus = HttpStatusCodes.BAD_REQUEST;
|
|
30
19
|
|
|
31
20
|
constructor() {
|
|
32
|
-
super(ParamInvalidError.Msg,
|
|
21
|
+
super(ParamInvalidError.Msg, ParamInvalidError.HttpStatus);
|
|
33
22
|
}
|
|
34
23
|
}
|
|
35
24
|
|
|
@@ -39,7 +28,7 @@ export class ValidatorFnError extends CustomError {
|
|
|
39
28
|
public static readonly HttpStatus = HttpStatusCodes.BAD_REQUEST;
|
|
40
29
|
|
|
41
30
|
constructor(fnName: string) {
|
|
42
|
-
super(ValidatorFnError.Msg + fnName,
|
|
31
|
+
super(ValidatorFnError.Msg + fnName, ValidatorFnError.HttpStatus);
|
|
43
32
|
}
|
|
44
33
|
}
|
|
45
34
|
|
|
@@ -4,6 +4,11 @@ import { Query } from 'express-serve-static-core';
|
|
|
4
4
|
import { ISessionUser } from '@routes/middleware';
|
|
5
5
|
|
|
6
6
|
|
|
7
|
+
// **** Misc **** //
|
|
8
|
+
|
|
9
|
+
export type TAll = string | number | boolean | null | object;
|
|
10
|
+
|
|
11
|
+
|
|
7
12
|
// **** Express **** //
|
|
8
13
|
|
|
9
14
|
export interface IReq<T = void> extends e.Request {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "express-generator-typescript",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.3",
|
|
4
4
|
"description": "Generate new Express applications similar to express-generate which but sets it up to use TypeScript instead",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"express-generator-typescript": "node bin/cli.js",
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Put other validator functions here too that may be passed to the validate()
|
|
3
|
-
* function.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { ParamInvalidError, ValidatorFnError } from '@shared/errors';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
// **** Types **** //
|
|
10
|
-
|
|
11
|
-
type TParam = string | number | boolean | null | object;
|
|
12
|
-
type TValidatorFn = ((arg: TParam) => boolean);
|
|
13
|
-
type TParamFull = TParam | TValidatorFn;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
// **** Functions **** //
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Make sure parameter is of the specified type. If the type is not provided
|
|
20
|
-
* then 'string' is used as the default type. Instead of a type you can also
|
|
21
|
-
* pass a validator function which must return 'true' or 'false'. Return false
|
|
22
|
-
* if invalid.
|
|
23
|
-
*
|
|
24
|
-
* Example argument: [id, 'number'], id is the incoming variable, 'number' is
|
|
25
|
-
* the type.
|
|
26
|
-
*
|
|
27
|
-
* Example 1: validate(email, [user, 'object'], [isAdmin, 'boolean'])
|
|
28
|
-
* Example 2: validate(password) // will check that password is a string
|
|
29
|
-
* Example 3: validate([isAdmin, 'boolean'])
|
|
30
|
-
* Example 4: validate([user, isInstanceOfUser])
|
|
31
|
-
*/
|
|
32
|
-
function validate(...params: Array<TParam | TParamFull[]>): void {
|
|
33
|
-
for (const param of params) {
|
|
34
|
-
// If param is array check provided type
|
|
35
|
-
if (param instanceof Array) {
|
|
36
|
-
// Validator function provided
|
|
37
|
-
if (typeof param[1] === 'function') {
|
|
38
|
-
const fn = param[1];
|
|
39
|
-
if (!fn(param[0])) {
|
|
40
|
-
throw new ValidatorFnError(fn.name);
|
|
41
|
-
}
|
|
42
|
-
// If type is a number, need to do isNaN, cause type NaN is a 'number'.
|
|
43
|
-
// This could be an issue if you do Number(undefined)
|
|
44
|
-
} else if (param[1] === 'number') {
|
|
45
|
-
if (isNaN(param[0] as number)) {
|
|
46
|
-
throw new ParamInvalidError();
|
|
47
|
-
}
|
|
48
|
-
} else if (typeof param[0] !== param[1]) {
|
|
49
|
-
throw new ParamInvalidError();
|
|
50
|
-
}
|
|
51
|
-
// String is default if type is not provided
|
|
52
|
-
} else {
|
|
53
|
-
if (typeof param !== 'string') {
|
|
54
|
-
throw new ParamInvalidError();
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
// **** Export default **** //
|
|
62
|
-
|
|
63
|
-
export default validate;
|