express-generator-typescript 2.5.17 → 2.5.19
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/package.json +1 -1
- package/lib/project-files/spec/support/index.ts +17 -0
- package/lib/project-files/spec/tests/users.spec.ts +15 -14
- package/lib/project-files/src/common/route-errors.ts +19 -1
- package/lib/project-files/src/models/User.ts +21 -16
- package/lib/project-files/src/repos/database.test.json +1 -1
- package/lib/project-files/src/routes/common/index.ts +15 -41
- package/lib/project-files/src/util/validators.ts +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Response } from 'supertest';
|
|
2
2
|
import UserRepo from '@src/repos/UserRepo';
|
|
3
|
+
import { IParseObjectError, parseJson } from 'jet-validators/utils';
|
|
4
|
+
import { isString } from 'jet-validators';
|
|
3
5
|
|
|
4
6
|
|
|
5
7
|
/******************************************************************************
|
|
@@ -16,6 +18,11 @@ interface IErrObj {
|
|
|
16
18
|
[key: string]: unknown;
|
|
17
19
|
}
|
|
18
20
|
|
|
21
|
+
interface IValidationErr {
|
|
22
|
+
message: string;
|
|
23
|
+
errors: IParseObjectError[];
|
|
24
|
+
}
|
|
25
|
+
|
|
19
26
|
|
|
20
27
|
/******************************************************************************
|
|
21
28
|
Functions
|
|
@@ -29,3 +36,13 @@ export async function cleanDatabase(): Promise<void> {
|
|
|
29
36
|
UserRepo.deleteAllUsers(),
|
|
30
37
|
]);
|
|
31
38
|
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* JSON parse a validation error.
|
|
42
|
+
*/
|
|
43
|
+
export function parseValidationErr(arg: unknown): IValidationErr {
|
|
44
|
+
if (!isString(arg)) {
|
|
45
|
+
throw new Error('Not a string');
|
|
46
|
+
}
|
|
47
|
+
return parseJson<IValidationErr>(arg);
|
|
48
|
+
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import supertest from 'supertest';
|
|
2
2
|
import insertUrlParams from 'inserturlparams';
|
|
3
|
-
import {
|
|
4
|
-
import { parseJson, customDeepCompare } from 'jet-validators/utils';
|
|
3
|
+
import { customDeepCompare } from 'jet-validators/utils';
|
|
5
4
|
|
|
6
5
|
import app from '@src/server';
|
|
7
6
|
|
|
8
7
|
import UserRepo from '@src/repos/UserRepo';
|
|
9
8
|
import User, { IUser } from '@src/models/User';
|
|
10
9
|
import { USER_NOT_FOUND_ERR } from '@src/services/UserService';
|
|
11
|
-
|
|
10
|
+
|
|
12
11
|
import HttpStatusCodes from '@src/common/HttpStatusCodes';
|
|
12
|
+
import { ValidationError } from '@src/common/route-errors';
|
|
13
13
|
|
|
14
14
|
import Paths from 'spec/support/Paths';
|
|
15
|
-
import { cleanDatabase, TRes } from 'spec/support';
|
|
15
|
+
import { cleanDatabase, parseValidationErr, TRes } from 'spec/support';
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
/******************************************************************************
|
|
@@ -92,10 +92,9 @@ describe('UserRouter', () => {
|
|
|
92
92
|
.send({ user: null })
|
|
93
93
|
.end((_, res: TRes) => {
|
|
94
94
|
expect(res.status).toBe(HttpStatusCodes.BAD_REQUEST);
|
|
95
|
-
const errorObj =
|
|
96
|
-
|
|
97
|
-
expect(errorObj.
|
|
98
|
-
expect(isObject(errItem) && errItem.prop === 'user').toBeTruthy();
|
|
95
|
+
const errorObj = parseValidationErr(res.body.error);
|
|
96
|
+
expect(errorObj.message).toBe(ValidationError.MESSAGE);
|
|
97
|
+
expect(errorObj.errors[0].prop).toBe('user');
|
|
99
98
|
done();
|
|
100
99
|
});
|
|
101
100
|
});
|
|
@@ -118,19 +117,21 @@ describe('UserRouter', () => {
|
|
|
118
117
|
});
|
|
119
118
|
});
|
|
120
119
|
|
|
121
|
-
//
|
|
120
|
+
// Id is the wrong data type
|
|
122
121
|
it('should return a JSON object with an error message and a status code ' +
|
|
123
122
|
`of "${HttpStatusCodes.BAD_REQUEST}" if the user param was missing`,
|
|
124
123
|
done => {
|
|
124
|
+
const user = User.new();
|
|
125
|
+
user.id = ('5' as unknown as number);
|
|
125
126
|
agent
|
|
126
127
|
.put(Paths.Users.Update)
|
|
127
|
-
.send({ user
|
|
128
|
+
.send({ user })
|
|
128
129
|
.end((_, res: TRes) => {
|
|
129
130
|
expect(res.status).toBe(HttpStatusCodes.BAD_REQUEST);
|
|
130
|
-
const errorObj =
|
|
131
|
-
|
|
132
|
-
expect(errorObj.
|
|
133
|
-
expect(
|
|
131
|
+
const errorObj = parseValidationErr(res.body.error);
|
|
132
|
+
expect(errorObj.message).toBe(ValidationError.MESSAGE);
|
|
133
|
+
expect(errorObj.errors[0].prop).toBe('user');
|
|
134
|
+
expect(errorObj.errors[0].children?.[0].prop).toBe('id');
|
|
134
135
|
done();
|
|
135
136
|
});
|
|
136
137
|
});
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { IParseObjectError } from 'jet-validators/utils';
|
|
2
|
+
|
|
1
3
|
import HttpStatusCodes from '@src/common/HttpStatusCodes';
|
|
2
4
|
|
|
3
5
|
|
|
4
6
|
/******************************************************************************
|
|
5
|
-
|
|
7
|
+
Classes
|
|
6
8
|
******************************************************************************/
|
|
7
9
|
|
|
8
10
|
/**
|
|
@@ -17,3 +19,19 @@ export class RouteError extends Error {
|
|
|
17
19
|
}
|
|
18
20
|
}
|
|
19
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Handle "parseObj" errors.
|
|
24
|
+
*/
|
|
25
|
+
export class ValidationError extends RouteError {
|
|
26
|
+
|
|
27
|
+
public static MESSAGE = 'The parseObj() function discovered one or ' +
|
|
28
|
+
'more errors.';
|
|
29
|
+
|
|
30
|
+
public constructor(errors: IParseObjectError[]) {
|
|
31
|
+
const msg = JSON.stringify({
|
|
32
|
+
message: ValidationError.MESSAGE,
|
|
33
|
+
errors,
|
|
34
|
+
});
|
|
35
|
+
super(HttpStatusCodes.BAD_REQUEST, msg);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isString } from 'jet-validators';
|
|
2
|
-
import {
|
|
2
|
+
import { parseObject, TParseOnError } from 'jet-validators/utils';
|
|
3
3
|
|
|
4
|
-
import { isRelationalKey,
|
|
4
|
+
import { isRelationalKey, transIsDate } from '@src/util/validators';
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
/******************************************************************************
|
|
@@ -35,27 +35,33 @@ export interface IUser {
|
|
|
35
35
|
/**
|
|
36
36
|
* New user object.
|
|
37
37
|
*/
|
|
38
|
-
function newUser(user
|
|
38
|
+
function newUser(user?: Partial<IUser>): IUser {
|
|
39
39
|
const retVal = { ...DEFAULT_USER_VALS(), ...user };
|
|
40
|
-
return parseUser(retVal);
|
|
40
|
+
return parseUser(true)(retVal);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
|
-
*
|
|
44
|
+
* Check is a user object. For the route validation.
|
|
45
45
|
*/
|
|
46
|
-
function
|
|
47
|
-
return !!parseUser(arg);
|
|
46
|
+
function testUser(arg: unknown, errCb?: TParseOnError): arg is IUser {
|
|
47
|
+
return !!parseUser()(arg, errCb);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
|
-
*
|
|
51
|
+
* Parse a user object.
|
|
52
52
|
*/
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
function parseUser(throwErr?: boolean) {
|
|
54
|
+
return parseObject<IUser>({
|
|
55
|
+
id: isRelationalKey,
|
|
56
|
+
name: isString,
|
|
57
|
+
email: isString,
|
|
58
|
+
created: transIsDate,
|
|
59
|
+
}, errors => {
|
|
60
|
+
if (throwErr) {
|
|
61
|
+
throw new Error(JSON.stringify(errors));
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
59
65
|
|
|
60
66
|
|
|
61
67
|
/******************************************************************************
|
|
@@ -64,6 +70,5 @@ const parseUser: TParser<IUser> = parseObjectPlus({
|
|
|
64
70
|
|
|
65
71
|
export default {
|
|
66
72
|
new: newUser,
|
|
67
|
-
|
|
68
|
-
test: testIsUser,
|
|
73
|
+
test: testUser,
|
|
69
74
|
} as const;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"users":[{"id":
|
|
1
|
+
{"users":[{"id":64898245208,"name":"John Smith","created":"2025-03-10T08:17:36.414Z","email":"john.smith@gmail.com"},{"id":77834125799,"name":"Gordan Freeman","created":"2025-03-10T08:17:36.414Z","email":"gordan.freeman@gmail.com"}]}
|
|
@@ -1,54 +1,28 @@
|
|
|
1
1
|
import { Response, Request } from 'express';
|
|
2
|
+
import { parseObject, TSchema } from 'jet-validators/utils';
|
|
2
3
|
|
|
3
|
-
import {
|
|
4
|
-
ParseObjectError,
|
|
5
|
-
TParseErrorItem,
|
|
6
|
-
TSchema,
|
|
7
|
-
parseObjectPlus,
|
|
8
|
-
} from 'jet-validators/utils';
|
|
9
|
-
|
|
10
|
-
import HttpStatusCodes from '@src/common/HttpStatusCodes';
|
|
11
|
-
import { RouteError } from '@src/common/route-errors';
|
|
4
|
+
import { ValidationError } from '@src/common/route-errors';
|
|
12
5
|
|
|
13
6
|
|
|
14
7
|
/******************************************************************************
|
|
15
|
-
|
|
8
|
+
Functions
|
|
16
9
|
******************************************************************************/
|
|
17
10
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
export
|
|
23
|
-
|
|
24
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Throw a "ParseObjError" when "parseObject" fails. Also extract a nested
|
|
13
|
+
* "ParseObjError" and add it to the nestedErrors array.
|
|
14
|
+
*/
|
|
15
|
+
export function parseReq<U extends TSchema>(schema: U) {
|
|
16
|
+
return parseObject(schema, errors => {
|
|
17
|
+
throw new ValidationError(errors);
|
|
18
|
+
});
|
|
25
19
|
}
|
|
26
20
|
|
|
27
21
|
|
|
28
22
|
/******************************************************************************
|
|
29
|
-
|
|
23
|
+
Types
|
|
30
24
|
******************************************************************************/
|
|
31
25
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
export function parseReq<U extends TSchema>(schema: U) {
|
|
36
|
-
const parse = parseObjectPlus(schema);
|
|
37
|
-
return (arg: unknown) => {
|
|
38
|
-
let retVal;
|
|
39
|
-
try {
|
|
40
|
-
retVal = parse(arg);
|
|
41
|
-
} catch (err) {
|
|
42
|
-
if (err instanceof ParseObjectError) {
|
|
43
|
-
const errObj: IParseRequestError = {
|
|
44
|
-
message: 'Parse request validation failed',
|
|
45
|
-
errors: err.getErrors(),
|
|
46
|
-
};
|
|
47
|
-
const msg = JSON.stringify(errObj);
|
|
48
|
-
throw new RouteError(HttpStatusCodes.BAD_REQUEST, msg);
|
|
49
|
-
}
|
|
50
|
-
throw err;
|
|
51
|
-
}
|
|
52
|
-
return retVal;
|
|
53
|
-
};
|
|
54
|
-
}
|
|
26
|
+
type TRecord = Record<string, unknown>;
|
|
27
|
+
export type IReq = Request<TRecord, void, TRecord, TRecord>;
|
|
28
|
+
export type IRes = Response<unknown, TRecord>;
|
|
@@ -16,7 +16,7 @@ export function isRelationalKey(arg: unknown): arg is number {
|
|
|
16
16
|
/**
|
|
17
17
|
* Convert to date object then check is a validate date.
|
|
18
18
|
*/
|
|
19
|
-
export const
|
|
19
|
+
export const transIsDate = transform(
|
|
20
20
|
arg => new Date(arg as string),
|
|
21
21
|
arg => isDate(arg),
|
|
22
22
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "express-generator-typescript",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.19",
|
|
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",
|