express-generator-typescript 2.9.1 → 3.0.1
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/README.md +34 -36
- package/lib/template/README.md +33 -15
- package/lib/template/package.json +11 -21
- package/lib/template/src/common/{utils → classes}/route-errors.ts +1 -1
- package/lib/template/src/common/constants/HttpStatusCodes.ts +1 -1
- package/lib/template/src/common/constants/env-inv.ts +2 -1
- package/lib/template/src/common/utils/dev-only.ts +25 -0
- package/lib/template/src/entities/User/_internal/validators.ts +47 -0
- package/lib/template/src/entities/User/index.ts +2 -0
- package/lib/template/src/entities/User/module.ts +63 -0
- package/lib/template/src/entities/User/types.ts +18 -0
- package/lib/template/src/{models → entities}/common/types.ts +1 -1
- package/lib/template/src/public/scripts/HttpClient.js +59 -0
- package/lib/template/src/public/scripts/renderUsers.js +43 -5
- package/lib/template/src/public/scripts/users.js +75 -14
- package/lib/template/src/repos/MockOrm.ts +3 -3
- package/lib/template/src/repos/UserRepo.ts +6 -6
- package/lib/template/src/repos/common/database.json +2 -2
- package/lib/template/src/routes/UserRoutes.ts +2 -2
- package/lib/template/src/routes/common/express-types.ts +1 -1
- package/lib/template/src/routes/common/parseReq.ts +2 -2
- package/lib/template/src/server.ts +16 -4
- package/lib/template/src/services/UserService.ts +6 -6
- package/lib/template/src/views/users.html +1 -1
- package/lib/template/tests/common/comparators.ts +3 -3
- package/lib/template/tests/common/supertest-types.ts +2 -2
- package/lib/template/tests/frontend.test.ts +1 -1
- package/lib/template/tests/support/agent.ts +2 -2
- package/lib/template/tests/users.test.ts +11 -11
- package/lib/template/tsconfig.json +9 -10
- package/lib/template/tsconfig.prod.json +13 -4
- package/lib/template/{vitest.config.mts → vitest.config.ts} +6 -4
- package/package.json +1 -1
- package/lib/template/bs-config.js +0 -8
- package/lib/template/src/models/User.model.ts +0 -95
- package/lib/template/src/public/scripts/http.js +0 -25
|
@@ -2,18 +2,25 @@
|
|
|
2
2
|
// EXEC //
|
|
3
3
|
// ========================================================================= //
|
|
4
4
|
|
|
5
|
-
// Start
|
|
6
5
|
displayUsers();
|
|
6
|
+
document.addEventListener('click', onDocumentClick);
|
|
7
7
|
|
|
8
8
|
// ========================================================================= //
|
|
9
9
|
// FUNCTIONS //
|
|
10
10
|
// ========================================================================= //
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
13
|
+
* Fetch all users and render them into the page.
|
|
14
|
+
*
|
|
15
|
+
* Used by: @EXEC
|
|
16
|
+
* {@link addUser}
|
|
17
|
+
* {@link submitEdit}
|
|
18
|
+
* {@link deleteUser}
|
|
19
|
+
*
|
|
20
|
+
* @returns {void}
|
|
14
21
|
*/
|
|
15
22
|
function displayUsers() {
|
|
16
|
-
|
|
23
|
+
HttpClient.get('/api/users/all')
|
|
17
24
|
.then(checkResponse)
|
|
18
25
|
.then((resp) => resp.json())
|
|
19
26
|
.then((resp) => {
|
|
@@ -23,8 +30,16 @@ function displayUsers() {
|
|
|
23
30
|
.catch(showError);
|
|
24
31
|
}
|
|
25
32
|
|
|
26
|
-
//
|
|
27
|
-
|
|
33
|
+
// =========================== `onDocumentClick` =========================== //
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Route clicks on the page's buttons to their handlers.
|
|
37
|
+
*
|
|
38
|
+
* @listens click
|
|
39
|
+
* @param {MouseEvent} event
|
|
40
|
+
* @returns {void}
|
|
41
|
+
*/
|
|
42
|
+
function onDocumentClick(event) {
|
|
28
43
|
var ele = event.target;
|
|
29
44
|
if (ele.matches('#add-user-btn')) {
|
|
30
45
|
addUser();
|
|
@@ -37,10 +52,14 @@ document.addEventListener('click', (event) => {
|
|
|
37
52
|
} else if (ele.matches('.delete-user-btn')) {
|
|
38
53
|
deleteUser(ele);
|
|
39
54
|
}
|
|
40
|
-
}
|
|
55
|
+
}
|
|
41
56
|
|
|
42
57
|
/**
|
|
43
|
-
*
|
|
58
|
+
* Create a user from the "Add User" form, then refresh the list.
|
|
59
|
+
*
|
|
60
|
+
* Used by: {@link onDocumentClick}
|
|
61
|
+
*
|
|
62
|
+
* @returns {void}
|
|
44
63
|
*/
|
|
45
64
|
function addUser() {
|
|
46
65
|
var nameInput = document.getElementById('name-input');
|
|
@@ -54,7 +73,7 @@ function addUser() {
|
|
|
54
73
|
email: emailInput.value,
|
|
55
74
|
},
|
|
56
75
|
};
|
|
57
|
-
|
|
76
|
+
HttpClient.post('/api/users/add', data)
|
|
58
77
|
.then(checkResponse)
|
|
59
78
|
.then(() => {
|
|
60
79
|
nameInput.value = '';
|
|
@@ -65,7 +84,12 @@ function addUser() {
|
|
|
65
84
|
}
|
|
66
85
|
|
|
67
86
|
/**
|
|
68
|
-
*
|
|
87
|
+
* Switch a user's row to its edit form.
|
|
88
|
+
*
|
|
89
|
+
* Used by: {@link onDocumentClick}
|
|
90
|
+
*
|
|
91
|
+
* @param {HTMLElement} userEle - The `.user-display-ele` wrapper for the user.
|
|
92
|
+
* @returns {void}
|
|
69
93
|
*/
|
|
70
94
|
function showEditView(userEle) {
|
|
71
95
|
var normalView = userEle.getElementsByClassName('normal-view')[0];
|
|
@@ -75,7 +99,12 @@ function showEditView(userEle) {
|
|
|
75
99
|
}
|
|
76
100
|
|
|
77
101
|
/**
|
|
78
|
-
*
|
|
102
|
+
* Close a user's edit form without saving.
|
|
103
|
+
*
|
|
104
|
+
* Used by: {@link onDocumentClick}
|
|
105
|
+
*
|
|
106
|
+
* @param {HTMLElement} userEle - The `.user-display-ele` wrapper for the user.
|
|
107
|
+
* @returns {void}
|
|
79
108
|
*/
|
|
80
109
|
function cancelEdit(userEle) {
|
|
81
110
|
var normalView = userEle.getElementsByClassName('normal-view')[0];
|
|
@@ -85,7 +114,13 @@ function cancelEdit(userEle) {
|
|
|
85
114
|
}
|
|
86
115
|
|
|
87
116
|
/**
|
|
88
|
-
*
|
|
117
|
+
* Save a user's edit form, then refresh the list.
|
|
118
|
+
*
|
|
119
|
+
* Used by: {@link onDocumentClick}
|
|
120
|
+
*
|
|
121
|
+
* @param {HTMLElement} ele - The clicked "Submit" button; carries the user's
|
|
122
|
+
* id and created date in data attributes.
|
|
123
|
+
* @returns {void}
|
|
89
124
|
*/
|
|
90
125
|
function submitEdit(ele) {
|
|
91
126
|
var userEle = ele.parentNode.parentNode;
|
|
@@ -102,25 +137,42 @@ function submitEdit(ele) {
|
|
|
102
137
|
created: ele.getAttribute('data-user-created'),
|
|
103
138
|
},
|
|
104
139
|
};
|
|
105
|
-
|
|
140
|
+
HttpClient.put('/api/users/update', data)
|
|
106
141
|
.then(checkResponse)
|
|
107
142
|
.then(() => displayUsers())
|
|
108
143
|
.catch(showError);
|
|
109
144
|
}
|
|
110
145
|
|
|
111
146
|
/**
|
|
112
|
-
* Delete a user
|
|
147
|
+
* Delete a user, then refresh the list.
|
|
148
|
+
*
|
|
149
|
+
* Used by: {@link onDocumentClick}
|
|
150
|
+
*
|
|
151
|
+
* @param {HTMLElement} ele - The clicked "Delete" button; carries the user's
|
|
152
|
+
* id in `data-user-id`.
|
|
153
|
+
* @returns {void}
|
|
113
154
|
*/
|
|
114
155
|
function deleteUser(ele) {
|
|
115
156
|
var id = ele.getAttribute('data-user-id');
|
|
116
|
-
|
|
157
|
+
HttpClient.delete('/api/users/delete?id=' + encodeURIComponent(id))
|
|
117
158
|
.then(checkResponse)
|
|
118
159
|
.then(() => displayUsers())
|
|
119
160
|
.catch(showError);
|
|
120
161
|
}
|
|
121
162
|
|
|
163
|
+
// ============================= Shared Helpers ============================ //
|
|
164
|
+
|
|
122
165
|
/**
|
|
123
166
|
* Reject non-2xx responses with the server's error message.
|
|
167
|
+
*
|
|
168
|
+
* Used by:
|
|
169
|
+
* {@link displayUsers}
|
|
170
|
+
* {@link addUser}
|
|
171
|
+
* {@link submitEdit}
|
|
172
|
+
* {@link deleteUser}
|
|
173
|
+
*
|
|
174
|
+
* @param {Response} resp
|
|
175
|
+
* @returns {Response | Promise<never>} The response when it succeeded.
|
|
124
176
|
*/
|
|
125
177
|
function checkResponse(resp) {
|
|
126
178
|
if (resp.ok) {
|
|
@@ -136,6 +188,15 @@ function checkResponse(resp) {
|
|
|
136
188
|
|
|
137
189
|
/**
|
|
138
190
|
* Surface a failed request to the user.
|
|
191
|
+
*
|
|
192
|
+
* Used by:
|
|
193
|
+
* {@link displayUsers}
|
|
194
|
+
* {@link addUser}
|
|
195
|
+
* {@link submitEdit}
|
|
196
|
+
* {@link deleteUser}
|
|
197
|
+
*
|
|
198
|
+
* @param {Error} err
|
|
199
|
+
* @returns {void}
|
|
139
200
|
*/
|
|
140
201
|
function showError(err) {
|
|
141
202
|
alert(err.message);
|
|
@@ -3,14 +3,14 @@ import jsonfile from 'jsonfile';
|
|
|
3
3
|
import path from 'path';
|
|
4
4
|
|
|
5
5
|
import { EnvVars, NodeEnvs } from '@src/common/constants/env-inv';
|
|
6
|
-
import {
|
|
6
|
+
import type { UserEntity } from '@src/entities/User';
|
|
7
7
|
|
|
8
8
|
// ========================================================================= //
|
|
9
9
|
// CONSTANTS //
|
|
10
10
|
// ========================================================================= //
|
|
11
11
|
|
|
12
12
|
const DATABASE_FILE_PATH = path.join(
|
|
13
|
-
|
|
13
|
+
import.meta.dirname,
|
|
14
14
|
'common',
|
|
15
15
|
EnvVars.NodeEnv === NodeEnvs.TEST ? 'database.test.json' : 'database.json',
|
|
16
16
|
);
|
|
@@ -20,7 +20,7 @@ const DATABASE_FILE_PATH = path.join(
|
|
|
20
20
|
// ========================================================================= //
|
|
21
21
|
|
|
22
22
|
type Database = {
|
|
23
|
-
users:
|
|
23
|
+
users: UserEntity[];
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
// ========================================================================= //
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import jetid from 'jet-id';
|
|
2
2
|
|
|
3
3
|
import { getISOString } from '@src/common/utils/date-utils';
|
|
4
|
-
import {
|
|
4
|
+
import type { UserEntity } from '@src/entities/User';
|
|
5
5
|
|
|
6
6
|
import orm from './MockOrm';
|
|
7
7
|
|
|
@@ -25,7 +25,7 @@ async function persists(id: string): Promise<boolean> {
|
|
|
25
25
|
/**
|
|
26
26
|
* Get all users.
|
|
27
27
|
*/
|
|
28
|
-
async function getAll(): Promise<
|
|
28
|
+
async function getAll(): Promise<UserEntity[]> {
|
|
29
29
|
const db = await orm.openDb();
|
|
30
30
|
return db.users;
|
|
31
31
|
}
|
|
@@ -33,7 +33,7 @@ async function getAll(): Promise<IUser[]> {
|
|
|
33
33
|
/**
|
|
34
34
|
* Add one user.
|
|
35
35
|
*/
|
|
36
|
-
async function add(user:
|
|
36
|
+
async function add(user: UserEntity): Promise<void> {
|
|
37
37
|
const db = await orm.openDb();
|
|
38
38
|
db.users.push(user);
|
|
39
39
|
return orm.saveDb(db);
|
|
@@ -42,7 +42,7 @@ async function add(user: IUser): Promise<void> {
|
|
|
42
42
|
/**
|
|
43
43
|
* Update a user.
|
|
44
44
|
*/
|
|
45
|
-
async function update(user:
|
|
45
|
+
async function update(user: UserEntity): Promise<void> {
|
|
46
46
|
const db = await orm.openDb();
|
|
47
47
|
for (let i = 0; i < db.users.length; i++) {
|
|
48
48
|
if (db.users[i].id === user.id) {
|
|
@@ -89,8 +89,8 @@ async function deleteAllUsers(): Promise<void> {
|
|
|
89
89
|
* Insert copies of `users` with fresh ids; the inputs are not modified.
|
|
90
90
|
*/
|
|
91
91
|
async function insertMultiple(
|
|
92
|
-
users:
|
|
93
|
-
): Promise<
|
|
92
|
+
users: UserEntity[] | readonly UserEntity[],
|
|
93
|
+
): Promise<UserEntity[]> {
|
|
94
94
|
const db = await orm.openDb();
|
|
95
95
|
const inserted = users.map((user) => ({
|
|
96
96
|
...user,
|
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
"created": "2024-03-22T05:42:18.895Z"
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
|
-
"id": "
|
|
22
|
+
"id": "1S0KVJXSP-A7PXE-P15HN-KKFFNM",
|
|
23
23
|
"name": "asdf",
|
|
24
24
|
"email": "asdf",
|
|
25
|
-
"created": "2026-09-
|
|
25
|
+
"created": "2026-09-27T01:07:01.857Z"
|
|
26
26
|
}
|
|
27
27
|
]
|
|
28
28
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import HttpStatusCodes from '@src/common/constants/HttpStatusCodes';
|
|
2
|
-
import User from '@src/
|
|
2
|
+
import User from '@src/entities/User';
|
|
3
3
|
import UserService from '@src/services/UserService';
|
|
4
4
|
|
|
5
|
-
import { Req, Res } from './common/express-types';
|
|
5
|
+
import type { Req, Res } from './common/express-types';
|
|
6
6
|
import parseReq from './common/parseReq';
|
|
7
7
|
|
|
8
8
|
// ========================================================================= //
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { parseObject, Schema } from 'jet-validators/utils';
|
|
1
|
+
import { parseObject, type Schema } from 'jet-validators/utils';
|
|
2
2
|
|
|
3
|
-
import { ValidationError } from '@src/common/
|
|
3
|
+
import { ValidationError } from '@src/common/classes/route-errors';
|
|
4
4
|
|
|
5
5
|
// ========================================================================= //
|
|
6
6
|
// FUNCTIONS //
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import express, {
|
|
1
|
+
import express, {
|
|
2
|
+
type NextFunction,
|
|
3
|
+
type Request,
|
|
4
|
+
type Response,
|
|
5
|
+
} from 'express';
|
|
2
6
|
import helmet from 'helmet';
|
|
3
7
|
import logger from 'jet-logger';
|
|
4
8
|
import morgan from 'morgan';
|
|
@@ -6,7 +10,7 @@ import path from 'path';
|
|
|
6
10
|
|
|
7
11
|
import HttpStatusCodes from '@src/common/constants/HttpStatusCodes';
|
|
8
12
|
import Paths from '@src/common/constants/Paths';
|
|
9
|
-
import { RouteError } from '@src/common/
|
|
13
|
+
import { RouteError } from '@src/common/classes/route-errors';
|
|
10
14
|
import BaseRouter from '@src/routes/apiRouter';
|
|
11
15
|
|
|
12
16
|
import { EnvVars, NodeEnvs } from './common/constants/env-inv';
|
|
@@ -55,10 +59,18 @@ app.use((err: Error, _: Request, res: Response, _next: NextFunction) => {
|
|
|
55
59
|
// =========================== Front-end Content =========================== //
|
|
56
60
|
|
|
57
61
|
// Views directory (html)
|
|
58
|
-
const viewsDir = path.join(
|
|
62
|
+
const viewsDir = path.join(import.meta.dirname, 'views');
|
|
59
63
|
|
|
60
64
|
// Set static directory (js and css).
|
|
61
|
-
const staticDir = path.join(
|
|
65
|
+
const staticDir = path.join(import.meta.dirname, 'public');
|
|
66
|
+
|
|
67
|
+
// Refresh the browser on changes. Imported lazily because livereload is a
|
|
68
|
+
// dev dependency and isn't installed in production.
|
|
69
|
+
if (EnvVars.NodeEnv === NodeEnvs.DEV) {
|
|
70
|
+
const { setupLiveReload } = await import('@src/common/utils/dev-only');
|
|
71
|
+
setupLiveReload(app, [staticDir, viewsDir]);
|
|
72
|
+
}
|
|
73
|
+
|
|
62
74
|
app.use(express.static(staticDir));
|
|
63
75
|
|
|
64
76
|
// Nav to users pg by default
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import HttpStatusCodes from '@src/common/constants/HttpStatusCodes';
|
|
2
|
-
import { RouteError } from '@src/common/
|
|
3
|
-
import User, {
|
|
2
|
+
import { RouteError } from '@src/common/classes/route-errors';
|
|
3
|
+
import User, { type UserEntity, type UserInput } from '@src/entities/User';
|
|
4
4
|
import UserRepo from '@src/repos/UserRepo';
|
|
5
5
|
|
|
6
6
|
// ========================================================================= //
|
|
@@ -18,15 +18,15 @@ const Errors = {
|
|
|
18
18
|
/**
|
|
19
19
|
* Get all users.
|
|
20
20
|
*/
|
|
21
|
-
function getAll(): Promise<
|
|
21
|
+
function getAll(): Promise<UserEntity[]> {
|
|
22
22
|
return UserRepo.getAll();
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* Create a user from client input; the id and created date are set here.
|
|
27
27
|
*/
|
|
28
|
-
async function addOne(input:
|
|
29
|
-
const user = User.
|
|
28
|
+
async function addOne(input: UserInput): Promise<UserEntity> {
|
|
29
|
+
const user = User.create(input);
|
|
30
30
|
await UserRepo.add(user);
|
|
31
31
|
return user;
|
|
32
32
|
}
|
|
@@ -34,7 +34,7 @@ async function addOne(input: IUserInput): Promise<IUser> {
|
|
|
34
34
|
/**
|
|
35
35
|
* Update one user.
|
|
36
36
|
*/
|
|
37
|
-
async function updateOne(user:
|
|
37
|
+
async function updateOne(user: UserEntity): Promise<void> {
|
|
38
38
|
const persists = await UserRepo.persists(user.id);
|
|
39
39
|
if (!persists) {
|
|
40
40
|
throw new RouteError(HttpStatusCodes.NOT_FOUND, Errors.USER_NOT_FOUND);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { UserEntity } from '@src/entities/User';
|
|
2
2
|
|
|
3
3
|
// ========================================================================= //
|
|
4
4
|
// TYPES //
|
|
5
5
|
// ========================================================================= //
|
|
6
6
|
|
|
7
|
-
type UserArray =
|
|
7
|
+
type UserArray = UserEntity[] | readonly UserEntity[];
|
|
8
8
|
|
|
9
9
|
// ========================================================================= //
|
|
10
10
|
// FUNCTIONS //
|
|
@@ -31,7 +31,7 @@ export function compareUserArrays(a: UserArray, b: UserArray): boolean {
|
|
|
31
31
|
/**
|
|
32
32
|
* Sort user array by email.
|
|
33
33
|
*/
|
|
34
|
-
function sortByEmail(arr: UserArray):
|
|
34
|
+
function sortByEmail(arr: UserArray): UserEntity[] {
|
|
35
35
|
return [...arr].sort((x, y) => {
|
|
36
36
|
return x.email.localeCompare(y.email);
|
|
37
37
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ParseError } from 'jet-validators/utils';
|
|
2
|
-
import { Response } from 'supertest';
|
|
1
|
+
import type { ParseError } from 'jet-validators/utils';
|
|
2
|
+
import type { Response } from 'supertest';
|
|
3
3
|
|
|
4
4
|
// ========================================================================= //
|
|
5
5
|
// TYPES //
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import supertest, { Test } from 'supertest';
|
|
2
|
-
import TestAgent from 'supertest/lib/agent';
|
|
1
|
+
import supertest, { type Test } from 'supertest';
|
|
2
|
+
import type TestAgent from 'supertest/lib/agent.js';
|
|
3
3
|
import { beforeAll } from 'vitest';
|
|
4
4
|
|
|
5
5
|
import MockOrm from '@src/repos/MockOrm';
|
|
@@ -2,13 +2,13 @@ import jetid from 'jet-id';
|
|
|
2
2
|
|
|
3
3
|
import HttpStatusCodes from '@src/common/constants/HttpStatusCodes';
|
|
4
4
|
import Paths from '@src/common/constants/Paths';
|
|
5
|
-
import { ValidationError } from '@src/common/
|
|
6
|
-
import User, {
|
|
5
|
+
import { ValidationError } from '@src/common/classes/route-errors';
|
|
6
|
+
import User, { type UserEntity } from '@src/entities/User';
|
|
7
7
|
import UserRepo from '@src/repos/UserRepo';
|
|
8
8
|
import UserService from '@src/services/UserService';
|
|
9
9
|
|
|
10
10
|
import { compareUserArrays } from './common/comparators';
|
|
11
|
-
import { TestRes } from './common/supertest-types';
|
|
11
|
+
import type { TestRes } from './common/supertest-types';
|
|
12
12
|
import { agent } from './support/agent';
|
|
13
13
|
|
|
14
14
|
// ========================================================================= //
|
|
@@ -16,9 +16,9 @@ import { agent } from './support/agent';
|
|
|
16
16
|
// ========================================================================= //
|
|
17
17
|
|
|
18
18
|
const DUMMY_USERS = [
|
|
19
|
-
User.
|
|
20
|
-
User.
|
|
21
|
-
User.
|
|
19
|
+
User.of('Sean Maxwell', 'sean.maxwell@gmail.com'),
|
|
20
|
+
User.of('John Smith', 'john.smith@gmail.com'),
|
|
21
|
+
User.of('Gordan Freeman', 'gordan.freeman@gmail.com'),
|
|
22
22
|
] as const;
|
|
23
23
|
|
|
24
24
|
const { BAD_REQUEST, CREATED, INTERNAL_SERVER_ERROR, OK, NOT_FOUND } =
|
|
@@ -32,7 +32,7 @@ const { BAD_REQUEST, CREATED, INTERNAL_SERVER_ERROR, OK, NOT_FOUND } =
|
|
|
32
32
|
// scenarios (i.e. a failed database connection).
|
|
33
33
|
|
|
34
34
|
describe('UserRouter', () => {
|
|
35
|
-
let dbUsers:
|
|
35
|
+
let dbUsers: UserEntity[] = [];
|
|
36
36
|
|
|
37
37
|
beforeEach(async () => {
|
|
38
38
|
await UserRepo.deleteAllUsers();
|
|
@@ -49,7 +49,7 @@ describe('UserRouter', () => {
|
|
|
49
49
|
'should return a JSON object with all the users and a status code of ' +
|
|
50
50
|
`"${OK}" if the request was successful.`,
|
|
51
51
|
async () => {
|
|
52
|
-
const res: TestRes<{ users:
|
|
52
|
+
const res: TestRes<{ users: UserEntity[] }> = await agent.get(
|
|
53
53
|
Paths.Users.Get(),
|
|
54
54
|
);
|
|
55
55
|
expect(res.status).toBe(OK);
|
|
@@ -79,7 +79,7 @@ describe('UserRouter', () => {
|
|
|
79
79
|
async () => {
|
|
80
80
|
// Same payload shape the front-end sends
|
|
81
81
|
const input = { name: 'a', email: 'a@a.com' };
|
|
82
|
-
const res: TestRes<{ user:
|
|
82
|
+
const res: TestRes<{ user: UserEntity }> = await agent
|
|
83
83
|
.post(Paths.Users.Add())
|
|
84
84
|
.send({ user: input });
|
|
85
85
|
expect(res.status).toBe(CREATED);
|
|
@@ -134,7 +134,7 @@ describe('UserRouter', () => {
|
|
|
134
134
|
'should return a JSON object with an error message and a status code ' +
|
|
135
135
|
`of "${BAD_REQUEST}" if id is not a valid id`,
|
|
136
136
|
async () => {
|
|
137
|
-
const user = { ...User.
|
|
137
|
+
const user = { ...User.create(), name: 'a', email: 'a@a.com', id: '5' };
|
|
138
138
|
const res: TestRes = await agent
|
|
139
139
|
.put(Paths.Users.Update())
|
|
140
140
|
.send({ user });
|
|
@@ -149,7 +149,7 @@ describe('UserRouter', () => {
|
|
|
149
149
|
`"${UserService.Errors.USER_NOT_FOUND}" and a status code of ` +
|
|
150
150
|
`"${NOT_FOUND}" if the id was not found.`,
|
|
151
151
|
async () => {
|
|
152
|
-
const user = User.
|
|
152
|
+
const user = User.create({ id: jetid(), name: 'a', email: 'a@a.com' }),
|
|
153
153
|
res: TestRes = await agent.put(Paths.Users.Update()).send({ user });
|
|
154
154
|
expect(res.status).toBe(NOT_FOUND);
|
|
155
155
|
expect(res.body.error).toBe(UserService.Errors.USER_NOT_FOUND);
|
|
@@ -1,27 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
|
-
"target": "
|
|
4
|
-
"module": "
|
|
5
|
-
"
|
|
6
|
-
"strict": true,
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "esnext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
7
6
|
"esModuleInterop": true,
|
|
7
|
+
"lib": ["ES2022"],
|
|
8
|
+
"strict": true,
|
|
8
9
|
"skipLibCheck": true,
|
|
9
10
|
"forceConsistentCasingInFileNames": true,
|
|
10
11
|
"paths": {
|
|
11
12
|
"@src/*": ["./src/*"]
|
|
12
13
|
},
|
|
14
|
+
// tsx transpiles one file at a time, so type-only imports must say so
|
|
15
|
+
"verbatimModuleSyntax": true,
|
|
13
16
|
"useUnknownInCatchVariables": false,
|
|
14
|
-
"types": ["vitest/globals"]
|
|
15
|
-
},
|
|
16
|
-
"ts-node": {
|
|
17
|
-
"swc": true,
|
|
18
|
-
"require": ["tsconfig-paths/register", "dotenv/config"],
|
|
17
|
+
"types": ["node", "vitest/globals"]
|
|
19
18
|
},
|
|
20
19
|
"include": [
|
|
21
20
|
"src/**/*.ts",
|
|
22
21
|
"tests/**/*.ts",
|
|
23
22
|
"eslint.config.ts",
|
|
24
|
-
"vitest.config.
|
|
23
|
+
"vitest.config.ts"
|
|
25
24
|
],
|
|
26
25
|
"exclude": ["src/public/*"]
|
|
27
26
|
}
|
|
@@ -1,21 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
|
-
"target": "
|
|
4
|
-
"module": "
|
|
5
|
-
"
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "esnext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"esModuleInterop": true,
|
|
7
|
+
"lib": ["ES2022"],
|
|
6
8
|
"strict": true,
|
|
7
9
|
"rootDir": "./src",
|
|
8
10
|
"outDir": "dist",
|
|
9
|
-
"esModuleInterop": true,
|
|
10
11
|
"skipLibCheck": true,
|
|
11
12
|
"forceConsistentCasingInFileNames": true,
|
|
12
13
|
"paths": {
|
|
13
14
|
"@src/*": ["./src/*"]
|
|
14
15
|
},
|
|
16
|
+
"verbatimModuleSyntax": true,
|
|
15
17
|
"useUnknownInCatchVariables": false,
|
|
18
|
+
"types": ["node"],
|
|
16
19
|
"sourceMap": false,
|
|
17
20
|
"removeComments": true
|
|
18
21
|
},
|
|
22
|
+
// After tsc, tsc-alias rewrites "@src/..." imports in dist/ to relative
|
|
23
|
+
// paths and adds the ".js" extensions Node's ESM loader requires (source
|
|
24
|
+
// imports are written without extensions)
|
|
25
|
+
"tsc-alias": {
|
|
26
|
+
"resolveFullPaths": true
|
|
27
|
+
},
|
|
19
28
|
"include": ["src/**/*.ts"],
|
|
20
29
|
"exclude": ["src/public/"]
|
|
21
30
|
}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import { defineConfig } from 'vitest/config';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
// ========================================================================= //
|
|
5
|
+
// EXPORT //
|
|
6
|
+
// ========================================================================= //
|
|
7
|
+
|
|
8
|
+
export default defineConfig({
|
|
5
9
|
test: {
|
|
6
10
|
globals: true,
|
|
7
11
|
environment: 'node',
|
|
@@ -15,9 +19,7 @@ const config = defineConfig({
|
|
|
15
19
|
},
|
|
16
20
|
resolve: {
|
|
17
21
|
alias: {
|
|
18
|
-
'@src': path.resolve(
|
|
22
|
+
'@src': path.resolve(import.meta.dirname, './src'),
|
|
19
23
|
},
|
|
20
24
|
},
|
|
21
25
|
});
|
|
22
|
-
|
|
23
|
-
export default config;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "express-generator-typescript",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
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
|
"commit": "git add -A && git commit -m \"dev commit\"",
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
proxy: "http://localhost:3000/", // The address where your Express app runs
|
|
3
|
-
open: true, // Avoid reopening the browser on every nodemon restart
|
|
4
|
-
port: 3001, // The port BrowserSync will run on
|
|
5
|
-
files: ["src/**/*.*"], // Files to watch
|
|
6
|
-
ignore: ['**/node_modules/**', '**/repos/**/*.json'],
|
|
7
|
-
reloadDelay: 500, // Wait for nodemon to restart
|
|
8
|
-
};
|