express-generator-typescript 2.8.1 → 2.9.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.
Files changed (72) hide show
  1. package/README.md +198 -18
  2. package/bin/cli.js +91 -32
  3. package/lib/express-generator-typescript.js +125 -151
  4. package/lib/{project-files → template}/.prettierignore +2 -4
  5. package/lib/template/README.md +50 -0
  6. package/lib/template/bs-config.js +8 -0
  7. package/lib/{project-files → template}/config/.env.development +4 -6
  8. package/lib/{project-files → template}/config/.env.production +4 -5
  9. package/lib/{project-files → template}/config/.env.test +4 -5
  10. package/lib/{project-files → template}/eslint.config.ts +4 -0
  11. package/lib/template/gitignore +10 -0
  12. package/lib/{project-files → template}/package.json +31 -36
  13. package/lib/{project-files → template}/src/common/constants/HttpStatusCodes.ts +12 -8
  14. package/lib/template/src/common/constants/Paths.ts +22 -0
  15. package/lib/template/src/common/constants/env-inv.ts +31 -0
  16. package/lib/template/src/common/types/utility-types.ts +5 -0
  17. package/lib/template/src/common/utils/date-utils.ts +29 -0
  18. package/lib/template/src/common/utils/route-errors.ts +37 -0
  19. package/lib/template/src/main.ts +24 -0
  20. package/lib/template/src/models/User.model.ts +95 -0
  21. package/lib/template/src/models/common/types.ts +10 -0
  22. package/lib/template/src/public/scripts/http.js +25 -0
  23. package/lib/template/src/public/scripts/lib/bootstrap.bundle.min.js +4229 -0
  24. package/lib/template/src/public/scripts/renderUsers.js +90 -0
  25. package/lib/template/src/public/scripts/users.js +142 -0
  26. package/lib/template/src/public/stylesheets/lib/bootstrap.min.css +11798 -0
  27. package/lib/template/src/repos/MockOrm.ts +71 -0
  28. package/lib/{project-files → template}/src/repos/UserRepo.ts +21 -35
  29. package/lib/template/src/repos/common/database.json +28 -0
  30. package/lib/{project-files → template}/src/routes/UserRoutes.ts +15 -18
  31. package/lib/template/src/routes/apiRouter.ts +28 -0
  32. package/lib/template/src/routes/common/express-types.ts +9 -0
  33. package/lib/template/src/routes/common/parseReq.ts +23 -0
  34. package/lib/template/src/server.ts +78 -0
  35. package/lib/template/src/services/UserService.ts +66 -0
  36. package/lib/{project-files → template}/src/views/users.html +13 -6
  37. package/lib/{project-files → template}/tests/common/comparators.ts +6 -6
  38. package/lib/template/tests/common/supertest-types.ts +11 -0
  39. package/lib/template/tests/frontend.test.ts +33 -0
  40. package/lib/template/tests/support/agent.ts +23 -0
  41. package/lib/template/tests/users.test.ts +205 -0
  42. package/lib/{project-files → template}/tsconfig.json +1 -3
  43. package/lib/{project-files → template}/tsconfig.prod.json +3 -9
  44. package/lib/{project-files → template}/vitest.config.mts +2 -0
  45. package/package.json +65 -52
  46. package/lib/cli.js +0 -33
  47. package/lib/project-files/README.md +0 -39
  48. package/lib/project-files/gitignore +0 -4
  49. package/lib/project-files/src/common/constants/Paths.ts +0 -15
  50. package/lib/project-files/src/common/constants/env.ts +0 -28
  51. package/lib/project-files/src/common/types/structure-utils.ts +0 -2
  52. package/lib/project-files/src/common/utils/number-utils.ts +0 -10
  53. package/lib/project-files/src/common/utils/route-errors.ts +0 -35
  54. package/lib/project-files/src/common/utils/validators.ts +0 -14
  55. package/lib/project-files/src/main.ts +0 -24
  56. package/lib/project-files/src/models/User.model.ts +0 -72
  57. package/lib/project-files/src/models/common/types.ts +0 -4
  58. package/lib/project-files/src/public/stylesheets/lib/bootstrap.min.css +0 -6
  59. package/lib/project-files/src/repos/MockOrm.ts +0 -63
  60. package/lib/project-files/src/repos/common/database.json +0 -1
  61. package/lib/project-files/src/repos/common/database.test.json +0 -1
  62. package/lib/project-files/src/routes/apiRouter.ts +0 -28
  63. package/lib/project-files/src/routes/common/express-types.ts +0 -8
  64. package/lib/project-files/src/routes/common/parseReq.ts +0 -19
  65. package/lib/project-files/src/server.ts +0 -73
  66. package/lib/project-files/src/services/UserService.ts +0 -64
  67. package/lib/project-files/tests/common/error-utils.ts +0 -25
  68. package/lib/project-files/tests/common/supertest-types.ts +0 -15
  69. package/lib/project-files/tests/support/agent.ts +0 -23
  70. package/lib/project-files/tests/users.test.ts +0 -131
  71. /package/lib/{project-files → template}/.prettierrc.json +0 -0
  72. /package/lib/{project-files → template}/src/public/stylesheets/users.css +0 -0
@@ -1,63 +0,0 @@
1
- import jsonfile from 'jsonfile';
2
- import tspo from 'tspo';
3
-
4
- import EnvVars, { NodeEnvs } from '@src/common/constants/env';
5
- import { IUser } from '@src/models/User.model';
6
-
7
- /******************************************************************************
8
- Constants
9
- ******************************************************************************/
10
-
11
- const DATABASE_FILE_PATH =
12
- __dirname +
13
- '/common' +
14
- (EnvVars.NodeEnv === NodeEnvs.TEST
15
- ? '/database.test.json'
16
- : '/database.json');
17
-
18
- /******************************************************************************
19
- Types
20
- ******************************************************************************/
21
-
22
- type Database = {
23
- users: IUser[];
24
- };
25
-
26
- /******************************************************************************
27
- Functions
28
- ******************************************************************************/
29
-
30
- /**
31
- * Fetch the json from the file.
32
- */
33
- async function openDb(): Promise<Database> {
34
- const db = await (jsonfile.readFile(DATABASE_FILE_PATH) as Promise<Database>);
35
- if (!('users' in db)) {
36
- return tspo.addEntry(db, ['users', []]);
37
- }
38
- return db;
39
- }
40
-
41
- /**
42
- * Update the file.
43
- */
44
- function saveDb(db: Database): Promise<void> {
45
- return jsonfile.writeFile(DATABASE_FILE_PATH, db);
46
- }
47
-
48
- /**
49
- * Empty the database
50
- */
51
- function cleanDb(): Promise<void> {
52
- return jsonfile.writeFile(DATABASE_FILE_PATH, {});
53
- }
54
-
55
- /******************************************************************************
56
- Export default
57
- ******************************************************************************/
58
-
59
- export default {
60
- openDb,
61
- saveDb,
62
- cleanDb,
63
- } as const;
@@ -1 +0,0 @@
1
- {"users":[{"id":366115170645,"name":"Sean Maxwell","email":"smaxwell@example.com","created":"2024-03-22T05:14:36.252Z"},{"id":310946254456,"name":"John Smith","email":"john.smith@example.com","created":"2024-03-22T05:20:55.079Z"},{"id":143027113460,"name":"Gordan Freeman","email":"nova@prospect.com","created":"2024-03-22T05:42:18.895Z"}]}
@@ -1 +0,0 @@
1
- {"users":[{"id":8930741536,"name":"Bill","email":"sean.maxwell@gmail.com","created":"2026-03-21T05:35:26.766Z"},{"id":59836411208,"name":"John Smith","email":"john.smith@gmail.com","created":"2026-03-21T05:35:26.766Z"},{"id":924320326056,"name":"Gordan Freeman","email":"gordan.freeman@gmail.com","created":"2026-03-21T05:35:26.766Z"}]}
@@ -1,28 +0,0 @@
1
- import { Router } from 'express';
2
-
3
- import Paths from '@src/common/constants/Paths';
4
-
5
- import UserRoutes from './UserRoutes';
6
-
7
- /******************************************************************************
8
- Setup
9
- ******************************************************************************/
10
-
11
- const apiRouter = Router();
12
-
13
- // ----------------------- Add UserRouter --------------------------------- //
14
-
15
- const userRouter = Router();
16
-
17
- userRouter.get(Paths.Users.Get, UserRoutes.getAll);
18
- userRouter.post(Paths.Users.Add, UserRoutes.add);
19
- userRouter.put(Paths.Users.Update, UserRoutes.update);
20
- userRouter.delete(Paths.Users.Delete, UserRoutes.delete);
21
-
22
- apiRouter.use(Paths.Users._, userRouter);
23
-
24
- /******************************************************************************
25
- Export
26
- ******************************************************************************/
27
-
28
- export default apiRouter;
@@ -1,8 +0,0 @@
1
- import { Request, Response } from 'express';
2
-
3
- /******************************************************************************
4
- Types
5
- ******************************************************************************/
6
-
7
- export type Req = Request<Record<string, string>, void, Record<string, string>>;
8
- export type Res = Response;
@@ -1,19 +0,0 @@
1
- import { parseObject, Schema } from 'jet-validators/utils';
2
-
3
- import { ValidationError } from '@src/common/utils/route-errors';
4
-
5
- /******************************************************************************
6
- Functions
7
- ******************************************************************************/
8
-
9
- /**
10
- * Throw a "ParseObjError" when "parseObject" fails. Also extract a nested
11
- * "ParseObjError" and add it to the nestedErrors array.
12
- */
13
- function parseReq<U extends Schema>(schema: U) {
14
- return parseObject(schema, (errors) => {
15
- throw new ValidationError(errors);
16
- });
17
- }
18
-
19
- export default parseReq;
@@ -1,73 +0,0 @@
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 Paths from '@src/common/constants/Paths';
8
- import { RouteError } from '@src/common/utils/route-errors';
9
- import BaseRouter from '@src/routes/apiRouter';
10
-
11
- import EnvVars, { NodeEnvs } from './common/constants/env';
12
-
13
- /******************************************************************************
14
- Setup
15
- ******************************************************************************/
16
-
17
- const app = express();
18
-
19
- // **** Middleware **** //
20
-
21
- // Basic middleware
22
- app.use(express.json());
23
- app.use(express.urlencoded({ extended: true }));
24
-
25
- // Show routes called in console during development
26
- if (EnvVars.NodeEnv === NodeEnvs.DEV) {
27
- app.use(morgan('dev'));
28
- }
29
-
30
- // Security
31
- if (EnvVars.NodeEnv === NodeEnvs.PRODUCTION) {
32
- app.use(helmet());
33
- }
34
-
35
- // Add APIs, must be after middleware
36
- app.use(Paths._, BaseRouter);
37
-
38
- // Add error handler
39
- app.use((err: Error, _: Request, res: Response, next: NextFunction) => {
40
- if (EnvVars.NodeEnv !== NodeEnvs.TEST.valueOf()) {
41
- logger.err(err, true);
42
- }
43
- if (err instanceof RouteError) {
44
- res.status(err.status).json({ error: err.message });
45
- }
46
- return next(err);
47
- });
48
-
49
- // **** FrontEnd Content **** //
50
-
51
- // Set views directory (html)
52
- const viewsDir = path.join(__dirname, 'views');
53
- app.set('views', viewsDir);
54
-
55
- // Set static directory (js and css).
56
- const staticDir = path.join(__dirname, 'public');
57
- app.use(express.static(staticDir));
58
-
59
- // Nav to users pg by default
60
- app.get('/', (_: Request, res: Response) => {
61
- return res.redirect('/users');
62
- });
63
-
64
- // Redirect to login if not logged in.
65
- app.get('/users', (_: Request, res: Response) => {
66
- return res.sendFile('users.html', { root: viewsDir });
67
- });
68
-
69
- /******************************************************************************
70
- Export default
71
- ******************************************************************************/
72
-
73
- export default app;
@@ -1,64 +0,0 @@
1
- import HttpStatusCodes from '@src/common/constants/HttpStatusCodes';
2
- import { RouteError } from '@src/common/utils/route-errors';
3
- import { IUser } from '@src/models/User.model';
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 deleteOne(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: deleteOne,
64
- } as const;
@@ -1,25 +0,0 @@
1
- import { isString } from 'jet-validators';
2
- import { ParseError, parseJson } from 'jet-validators/utils';
3
-
4
- /******************************************************************************
5
- Types
6
- ******************************************************************************/
7
-
8
- type ValidationError = {
9
- message: string;
10
- errors: ParseError[];
11
- }
12
-
13
- /******************************************************************************
14
- Functions
15
- ******************************************************************************/
16
-
17
- /**
18
- * JSON parse a validation error.
19
- */
20
- export function parseValidationError(arg: unknown): ValidationError {
21
- if (!isString(arg)) {
22
- throw new Error('Not a string');
23
- }
24
- return parseJson<ValidationError>(arg);
25
- }
@@ -1,15 +0,0 @@
1
- import { Response } from 'supertest';
2
-
3
- /******************************************************************************
4
- Types
5
- ******************************************************************************/
6
-
7
- // Use generics to add properties to 'body'
8
- export interface TestRes<T = object> extends Omit<Response, 'body'> {
9
- body: T & { error?: string | ErrorObject };
10
- }
11
-
12
- interface ErrorObject {
13
- message: string;
14
- [key: string]: unknown;
15
- }
@@ -1,23 +0,0 @@
1
- import supertest, { Test } from 'supertest';
2
- import TestAgent from 'supertest/lib/agent';
3
- import { beforeAll } from 'vitest';
4
-
5
- import MockOrm from '@src/repos/MockOrm';
6
- import app from '@src/server';
7
-
8
- /******************************************************************************
9
- Run
10
- ******************************************************************************/
11
-
12
- let agent: TestAgent<Test>;
13
-
14
- beforeAll(async () => {
15
- agent = supertest.agent(app);
16
- await MockOrm.cleanDb();
17
- });
18
-
19
- /******************************************************************************
20
- Export
21
- ******************************************************************************/
22
-
23
- export { agent };
@@ -1,131 +0,0 @@
1
- import HttpStatusCodes from '@src/common/constants/HttpStatusCodes';
2
- import { JetPaths as Paths } from '@src/common/constants/Paths';
3
- import { ValidationError } from '@src/common/utils/route-errors';
4
- import User, { IUser } from '@src/models/User.model';
5
- import UserRepo from '@src/repos/UserRepo';
6
-
7
- import { agent } from './support/agent';
8
- import { TestRes } from './common/supertest-types';
9
- import { parseValidationError } from './common/error-utils';
10
- import UserService from '@src/services/UserService';
11
- import { compareUserArrays } from './common/comparators';
12
-
13
- /******************************************************************************
14
- Constants
15
- ******************************************************************************/
16
-
17
- const DUMMY_USERS = [
18
- User.new({ name: 'Sean Maxwell', email: 'sean.maxwell@gmail.com' }),
19
- User.new({ name: 'John Smith', email: 'john.smith@gmail.com' }),
20
- User.new({ name: 'Gordan Freeman', email: 'gordan.freeman@gmail.com' }),
21
- ] as const;
22
-
23
- const { BAD_REQUEST, CREATED, OK, NOT_FOUND } = HttpStatusCodes;
24
-
25
- /******************************************************************************
26
- Tests
27
- IMPORTANT: Following TypeScript best practices, we test all scenarios that
28
- can be triggered by a user under normal circumstances. Not all theoretically
29
- scenarios (i.e. a failed database connection).
30
- ******************************************************************************/
31
-
32
- describe('UserRouter', () => {
33
- let dbUsers: IUser[] = [];
34
-
35
- beforeEach(async () => {
36
- await UserRepo.deleteAllUsers();
37
- dbUsers = await UserRepo.insertMultiple(DUMMY_USERS);
38
- });
39
-
40
- describe(`"GET:${Paths.Users.Get()}"`, () => {
41
- it(
42
- 'should return a JSON object with all the users and a status code of ' +
43
- `"${OK}" if the request was successful.`,
44
- async () => {
45
- const res: TestRes<{ users: IUser[] }> = await agent.get(Paths.Users.Get());
46
- expect(res.status).toBe(OK);
47
- expect(compareUserArrays(res.body.users, DUMMY_USERS)).toBeTruthy();
48
- },
49
- );
50
- });
51
-
52
- describe(`"POST:${Paths.Users.Add()}"`, () => {
53
- it(
54
- `should return a status code of "${CREATED}" if the request was ` +
55
- 'successful.',
56
- async () => {
57
- const user = User.new({ name: 'a', email: 'a@a.com' }),
58
- res = await agent.post(Paths.Users.Add()).send({ user });
59
- expect(res.status).toBe(CREATED);
60
- },
61
- );
62
-
63
- it(
64
- 'should return a JSON object with an error message of and a status ' +
65
- `code of "${BAD_REQUEST}" if the user param was missing.`,
66
- async () => {
67
- const res: TestRes = await agent
68
- .post(Paths.Users.Add())
69
- .send({ user: null });
70
- expect(res.status).toBe(BAD_REQUEST);
71
- const errorObject = parseValidationError(res.body.error);
72
- expect(errorObject.message).toBe(ValidationError.MESSAGE);
73
- expect(errorObject.errors[0].key).toStrictEqual('user');
74
- },
75
- );
76
- });
77
-
78
- describe(`"PUT:${Paths.Users.Update()}"`, () => {
79
- it(`should return a status code of "${OK}" if the request was successfull`, async () => {
80
- const user = DUMMY_USERS[0];
81
- user.name = 'Bill';
82
- const res = await agent.put(Paths.Users.Update()).send({ user });
83
- expect(res.status).toBe(OK);
84
- });
85
-
86
- it(
87
- 'should return a JSON object with an error message and a status code ' +
88
- `of "${BAD_REQUEST}" if id is the wrong data type`,
89
- async () => {
90
- const user = User.new();
91
- user.id = '5' as unknown as number;
92
- const res: TestRes = await agent.put(Paths.Users.Update()).send({ user });
93
- expect(res.status).toBe(BAD_REQUEST);
94
- const errorObj = parseValidationError(res.body.error);
95
- expect(errorObj.message).toBe(ValidationError.MESSAGE);
96
- expect(errorObj.errors[0].keyPath).toStrictEqual(['user', 'id']);
97
- },
98
- );
99
-
100
- it(
101
- 'should return a JSON object with the error message of ' +
102
- `"${UserService.Errors.USER_NOT_FOUND}" and a status code of ` +
103
- `"${NOT_FOUND}" if the id was not found.`,
104
- async () => {
105
- const user = User.new({ id: 4, name: 'a', email: 'a@a.com' }),
106
- res: TestRes = await agent.put(Paths.Users.Update()).send({ user });
107
- expect(res.status).toBe(NOT_FOUND);
108
- expect(res.body.error).toBe(UserService.Errors.USER_NOT_FOUND);
109
- },
110
- );
111
- });
112
-
113
- describe(`"DELETE:${Paths.Users.Delete()}"`, () => {
114
- it(`should return a status code of "${OK}" if the request was successful.`, async () => {
115
- const id = dbUsers[0].id,
116
- res = await agent.delete(Paths.Users.Delete({ id }));
117
- expect(res.status).toBe(OK);
118
- });
119
-
120
- it(
121
- 'should return a JSON object with the error message of ' +
122
- `"${UserService.Errors.USER_NOT_FOUND}" and a status code of ` +
123
- `"${NOT_FOUND}" if the id was not found.`,
124
- async () => {
125
- const res: TestRes = await agent.delete(Paths.Users.Delete({ id: -1 }));
126
- expect(res.status).toBe(NOT_FOUND);
127
- expect(res.body.error).toBe(UserService.Errors.USER_NOT_FOUND);
128
- },
129
- );
130
- });
131
- });