express-generator-typescript 2.8.1 → 2.9.0
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 +6 -7
- package/bin/cli.js +91 -32
- package/lib/express-generator-typescript.js +125 -151
- package/lib/{project-files → template}/.prettierignore +2 -4
- package/lib/template/README.md +50 -0
- package/lib/template/bs-config.js +8 -0
- package/lib/{project-files → template}/config/.env.development +4 -6
- package/lib/{project-files → template}/config/.env.production +4 -5
- package/lib/{project-files → template}/config/.env.test +4 -5
- package/lib/{project-files → template}/eslint.config.ts +4 -0
- package/lib/template/gitignore +10 -0
- package/lib/{project-files → template}/package.json +31 -35
- package/lib/{project-files → template}/src/common/constants/HttpStatusCodes.ts +7 -8
- package/lib/template/src/common/constants/Paths.ts +22 -0
- package/lib/template/src/common/constants/env.ts +28 -0
- package/lib/template/src/common/types/utility-types.ts +5 -0
- package/lib/template/src/common/utils/date-utils.ts +29 -0
- package/lib/template/src/common/utils/route-errors.ts +37 -0
- package/lib/template/src/main.ts +24 -0
- package/lib/template/src/models/User.model.ts +95 -0
- package/lib/template/src/models/common/types.ts +10 -0
- package/lib/template/src/public/scripts/http.js +25 -0
- package/lib/template/src/public/scripts/lib/bootstrap.bundle.min.js +4229 -0
- package/lib/template/src/public/scripts/renderUsers.js +90 -0
- package/lib/template/src/public/scripts/users.js +142 -0
- package/lib/template/src/public/stylesheets/lib/bootstrap.min.css +11798 -0
- package/lib/template/src/repos/MockOrm.ts +71 -0
- package/lib/{project-files → template}/src/repos/UserRepo.ts +21 -35
- package/lib/template/src/repos/common/database.json +28 -0
- package/lib/{project-files → template}/src/routes/UserRoutes.ts +15 -18
- package/lib/template/src/routes/apiRouter.ts +28 -0
- package/lib/template/src/routes/common/express-types.ts +9 -0
- package/lib/template/src/routes/common/parseReq.ts +23 -0
- package/lib/{project-files → template}/src/server.ts +23 -18
- package/lib/template/src/services/UserService.ts +66 -0
- package/lib/{project-files → template}/src/views/users.html +13 -6
- package/lib/{project-files → template}/tests/common/comparators.ts +6 -6
- package/lib/template/tests/common/supertest-types.ts +11 -0
- package/lib/template/tests/frontend.test.ts +33 -0
- package/lib/template/tests/support/agent.ts +23 -0
- package/lib/template/tests/users.test.ts +205 -0
- package/lib/{project-files → template}/tsconfig.json +1 -3
- package/lib/{project-files → template}/tsconfig.prod.json +3 -9
- package/lib/{project-files → template}/vitest.config.mts +2 -0
- package/package.json +69 -52
- package/lib/cli.js +0 -33
- package/lib/project-files/README.md +0 -39
- package/lib/project-files/gitignore +0 -4
- package/lib/project-files/src/common/constants/Paths.ts +0 -15
- package/lib/project-files/src/common/constants/env.ts +0 -28
- package/lib/project-files/src/common/types/structure-utils.ts +0 -2
- package/lib/project-files/src/common/utils/number-utils.ts +0 -10
- package/lib/project-files/src/common/utils/route-errors.ts +0 -35
- package/lib/project-files/src/common/utils/validators.ts +0 -14
- package/lib/project-files/src/main.ts +0 -24
- package/lib/project-files/src/models/User.model.ts +0 -72
- package/lib/project-files/src/models/common/types.ts +0 -4
- package/lib/project-files/src/public/stylesheets/lib/bootstrap.min.css +0 -6
- package/lib/project-files/src/repos/MockOrm.ts +0 -63
- package/lib/project-files/src/repos/common/database.json +0 -1
- package/lib/project-files/src/repos/common/database.test.json +0 -1
- package/lib/project-files/src/routes/apiRouter.ts +0 -28
- package/lib/project-files/src/routes/common/express-types.ts +0 -8
- package/lib/project-files/src/routes/common/parseReq.ts +0 -19
- package/lib/project-files/src/services/UserService.ts +0 -64
- package/lib/project-files/tests/common/error-utils.ts +0 -25
- package/lib/project-files/tests/common/supertest-types.ts +0 -15
- package/lib/project-files/tests/support/agent.ts +0 -23
- package/lib/project-files/tests/users.test.ts +0 -131
- /package/lib/{project-files → template}/.prettierrc.json +0 -0
- /package/lib/{project-files → template}/src/public/stylesheets/users.css +0 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// ========================================================================= //
|
|
2
|
+
// CONSTANTS //
|
|
3
|
+
// ========================================================================= //
|
|
4
|
+
|
|
5
|
+
const DateFormatter = new Intl.DateTimeFormat('en-US', {
|
|
6
|
+
year: 'numeric',
|
|
7
|
+
month: '2-digit',
|
|
8
|
+
day: '2-digit',
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const formatDate = (date) => DateFormatter.format(new Date(date));
|
|
12
|
+
|
|
13
|
+
const HTML_ESCAPES = {
|
|
14
|
+
'&': '&',
|
|
15
|
+
'<': '<',
|
|
16
|
+
'>': '>',
|
|
17
|
+
'"': '"',
|
|
18
|
+
"'": ''',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// User data is untrusted, so escape it before it goes into innerHTML
|
|
22
|
+
const esc = (val) => String(val).replace(/[&<>"']/g, (ch) => HTML_ESCAPES[ch]);
|
|
23
|
+
|
|
24
|
+
// ========================================================================= //
|
|
25
|
+
// FUNCTIONS //
|
|
26
|
+
// ========================================================================= //
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Render users
|
|
30
|
+
*/
|
|
31
|
+
function renderUsers(users) {
|
|
32
|
+
return users
|
|
33
|
+
.map((user) => {
|
|
34
|
+
return `
|
|
35
|
+
<div class="user-display-ele">
|
|
36
|
+
<div class="normal-view">
|
|
37
|
+
<div><b>Name:</b> ${esc(user.name)}</div>
|
|
38
|
+
<div><b>Email:</b> ${esc(user.email)}</div>
|
|
39
|
+
<div><b>Created:</b> ${esc(formatDate(user.created))}</div>
|
|
40
|
+
<button
|
|
41
|
+
type="button"
|
|
42
|
+
class="btn btn-primary edit-user-btn"
|
|
43
|
+
data-user-id="${esc(user.id)}"
|
|
44
|
+
>
|
|
45
|
+
Edit
|
|
46
|
+
</button>
|
|
47
|
+
<button
|
|
48
|
+
class="btn btn-danger delete-user-btn"
|
|
49
|
+
data-user-id="${esc(user.id)}"
|
|
50
|
+
>
|
|
51
|
+
Delete
|
|
52
|
+
</button>
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
<div class="edit-view">
|
|
56
|
+
<div>
|
|
57
|
+
Name:
|
|
58
|
+
<input
|
|
59
|
+
type="text"
|
|
60
|
+
class="form-control name-edit-input"
|
|
61
|
+
value="${esc(user.name)}"
|
|
62
|
+
/>
|
|
63
|
+
</div>
|
|
64
|
+
<div class="email-edit">
|
|
65
|
+
Email:
|
|
66
|
+
<input
|
|
67
|
+
type="email"
|
|
68
|
+
class="form-control email-edit-input"
|
|
69
|
+
value="${esc(user.email)}"
|
|
70
|
+
/>
|
|
71
|
+
</div>
|
|
72
|
+
<button
|
|
73
|
+
class="btn btn-primary submit-edit-btn"
|
|
74
|
+
data-user-id="${esc(user.id)}"
|
|
75
|
+
data-user-created="${esc(user.created)}"
|
|
76
|
+
>
|
|
77
|
+
Submit
|
|
78
|
+
</button>
|
|
79
|
+
<button
|
|
80
|
+
class="btn btn-secondary cancel-edit-btn"
|
|
81
|
+
data-user-id="${esc(user.id)}"
|
|
82
|
+
>
|
|
83
|
+
Cancel
|
|
84
|
+
</button>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
`;
|
|
88
|
+
})
|
|
89
|
+
.join('');
|
|
90
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// ========================================================================= //
|
|
2
|
+
// EXEC //
|
|
3
|
+
// ========================================================================= //
|
|
4
|
+
|
|
5
|
+
// Start
|
|
6
|
+
displayUsers();
|
|
7
|
+
|
|
8
|
+
// ========================================================================= //
|
|
9
|
+
// FUNCTIONS //
|
|
10
|
+
// ========================================================================= //
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Call api
|
|
14
|
+
*/
|
|
15
|
+
function displayUsers() {
|
|
16
|
+
Http.get('/api/users/all')
|
|
17
|
+
.then(checkResponse)
|
|
18
|
+
.then((resp) => resp.json())
|
|
19
|
+
.then((resp) => {
|
|
20
|
+
const allUsersAnchor = document.getElementById('all-users-anchor');
|
|
21
|
+
allUsersAnchor.innerHTML = renderUsers(resp.users);
|
|
22
|
+
})
|
|
23
|
+
.catch(showError);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Setup event listener for button click
|
|
27
|
+
document.addEventListener('click', (event) => {
|
|
28
|
+
var ele = event.target;
|
|
29
|
+
if (ele.matches('#add-user-btn')) {
|
|
30
|
+
addUser();
|
|
31
|
+
} else if (ele.matches('.edit-user-btn')) {
|
|
32
|
+
showEditView(ele.parentNode.parentNode);
|
|
33
|
+
} else if (ele.matches('.cancel-edit-btn')) {
|
|
34
|
+
cancelEdit(ele.parentNode.parentNode);
|
|
35
|
+
} else if (ele.matches('.submit-edit-btn')) {
|
|
36
|
+
submitEdit(ele);
|
|
37
|
+
} else if (ele.matches('.delete-user-btn')) {
|
|
38
|
+
deleteUser(ele);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Add a new user.
|
|
44
|
+
*/
|
|
45
|
+
function addUser() {
|
|
46
|
+
var nameInput = document.getElementById('name-input');
|
|
47
|
+
var emailInput = document.getElementById('email-input');
|
|
48
|
+
if (!nameInput.value || !emailInput.value) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
var data = {
|
|
52
|
+
user: {
|
|
53
|
+
name: nameInput.value,
|
|
54
|
+
email: emailInput.value,
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
Http.post('/api/users/add', data)
|
|
58
|
+
.then(checkResponse)
|
|
59
|
+
.then(() => {
|
|
60
|
+
nameInput.value = '';
|
|
61
|
+
emailInput.value = '';
|
|
62
|
+
displayUsers();
|
|
63
|
+
})
|
|
64
|
+
.catch(showError);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Show edit view.
|
|
69
|
+
*/
|
|
70
|
+
function showEditView(userEle) {
|
|
71
|
+
var normalView = userEle.getElementsByClassName('normal-view')[0];
|
|
72
|
+
var editView = userEle.getElementsByClassName('edit-view')[0];
|
|
73
|
+
normalView.style.display = 'none';
|
|
74
|
+
editView.style.display = 'block';
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Cancel edit.
|
|
79
|
+
*/
|
|
80
|
+
function cancelEdit(userEle) {
|
|
81
|
+
var normalView = userEle.getElementsByClassName('normal-view')[0];
|
|
82
|
+
var editView = userEle.getElementsByClassName('edit-view')[0];
|
|
83
|
+
normalView.style.display = 'block';
|
|
84
|
+
editView.style.display = 'none';
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Submit edit.
|
|
89
|
+
*/
|
|
90
|
+
function submitEdit(ele) {
|
|
91
|
+
var userEle = ele.parentNode.parentNode;
|
|
92
|
+
var nameInput = userEle.getElementsByClassName('name-edit-input')[0];
|
|
93
|
+
var emailInput = userEle.getElementsByClassName('email-edit-input')[0];
|
|
94
|
+
if (!nameInput.value || !emailInput.value) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
var data = {
|
|
98
|
+
user: {
|
|
99
|
+
id: ele.getAttribute('data-user-id'),
|
|
100
|
+
name: nameInput.value,
|
|
101
|
+
email: emailInput.value,
|
|
102
|
+
created: ele.getAttribute('data-user-created'),
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
Http.put('/api/users/update', data)
|
|
106
|
+
.then(checkResponse)
|
|
107
|
+
.then(() => displayUsers())
|
|
108
|
+
.catch(showError);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Delete a user
|
|
113
|
+
*/
|
|
114
|
+
function deleteUser(ele) {
|
|
115
|
+
var id = ele.getAttribute('data-user-id');
|
|
116
|
+
Http.delete('/api/users/delete?id=' + encodeURIComponent(id))
|
|
117
|
+
.then(checkResponse)
|
|
118
|
+
.then(() => displayUsers())
|
|
119
|
+
.catch(showError);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Reject non-2xx responses with the server's error message.
|
|
124
|
+
*/
|
|
125
|
+
function checkResponse(resp) {
|
|
126
|
+
if (resp.ok) {
|
|
127
|
+
return resp;
|
|
128
|
+
}
|
|
129
|
+
return resp
|
|
130
|
+
.json()
|
|
131
|
+
.catch(() => ({}))
|
|
132
|
+
.then((body) => {
|
|
133
|
+
throw new Error(body.error || 'Request failed: ' + resp.status);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Surface a failed request to the user.
|
|
139
|
+
*/
|
|
140
|
+
function showError(err) {
|
|
141
|
+
alert(err.message);
|
|
142
|
+
}
|