express-generator-typescript 2.7.11 → 2.7.14

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.
Files changed (50) hide show
  1. package/LICENSE +0 -0
  2. package/README.md +0 -0
  3. package/lib/cli.js +0 -0
  4. package/lib/express-generator-typescript.js +44 -11
  5. package/lib/project-files/.prettierignore +12 -0
  6. package/lib/project-files/.prettierrc.json +15 -0
  7. package/lib/project-files/README.md +54 -65
  8. package/lib/project-files/config/.env.development +0 -0
  9. package/lib/project-files/config/.env.production +0 -0
  10. package/lib/project-files/config/.env.test +0 -0
  11. package/lib/project-files/eslint.config.ts +46 -100
  12. package/lib/project-files/gitignore +0 -2
  13. package/lib/project-files/package.json +62 -56
  14. package/lib/project-files/src/common/constants/HttpStatusCodes.ts +393 -394
  15. package/lib/project-files/src/common/constants/Paths.ts +15 -15
  16. package/lib/project-files/src/common/constants/{EnvVars.ts → env.ts} +28 -19
  17. package/lib/project-files/src/common/utils/{misc.ts → number-utils.ts} +10 -11
  18. package/lib/project-files/src/common/utils/route-errors.ts +35 -36
  19. package/lib/project-files/src/common/utils/validators.ts +14 -14
  20. package/lib/project-files/src/{index.ts → main.ts} +24 -27
  21. package/lib/project-files/src/models/User.ts +73 -72
  22. package/lib/project-files/src/models/common/IModel.ts +4 -0
  23. package/lib/project-files/src/public/stylesheets/users.css +50 -48
  24. package/lib/project-files/src/repos/MockOrm.ts +57 -63
  25. package/lib/project-files/src/repos/UserRepo.ts +131 -133
  26. package/lib/project-files/src/repos/{database.json → common/database.json} +0 -0
  27. package/lib/project-files/src/repos/common/database.test.json +1 -0
  28. package/lib/project-files/src/routes/UserRoutes.ts +77 -69
  29. package/lib/project-files/src/routes/{index.ts → apiRouter.ts} +28 -28
  30. package/lib/project-files/src/routes/common/{types.ts → express-types.ts} +9 -10
  31. package/lib/project-files/src/routes/common/{utils.ts → parseReq.ts} +19 -16
  32. package/lib/project-files/src/server.ts +79 -84
  33. package/lib/project-files/src/services/{UserService/index.ts → UserService.ts} +64 -58
  34. package/lib/project-files/src/views/users.html +118 -132
  35. package/lib/project-files/tests/common/{utils.ts → comparators.ts} +38 -55
  36. package/lib/project-files/tests/common/error-utils.ts +25 -0
  37. package/lib/project-files/tests/common/{types.ts → supertest-types.ts} +15 -16
  38. package/lib/project-files/tests/{aux/setup.ts → support/agent.ts} +23 -26
  39. package/lib/project-files/tests/users.test.ts +131 -123
  40. package/lib/project-files/tsconfig.json +29 -35
  41. package/lib/project-files/tsconfig.prod.json +27 -30
  42. package/lib/project-files/vitest.config.mts +21 -18
  43. package/package.json +1 -1
  44. package/lib/project-files/config.ts +0 -22
  45. package/lib/project-files/scripts/build.ts +0 -28
  46. package/lib/project-files/scripts/common/utils.ts +0 -93
  47. package/lib/project-files/src/common/constants/index.ts +0 -11
  48. package/lib/project-files/src/models/common/types.ts +0 -5
  49. package/lib/project-files/src/repos/database.test.json +0 -1
  50. package/lib/project-files/src/services/UserService/constants.ts +0 -5
@@ -1,84 +1,79 @@
1
- import morgan from 'morgan';
2
- import path from 'path';
3
- import helmet from 'helmet';
4
- import express, { Request, Response, NextFunction } from 'express';
5
- import logger from 'jet-logger';
6
-
7
- import BaseRouter from '@src/routes';
8
-
9
- import Paths from '@src/common/constants/Paths';
10
- import EnvVars from '@src/common/constants/EnvVars';
11
- import HttpStatusCodes from '@src/common/constants/HttpStatusCodes';
12
- import { RouteError } from '@src/common/utils/route-errors';
13
- import { NodeEnvs } from '@src/common/constants';
14
-
15
-
16
- /******************************************************************************
17
- Setup
18
- ******************************************************************************/
19
-
20
- const app = express();
21
-
22
-
23
- // **** Middleware **** //
24
-
25
- // Basic middleware
26
- app.use(express.json());
27
- app.use(express.urlencoded({extended: true}));
28
-
29
- // Show routes called in console during development
30
- if (EnvVars.NodeEnv === NodeEnvs.DEV) {
31
- app.use(morgan('dev'));
32
- }
33
-
34
- // Security
35
- if (EnvVars.NodeEnv === NodeEnvs.PRODUCTION) {
36
- // eslint-disable-next-line n/no-process-env
37
- if (!process.env.DISABLE_HELMET) {
38
- app.use(helmet());
39
- }
40
- }
41
-
42
- // Add APIs, must be after middleware
43
- app.use(Paths._, BaseRouter);
44
-
45
- // Add error handler
46
- app.use((err: Error, _: Request, res: Response, next: NextFunction) => {
47
- if (EnvVars.NodeEnv !== NodeEnvs.TEST.valueOf()) {
48
- logger.err(err, true);
49
- }
50
- let status: HttpStatusCodes = HttpStatusCodes.BAD_REQUEST;
51
- if (err instanceof RouteError) {
52
- status = err.status;
53
- res.status(status).json({ error: err.message });
54
- }
55
- return next(err);
56
- });
57
-
58
-
59
- // **** FrontEnd Content **** //
60
-
61
- // Set views directory (html)
62
- const viewsDir = path.join(__dirname, 'views');
63
- app.set('views', viewsDir);
64
-
65
- // Set static directory (js and css).
66
- const staticDir = path.join(__dirname, 'public');
67
- app.use(express.static(staticDir));
68
-
69
- // Nav to users pg by default
70
- app.get('/', (_: Request, res: Response) => {
71
- return res.redirect('/users');
72
- });
73
-
74
- // Redirect to login if not logged in.
75
- app.get('/users', (_: Request, res: Response) => {
76
- return res.sendFile('users.html', { root: viewsDir });
77
- });
78
-
79
-
80
- /******************************************************************************
81
- Export default
82
- ******************************************************************************/
83
-
84
- export default app;
1
+ import express, { NextFunction, Request, Response } from 'express';
2
+ import helmet from 'helmet';
3
+ import logger from 'jet-logger';
4
+ import morgan from 'morgan';
5
+ import path from 'path';
6
+
7
+ import HttpStatusCodes from '@src/common/constants/HttpStatusCodes';
8
+ import Paths from '@src/common/constants/Paths';
9
+ import { RouteError } from '@src/common/utils/route-errors';
10
+ import BaseRouter from '@src/routes/apiRouter';
11
+
12
+ import EnvVars, { NodeEnvs } from './common/constants/env';
13
+
14
+ /******************************************************************************
15
+ Setup
16
+ ******************************************************************************/
17
+
18
+ const app = express();
19
+
20
+ // **** Middleware **** //
21
+
22
+ // Basic middleware
23
+ app.use(express.json());
24
+ app.use(express.urlencoded({ extended: true }));
25
+
26
+ // Show routes called in console during development
27
+ if (EnvVars.NodeEnv === NodeEnvs.DEV) {
28
+ app.use(morgan('dev'));
29
+ }
30
+
31
+ // Security
32
+ if (EnvVars.NodeEnv === NodeEnvs.PRODUCTION) {
33
+ // eslint-disable-next-line no-process-env
34
+ if (!process.env.DISABLE_HELMET) {
35
+ app.use(helmet());
36
+ }
37
+ }
38
+
39
+ // Add APIs, must be after middleware
40
+ app.use(Paths._, BaseRouter);
41
+
42
+ // Add error handler
43
+ app.use((err: Error, _: Request, res: Response, next: NextFunction) => {
44
+ if (EnvVars.NodeEnv !== NodeEnvs.TEST.valueOf()) {
45
+ logger.err(err, true);
46
+ }
47
+ let status: HttpStatusCodes = HttpStatusCodes.BAD_REQUEST;
48
+ if (err instanceof RouteError) {
49
+ status = err.status;
50
+ res.status(status).json({ error: err.message });
51
+ }
52
+ return next(err);
53
+ });
54
+
55
+ // **** FrontEnd Content **** //
56
+
57
+ // Set views directory (html)
58
+ const viewsDir = path.join(__dirname, 'views');
59
+ app.set('views', viewsDir);
60
+
61
+ // Set static directory (js and css).
62
+ const staticDir = path.join(__dirname, 'public');
63
+ app.use(express.static(staticDir));
64
+
65
+ // Nav to users pg by default
66
+ app.get('/', (_: Request, res: Response) => {
67
+ return res.redirect('/users');
68
+ });
69
+
70
+ // Redirect to login if not logged in.
71
+ app.get('/users', (_: Request, res: Response) => {
72
+ return res.sendFile('users.html', { root: viewsDir });
73
+ });
74
+
75
+ /******************************************************************************
76
+ Export default
77
+ ******************************************************************************/
78
+
79
+ export default app;
@@ -1,58 +1,64 @@
1
- import { RouteError } from '@src/common/utils/route-errors';
2
- import HttpStatusCodes from '@src/common/constants/HttpStatusCodes';
3
-
4
- import UserRepo from '@src/repos/UserRepo';
5
- import { IUser } from '@src/models/User';
6
- import { USER_NOT_FOUND_ERROR } from './constants';
7
-
8
- /******************************************************************************
9
- Functions
10
- ******************************************************************************/
11
-
12
- /**
13
- * Get all users.
14
- */
15
- function getAll(): Promise<IUser[]> {
16
- return UserRepo.getAll();
17
- }
18
-
19
- /**
20
- * Add one user.
21
- */
22
- function addOne(user: IUser): Promise<void> {
23
- return UserRepo.add(user);
24
- }
25
-
26
- /**
27
- * Update one user.
28
- */
29
- async function updateOne(user: IUser): Promise<void> {
30
- const persists = await UserRepo.persists(user.id);
31
- if (!persists) {
32
- throw new RouteError(HttpStatusCodes.NOT_FOUND, USER_NOT_FOUND_ERROR);
33
- }
34
- // Return user
35
- return UserRepo.update(user);
36
- }
37
-
38
- /**
39
- * Delete a user by their id.
40
- */
41
- async function __delete__(id: number): Promise<void> {
42
- const persists = await UserRepo.persists(id);
43
- if (!persists) {
44
- throw new RouteError(HttpStatusCodes.NOT_FOUND, USER_NOT_FOUND_ERROR);
45
- }
46
- return UserRepo.delete(id);
47
- }
48
-
49
- /******************************************************************************
50
- Export default
51
- ******************************************************************************/
52
-
53
- export default {
54
- getAll,
55
- addOne,
56
- updateOne,
57
- delete: __delete__,
58
- } as const;
1
+ import HttpStatusCodes from '@src/common/constants/HttpStatusCodes';
2
+ import { RouteError } from '@src/common/utils/route-errors';
3
+ import { IUser } from '@src/models/User';
4
+ import UserRepo from '@src/repos/UserRepo';
5
+
6
+ /******************************************************************************
7
+ Constants
8
+ ******************************************************************************/
9
+
10
+ const Errors = {
11
+ USER_NOT_FOUND: 'User not found',
12
+ } as const;
13
+
14
+ /******************************************************************************
15
+ Functions
16
+ ******************************************************************************/
17
+
18
+ /**
19
+ * Get all users.
20
+ */
21
+ function getAll(): Promise<IUser[]> {
22
+ return UserRepo.getAll();
23
+ }
24
+
25
+ /**
26
+ * Add one user.
27
+ */
28
+ function addOne(user: IUser): Promise<void> {
29
+ return UserRepo.add(user);
30
+ }
31
+
32
+ /**
33
+ * Update one user.
34
+ */
35
+ async function updateOne(user: IUser): Promise<void> {
36
+ const persists = await UserRepo.persists(user.id);
37
+ if (!persists) {
38
+ throw new RouteError(HttpStatusCodes.NOT_FOUND, Errors.USER_NOT_FOUND);
39
+ }
40
+ return UserRepo.update(user);
41
+ }
42
+
43
+ /**
44
+ * Delete a user by their id.
45
+ */
46
+ async function __delete__(id: number): Promise<void> {
47
+ const persists = await UserRepo.persists(id);
48
+ if (!persists) {
49
+ throw new RouteError(HttpStatusCodes.NOT_FOUND, Errors.USER_NOT_FOUND);
50
+ }
51
+ return UserRepo.delete(id);
52
+ }
53
+
54
+ /******************************************************************************
55
+ Export default
56
+ ******************************************************************************/
57
+
58
+ export default {
59
+ Errors,
60
+ getAll,
61
+ addOne,
62
+ updateOne,
63
+ delete: __delete__,
64
+ } as const;
@@ -1,132 +1,118 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
-
4
- <!-- Head -->
5
- <head>
6
- <meta charset="UTF-8">
7
- <title>Users</title>
8
- <link rel="stylesheet" type="text/css" href="/stylesheets/users.css" />
9
-
10
- <!-- Handlebars -->
11
- <script src="http://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.8/handlebars.min.js"></script>
12
-
13
- <!-- Bootstrap -->
14
- <link
15
- href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
16
- rel="stylesheet"
17
- integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
18
- crossorigin="anonymous"
19
- />
20
- <script
21
- src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
22
- integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
23
- crossorigin="anonymous"
24
- ></script>
25
- </head>
26
-
27
- <!-- Body -->
28
- <body>
29
-
30
- <!-- Add Users -->
31
- <div class="users-column add-user-col">
32
- <div class="column-header">
33
- Add User:
34
- </div>
35
- <div>
36
- <input
37
- id="name-input"
38
- type="text"
39
- class="form-control"
40
- placeholder="Name"
41
- />
42
- </div>
43
- <div>
44
- <input
45
- id="email-input"
46
- type="email"
47
- class="form-control"
48
- placeholder="Email"
49
- />
50
- </div>
51
- <div>
52
- <button
53
- id="add-user-btn"
54
- class="btn btn-success"
55
- >
56
- Add
57
- </button>
58
- </div>
59
- </div>
60
-
61
- <!-- Display Users -->
62
- <div class="users-column">
63
- <div class="column-header">
64
- Users:
65
- </div>
66
-
67
- <div id="all-users-anchor"></div>
68
- <script
69
- id="all-users-template"
70
- type="text/x-handlebars-template"
71
- >
72
- {{#each users}}
73
- <div class="user-display-ele">
74
- <div class="normal-view">
75
- <div><b>Name:</b> {{name}}</div>
76
- <div><b>Email:</b> {{email}}</div>
77
- <div><b>Created:</b> {{createdFormatted}}</div>
78
- <button
79
- type="button"
80
- class="btn btn-primary edit-user-btn"
81
- data-user-id="{{id}}"
82
- >
83
- Edit
84
- </button>
85
- <button
86
- class="btn btn-danger delete-user-btn"
87
- data-user-id="{{id}}"
88
- >
89
- Delete
90
- </button>
91
- </div>
92
-
93
- <div class="edit-view">
94
- <div>
95
- Name:&nbsp;
96
- <input
97
- type="text"
98
- class="form-control name-edit-input"
99
- value="{{name}}"
100
- />
101
- </div>
102
- <div class="email-edit">
103
- Email:&nbsp;
104
- <input
105
- type="email"
106
- class="form-control email-edit-input"
107
- value="{{email}}"
108
- />
109
- </div>
110
- <button
111
- class="btn btn-primary submit-edit-btn"
112
- data-user-id="{{id}}"
113
- data-user-created="{{created}}"
114
- >
115
- Submit
116
- </button>
117
- <button
118
- class="btn btn-secondary cancel-edit-btn"
119
- data-user-id="{{id}}"
120
- >
121
- Cancel
122
- </button>
123
- </div>
124
- </div>
125
- {{/each}}
126
- </script>
127
- </div>
128
- </body>
129
-
130
- <script src="scripts/http.js"></script>
131
- <script src="scripts/users.js"></script>
132
- </html>
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <!-- Head -->
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <title>Users</title>
7
+ <link rel="stylesheet" type="text/css" href="/stylesheets/users.css" />
8
+
9
+ <!-- Handlebars -->
10
+ <script src="http://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.8/handlebars.min.js"></script>
11
+
12
+ <!-- Bootstrap -->
13
+ <link
14
+ href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
15
+ rel="stylesheet"
16
+ integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
17
+ crossorigin="anonymous"
18
+ />
19
+ <script
20
+ src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
21
+ integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
22
+ crossorigin="anonymous"
23
+ ></script>
24
+ </head>
25
+
26
+ <!-- Body -->
27
+ <body>
28
+ <!-- Add Users -->
29
+ <div class="users-column add-user-col">
30
+ <div class="column-header">Add User:</div>
31
+ <div>
32
+ <input
33
+ id="name-input"
34
+ type="text"
35
+ class="form-control"
36
+ placeholder="Name"
37
+ />
38
+ </div>
39
+ <div>
40
+ <input
41
+ id="email-input"
42
+ type="email"
43
+ class="form-control"
44
+ placeholder="Email"
45
+ />
46
+ </div>
47
+ <div>
48
+ <button id="add-user-btn" class="btn btn-success">Add</button>
49
+ </div>
50
+ </div>
51
+
52
+ <!-- Display Users -->
53
+ <div class="users-column">
54
+ <div class="column-header">Users:</div>
55
+
56
+ <div id="all-users-anchor"></div>
57
+ <script id="all-users-template" type="text/x-handlebars-template">
58
+ {{#each users}}
59
+ <div class='user-display-ele'>
60
+ <div class='normal-view'>
61
+ <div><b>Name:</b> {{name}}</div>
62
+ <div><b>Email:</b> {{email}}</div>
63
+ <div><b>Created:</b> {{createdFormatted}}</div>
64
+ <button
65
+ type='button'
66
+ class='btn btn-primary edit-user-btn'
67
+ data-user-id='{{id}}'
68
+ >
69
+ Edit
70
+ </button>
71
+ <button
72
+ class='btn btn-danger delete-user-btn'
73
+ data-user-id='{{id}}'
74
+ >
75
+ Delete
76
+ </button>
77
+ </div>
78
+
79
+ <div class='edit-view'>
80
+ <div>
81
+ Name:&nbsp;
82
+ <input
83
+ type='text'
84
+ class='form-control name-edit-input'
85
+ value='{{name}}'
86
+ />
87
+ </div>
88
+ <div class='email-edit'>
89
+ Email:&nbsp;
90
+ <input
91
+ type='email'
92
+ class='form-control email-edit-input'
93
+ value='{{email}}'
94
+ />
95
+ </div>
96
+ <button
97
+ class='btn btn-primary submit-edit-btn'
98
+ data-user-id='{{id}}'
99
+ data-user-created='{{created}}'
100
+ >
101
+ Submit
102
+ </button>
103
+ <button
104
+ class='btn btn-secondary cancel-edit-btn'
105
+ data-user-id='{{id}}'
106
+ >
107
+ Cancel
108
+ </button>
109
+ </div>
110
+ </div>
111
+ {{/each}}
112
+ </script>
113
+ </div>
114
+ </body>
115
+
116
+ <script src="scripts/http.js"></script>
117
+ <script src="scripts/users.js"></script>
118
+ </html>
@@ -1,55 +1,38 @@
1
- import { ParseError, parseJson } from 'jet-validators/utils';
2
- import { isString } from 'jet-validators';
3
- import { IUser } from '@src/models/User';
4
-
5
- /******************************************************************************
6
- Types
7
- ******************************************************************************/
8
-
9
- type TUserArray = IUser[] | readonly IUser[];
10
-
11
- interface IValidationError {
12
- message: string;
13
- errors: ParseError[];
14
- }
15
-
16
- /******************************************************************************
17
- Functions
18
- ******************************************************************************/
19
-
20
- /**
21
- * JSON parse a validation error.
22
- */
23
- export function parseValidationError(arg: unknown): IValidationError {
24
- if (!isString(arg)) {
25
- throw new Error('Not a string');
26
- }
27
- return parseJson<IValidationError>(arg);
28
- }
29
-
30
- /**
31
- * Compare to user arrays. Order does not matter and this assumes the email
32
- * field is unique
33
- */
34
- export function compareUserArrays(a: TUserArray, b: TUserArray): boolean {
35
- if (a.length !== b.length) return false;
36
- const aSorted = sortByEmail(a);
37
- const bSorted = sortByEmail(b);
38
- for (let i = 0; i < aSorted.length; i++) {
39
- const a = aSorted[i],
40
- b = bSorted[i];
41
- if (a.email !== b.email || a.name !== b.name) {
42
- return false;
43
- }
44
- }
45
- return true;
46
- }
47
-
48
- /**
49
- * Sort user array by email.
50
- */
51
- function sortByEmail(arr: TUserArray): IUser[] {
52
- return [...arr].sort((x, y) => {
53
- return x.email.localeCompare(y.email);
54
- });
55
- }
1
+ import { IUser } from '@src/models/User';
2
+
3
+ /******************************************************************************
4
+ Types
5
+ ******************************************************************************/
6
+
7
+ type UserArray = IUser[] | readonly IUser[];
8
+
9
+ /******************************************************************************
10
+ Functions
11
+ ******************************************************************************/
12
+
13
+ /**
14
+ * Compare to user arrays. Order does not matter and this assumes the email
15
+ * field is unique
16
+ */
17
+ export function compareUserArrays(a: UserArray, b: UserArray): boolean {
18
+ if (a.length !== b.length) return false;
19
+ const aSorted = sortByEmail(a),
20
+ bSorted = sortByEmail(b);
21
+ for (let i = 0; i < aSorted.length; i++) {
22
+ const a = aSorted[i],
23
+ b = bSorted[i];
24
+ if (a.email !== b.email || a.name !== b.name) {
25
+ return false;
26
+ }
27
+ }
28
+ return true;
29
+ }
30
+
31
+ /**
32
+ * Sort user array by email.
33
+ */
34
+ function sortByEmail(arr: UserArray): IUser[] {
35
+ return [...arr].sort((x, y) => {
36
+ return x.email.localeCompare(y.email);
37
+ });
38
+ }