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.
- package/LICENSE +0 -0
- package/README.md +0 -0
- package/lib/cli.js +0 -0
- package/lib/express-generator-typescript.js +44 -11
- package/lib/project-files/.prettierignore +12 -0
- package/lib/project-files/.prettierrc.json +15 -0
- package/lib/project-files/README.md +54 -65
- package/lib/project-files/config/.env.development +0 -0
- package/lib/project-files/config/.env.production +0 -0
- package/lib/project-files/config/.env.test +0 -0
- package/lib/project-files/eslint.config.ts +46 -100
- package/lib/project-files/gitignore +0 -2
- package/lib/project-files/package.json +62 -56
- package/lib/project-files/src/common/constants/HttpStatusCodes.ts +393 -394
- package/lib/project-files/src/common/constants/Paths.ts +15 -15
- package/lib/project-files/src/common/constants/{EnvVars.ts → env.ts} +28 -19
- package/lib/project-files/src/common/utils/{misc.ts → number-utils.ts} +10 -11
- package/lib/project-files/src/common/utils/route-errors.ts +35 -36
- package/lib/project-files/src/common/utils/validators.ts +14 -14
- package/lib/project-files/src/{index.ts → main.ts} +24 -27
- package/lib/project-files/src/models/User.ts +73 -72
- package/lib/project-files/src/models/common/IModel.ts +4 -0
- package/lib/project-files/src/public/stylesheets/users.css +50 -48
- package/lib/project-files/src/repos/MockOrm.ts +57 -63
- package/lib/project-files/src/repos/UserRepo.ts +131 -133
- package/lib/project-files/src/repos/{database.json → common/database.json} +0 -0
- package/lib/project-files/src/repos/common/database.test.json +1 -0
- package/lib/project-files/src/routes/UserRoutes.ts +77 -69
- package/lib/project-files/src/routes/{index.ts → apiRouter.ts} +28 -28
- package/lib/project-files/src/routes/common/{types.ts → express-types.ts} +9 -10
- package/lib/project-files/src/routes/common/{utils.ts → parseReq.ts} +19 -16
- package/lib/project-files/src/server.ts +79 -84
- package/lib/project-files/src/services/{UserService/index.ts → UserService.ts} +64 -58
- package/lib/project-files/src/views/users.html +118 -132
- package/lib/project-files/tests/common/{utils.ts → comparators.ts} +38 -55
- package/lib/project-files/tests/common/error-utils.ts +25 -0
- package/lib/project-files/tests/common/{types.ts → supertest-types.ts} +15 -16
- package/lib/project-files/tests/{aux/setup.ts → support/agent.ts} +23 -26
- package/lib/project-files/tests/users.test.ts +131 -123
- package/lib/project-files/tsconfig.json +29 -35
- package/lib/project-files/tsconfig.prod.json +27 -30
- package/lib/project-files/vitest.config.mts +21 -18
- package/package.json +1 -1
- package/lib/project-files/config.ts +0 -22
- package/lib/project-files/scripts/build.ts +0 -28
- package/lib/project-files/scripts/common/utils.ts +0 -93
- package/lib/project-files/src/common/constants/index.ts +0 -11
- package/lib/project-files/src/models/common/types.ts +0 -5
- package/lib/project-files/src/repos/database.test.json +0 -1
- package/lib/project-files/src/services/UserService/constants.ts +0 -5
|
@@ -1,84 +1,79 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// Add
|
|
43
|
-
app.use(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
// Set
|
|
62
|
-
const
|
|
63
|
-
app.
|
|
64
|
-
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
import UserRepo from '@src/repos/UserRepo';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
-
<!
|
|
2
|
-
<html lang="en">
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
>
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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:
|
|
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:
|
|
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 {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
*
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
+
}
|