@anthonylzq/simba.js 1.10.0 → 2.0.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 +52 -24
- package/lib/src/functions/docker.js +2 -2
- package/lib/src/functions/eslint.js +1 -1
- package/lib/src/functions/express.js +438 -354
- package/lib/src/functions/tsconfig.js +38 -8
- package/lib/src/installation.js +1 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Set up a modern backend app by running one command. This project has the goal to
|
|
|
6
6
|
|
|
7
7
|
- `.env`
|
|
8
8
|
- `.eslintignore`
|
|
9
|
-
- `.eslintrc
|
|
9
|
+
- `.eslintrc`
|
|
10
10
|
- `.gitignore`
|
|
11
11
|
- `CHANGELOG.md`
|
|
12
12
|
- `Dockerfile`
|
|
@@ -15,8 +15,10 @@ Set up a modern backend app by running one command. This project has the goal to
|
|
|
15
15
|
- `nodemon.json`
|
|
16
16
|
- `package.json`
|
|
17
17
|
- `README.md`
|
|
18
|
+
- `tsconfig.base.json`
|
|
18
19
|
- `tsconfig.json`
|
|
19
20
|
- `webpack.config.js`
|
|
21
|
+
- `yarn.lock` (or `package-lock.json`)
|
|
20
22
|
|
|
21
23
|
## Installation
|
|
22
24
|
|
|
@@ -95,34 +97,56 @@ Developed by AnthonyLzq
|
|
|
95
97
|
Regardless of the option chosen, a new folder will be generated with the name of the project, it will contain the following structure:
|
|
96
98
|
|
|
97
99
|
```
|
|
98
|
-
|
|
99
|
-
|
|
100
|
+
📂node_modules
|
|
101
|
+
📂src
|
|
100
102
|
┣ 📂@types
|
|
101
|
-
┃ ┣
|
|
102
|
-
┣
|
|
103
|
-
┃
|
|
104
|
-
┃
|
|
105
|
-
|
|
106
|
-
┃ ┣
|
|
107
|
-
┃ ┗ 📜user.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
┃
|
|
103
|
+
┃ ┣ 📂custom
|
|
104
|
+
┃ ┃ ┣ 📜request.d.ts
|
|
105
|
+
┃ ┃ ┗ 📜response.d.ts
|
|
106
|
+
┃ ┣ 📂dto
|
|
107
|
+
┃ ┃ ┗ 📜user.d.ts
|
|
108
|
+
┃ ┣ 📂models
|
|
109
|
+
┃ ┃ ┗ 📜user.d.ts
|
|
110
|
+
┃ ┗ 📜index.d.ts
|
|
111
|
+
┣ 📂database
|
|
112
|
+
┃ ┣ 📂mongo
|
|
113
|
+
┃ ┃ ┣ 📂models
|
|
114
|
+
┃ ┃ ┃ ┣ 📜index.ts
|
|
115
|
+
┃ ┃ ┃ ┗ 📜user.ts
|
|
116
|
+
┃ ┃ ┣ 📂queries
|
|
117
|
+
┃ ┃ ┃ ┣ 📜index.ts
|
|
118
|
+
┃ ┃ ┃ ┗ 📜user.ts
|
|
119
|
+
┃ ┃ ┗ 📜index.ts
|
|
120
|
+
┃ ┗ 📜index.ts
|
|
111
121
|
┣ 📂network
|
|
122
|
+
┃ ┣ 📂routes
|
|
123
|
+
┃ ┃ ┣ 📂schemas
|
|
124
|
+
┃ ┃ ┃ ┣ 📜index.ts
|
|
125
|
+
┃ ┃ ┃ ┗ 📜user.ts
|
|
126
|
+
┃ ┃ ┣ 📜home.ts
|
|
127
|
+
┃ ┃ ┣ 📜index.ts
|
|
128
|
+
┃ ┃ ┗ 📜user.ts
|
|
112
129
|
┃ ┣ 📜index.ts
|
|
130
|
+
┃ ┣ 📜response.ts
|
|
113
131
|
┃ ┣ 📜routes.ts
|
|
114
132
|
┃ ┗ 📜server.ts
|
|
115
|
-
┣ 📂
|
|
116
|
-
┃ ┣
|
|
133
|
+
┣ 📂services
|
|
134
|
+
┃ ┣ 📂utils
|
|
135
|
+
┃ ┃ ┣ 📂messages
|
|
136
|
+
┃ ┃ ┃ ┣ 📜index.ts
|
|
137
|
+
┃ ┃ ┃ ┗ 📜user.ts
|
|
138
|
+
┃ ┃ ┗ 📜index.ts
|
|
117
139
|
┃ ┣ 📜index.ts
|
|
118
140
|
┃ ┗ 📜user.ts
|
|
141
|
+
┣ 📂test
|
|
142
|
+
┃ ┗ 📜test.http
|
|
119
143
|
┣ 📂utils
|
|
120
|
-
┃ ┣ 📜
|
|
121
|
-
┃ ┗ 📜
|
|
144
|
+
┃ ┣ 📜docs.json
|
|
145
|
+
┃ ┗ 📜index.ts
|
|
122
146
|
┗ 📜index.ts
|
|
123
147
|
📜.env
|
|
124
148
|
📜.eslintignore
|
|
125
|
-
📜.eslintrc
|
|
149
|
+
📜.eslintrc
|
|
126
150
|
📜.gitignore
|
|
127
151
|
📜CHANGELOG.md
|
|
128
152
|
📜Dockerfile
|
|
@@ -131,6 +155,7 @@ Regardless of the option chosen, a new folder will be generated with the name of
|
|
|
131
155
|
📜nodemon.json
|
|
132
156
|
📜package.json
|
|
133
157
|
📜README.md
|
|
158
|
+
📜tsconfig.base.json
|
|
134
159
|
📜tsconfig.json
|
|
135
160
|
📜webpack.config.js
|
|
136
161
|
📜yarn.lock (or package-lock.json)
|
|
@@ -160,8 +185,8 @@ simba -N myProject -D 'This is a test' -a myName -e myEmail@email.com -H
|
|
|
160
185
|
|
|
161
186
|
### Some considerations
|
|
162
187
|
|
|
163
|
-
- This project
|
|
164
|
-
- You are able to run a server that has one main route, `home` (`/`), `user` (`api/user` or `api/user/:
|
|
188
|
+
- This project was based in other project from my own, [`typescript-project-generator`](https://www.npmjs.com/package/typescript-project-generator), but only considering the `express-mongoose` part.
|
|
189
|
+
- You are able to run a server that has one main route, `home` (`/`), `user` (`api/user` or `api/user/:id`) and `docs` (`api/docs`).
|
|
165
190
|
- To connect your server with your `MongoDB` database, you need to provide your `uri` in the `.env`. By default, Simba will try to connect to a local database. The content of the `.env` file is:
|
|
166
191
|
|
|
167
192
|
```bash
|
|
@@ -182,11 +207,16 @@ simba -N myProject -D 'This is a test' -a myName -e myEmail@email.com -H
|
|
|
182
207
|
// Some more code...
|
|
183
208
|
|
|
184
209
|
// another file
|
|
185
|
-
globalStringVariable = 'Hi mom, I am global'
|
|
210
|
+
global.globalStringVariable = 'Hi mom, I am global'
|
|
186
211
|
console.log({ globalStringVariable })
|
|
187
212
|
```
|
|
188
213
|
|
|
189
|
-
- The provided project structure is inspired in my personal experience as [`Node.js`](https://nodejs.org/en/) developer and the [`Nest`](https://nestjs.com/) framework.
|
|
214
|
+
- The provided project structure is inspired in my personal experience as [`Node.js`](https://nodejs.org/en/) developer and the [`Nest`](https://nestjs.com/) framework. It follows a layered architecture:
|
|
215
|
+
|
|
216
|
+
1. Presentation layer (network layer): it is represented by the network folder, which contains the routes and the necessary schemas for each route.
|
|
217
|
+
2. Business layer (services layer): it is represented by the services folder, which contains all the code related to the business logic of your application.
|
|
218
|
+
3. Persistance layer (database layer): it is represented by the database folder, which contains the database connection, models and queries (that will be used by the services). Multiple database connection are possible and should be implemented here.
|
|
219
|
+
|
|
190
220
|
- The server is fully tested and has no errors (at least for now), feel free to report one [here](https://github.com/AnthonyLzq/simba.js/issues).
|
|
191
221
|
- Support for windows and linux platforms is available.
|
|
192
222
|
- To check the content of the files generated, please check the `example` folder.
|
|
@@ -215,8 +245,6 @@ Here is the list of the packages that are being installed, as `devDependencies`:
|
|
|
215
245
|
- [`eslint-config-standard`](https://www.npmjs.com/package/eslint-config-standard)
|
|
216
246
|
- [`eslint-plugin-import`](https://www.npmjs.com/package/eslint-plugin-import)
|
|
217
247
|
- [`eslint-plugin-prettier`](https://www.npmjs.com/package/eslint-plugin-prettier)
|
|
218
|
-
- [`eslint-plugin-sort-keys-fix`](https://www.npmjs.com/package/eslint-plugin-sort-keys-fix)
|
|
219
|
-
- [`eslint-plugin-typescript-sort-keys`](https://www.npmjs.com/package/eslint-plugin-typescript-sort-keys)
|
|
220
248
|
- [`nodemon`](https://www.npmjs.com/package/nodemon)
|
|
221
249
|
- [`prettier`](https://www.npmjs.com/package/prettier)
|
|
222
250
|
- [`standard-version`](https://www.npmjs.com/package/standard-version)
|
|
@@ -14,11 +14,11 @@ COPY package.json ./
|
|
|
14
14
|
|
|
15
15
|
RUN yarn install --prod
|
|
16
16
|
|
|
17
|
-
RUN yarn add webpack webpack-node-externals -D
|
|
17
|
+
RUN yarn add webpack webpack-node-externals tsconfig-paths-webpack-plugin -D
|
|
18
18
|
|
|
19
19
|
RUN yarn build
|
|
20
20
|
|
|
21
|
-
RUN yarn remove webpack webpack-node-externals
|
|
21
|
+
RUN yarn remove webpack webpack-node-externals tsconfig-paths-webpack-plugin
|
|
22
22
|
|
|
23
23
|
COPY dist /app/dist
|
|
24
24
|
|
|
@@ -5,30 +5,39 @@ const writeFile = require('../utils/writeFile')
|
|
|
5
5
|
/*
|
|
6
6
|
* src
|
|
7
7
|
* |- @types:
|
|
8
|
+
* |- |- dto:
|
|
9
|
+
* |- |- |- user: content, file
|
|
10
|
+
* |- |- models:
|
|
11
|
+
* |- |- |- user: content, file
|
|
8
12
|
* | |- index: content, file
|
|
9
|
-
* |-
|
|
10
|
-
* | |-
|
|
11
|
-
* |
|
|
13
|
+
* |- database:
|
|
14
|
+
* | |- mongo:
|
|
15
|
+
* | |- |- models:
|
|
16
|
+
* | |- |- |- index: content, file
|
|
17
|
+
* | |- |- |- user: content, file
|
|
18
|
+
* | |- |- queries:
|
|
19
|
+
* | |- |- |- index: content, file
|
|
20
|
+
* | |- |- |- user: content, file
|
|
21
|
+
* | |- |- index: content, file
|
|
22
|
+
* | |- index: content, file
|
|
23
|
+
* |- network:
|
|
24
|
+
* | |- routes:
|
|
25
|
+
* | | |- schemas:
|
|
12
26
|
* | | | |- user: content, file
|
|
13
27
|
* | | | |- index: content, file
|
|
28
|
+
* | | |- home: content, file
|
|
29
|
+
* | | |- user: content, file
|
|
14
30
|
* | | |- index: content, file
|
|
15
|
-
* | |-
|
|
16
|
-
* | |-
|
|
17
|
-
* |- dto-interfaces:
|
|
18
|
-
* | |- user: content, file
|
|
19
|
-
* | |- index: content, file
|
|
20
|
-
* |- models:
|
|
21
|
-
* | |- user: content, file
|
|
22
|
-
* | |- index: content, file
|
|
23
|
-
* |- network:
|
|
31
|
+
* | | |- response: content, file
|
|
32
|
+
* | |- router: content, file
|
|
24
33
|
* | |- server: content, file
|
|
25
|
-
* | |- routes: content, file
|
|
26
|
-
* | |- index: content, file
|
|
27
|
-
* |- routes:
|
|
28
|
-
* | |- home: content, file
|
|
29
|
-
* | |- user: content, file
|
|
30
34
|
* | |- index: content, file
|
|
31
|
-
* |-
|
|
35
|
+
* |- services:
|
|
36
|
+
* | |- utils:
|
|
37
|
+
* | | |- messages:
|
|
38
|
+
* | | | |- user: content, file
|
|
39
|
+
* | | | |- index: content, file
|
|
40
|
+
* | | |- index: content, file
|
|
32
41
|
* | |- user: content, file
|
|
33
42
|
* | |- index: content, file
|
|
34
43
|
* |- test:
|
|
@@ -50,268 +59,86 @@ module.exports = async (projectName, projectVersion, email) => {
|
|
|
50
59
|
'@types': {
|
|
51
60
|
index: {
|
|
52
61
|
content: `/* eslint-disable no-var */
|
|
53
|
-
|
|
54
|
-
import { Request, Response } from 'express'
|
|
55
|
-
|
|
56
|
-
import { DtoUser } from 'dto-interfaces'
|
|
57
|
-
|
|
58
|
-
declare global {
|
|
59
|
-
interface ResponseProps {
|
|
60
|
-
error: boolean
|
|
61
|
-
message: unknown
|
|
62
|
-
res: Response
|
|
63
|
-
status: number
|
|
64
|
-
}
|
|
65
|
-
// This variable is global, so it will be available everywhere in the code
|
|
66
|
-
var response: ({ error, message, res, status }: ResponseProps) => void
|
|
67
|
-
|
|
68
|
-
// We can personalize the response and request objects in case we need it by
|
|
69
|
-
// adding new optional attributes to this interface
|
|
70
|
-
interface CustomResponse extends Response {
|
|
71
|
-
newValue?: string
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
interface CustomRequest extends Request {
|
|
75
|
-
body: {
|
|
76
|
-
args?: DtoUser
|
|
77
|
-
}
|
|
78
|
-
// We can add custom headers via intersection, remember that for some reason
|
|
79
|
-
// headers must be in Snake-Pascal-Case
|
|
80
|
-
headers: IncomingHttpHeaders & {
|
|
81
|
-
'Custom-Header'?: string
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
62
|
+
declare global {}
|
|
85
63
|
|
|
86
64
|
export {}
|
|
87
65
|
`,
|
|
88
66
|
file: `${projectName}/src/@types/index.d.ts`
|
|
89
67
|
}
|
|
90
68
|
},
|
|
91
|
-
|
|
92
|
-
index: {
|
|
93
|
-
content: `import { User } from './user'
|
|
94
|
-
|
|
95
|
-
export { User }
|
|
96
|
-
`,
|
|
97
|
-
file: `${projectName}/src/controllers/index.ts`
|
|
98
|
-
},
|
|
69
|
+
'@types/dto': {
|
|
99
70
|
user: {
|
|
100
|
-
content: `
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
import { EFU, MFU, GE, errorHandling } from './utils'
|
|
105
|
-
|
|
106
|
-
type Process = {
|
|
107
|
-
type: 'store' | 'getAll' | 'deleteAll' | 'getOne' | 'update' | 'delete'
|
|
71
|
+
content: `interface DtoUser {
|
|
72
|
+
id?: string
|
|
73
|
+
lastName?: string
|
|
74
|
+
name?: string
|
|
108
75
|
}
|
|
76
|
+
`,
|
|
77
|
+
file: `${projectName}/src/@types/dto/user.d.ts`
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
'@types/custom': {
|
|
81
|
+
request: {
|
|
82
|
+
content: `type ExpressRequest = import('express').Request
|
|
109
83
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
constructor(args: DtoUser | null = null) {
|
|
114
|
-
this._args = args
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
public process({
|
|
118
|
-
type
|
|
119
|
-
}: Process): Promise<string> | Promise<IUser[]> | Promise<IUser> {
|
|
120
|
-
switch (type) {
|
|
121
|
-
case 'store':
|
|
122
|
-
return this._store()
|
|
123
|
-
case 'getAll':
|
|
124
|
-
return this._getAll()
|
|
125
|
-
case 'deleteAll':
|
|
126
|
-
return this._deleteAll()
|
|
127
|
-
case 'getOne':
|
|
128
|
-
return this._getOne()
|
|
129
|
-
case 'update':
|
|
130
|
-
return this._update()
|
|
131
|
-
case 'delete':
|
|
132
|
-
return this._delete()
|
|
133
|
-
default:
|
|
134
|
-
throw new httpErrors.InternalServerError(GE.INTERNAL_SERVER_ERROR)
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
private async _store(): Promise<IUser> {
|
|
139
|
-
const { lastName, name } = this._args as DtoUser
|
|
140
|
-
|
|
141
|
-
try {
|
|
142
|
-
const newUser = new UserModel({ lastName, name })
|
|
143
|
-
const result = await newUser.save()
|
|
144
|
-
|
|
145
|
-
return result
|
|
146
|
-
} catch (e) {
|
|
147
|
-
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
private async _getAll(): Promise<IUser[]> {
|
|
152
|
-
try {
|
|
153
|
-
const users = await UserModel.find({})
|
|
154
|
-
|
|
155
|
-
return users
|
|
156
|
-
} catch (e) {
|
|
157
|
-
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
private async _deleteAll(): Promise<string> {
|
|
162
|
-
try {
|
|
163
|
-
const usersDeleted = await UserModel.deleteMany({})
|
|
164
|
-
|
|
165
|
-
if (usersDeleted.deletedCount >= 1) return MFU.ALL_USERS_DELETED
|
|
166
|
-
|
|
167
|
-
if (usersDeleted.deletedCount === 0)
|
|
168
|
-
throw new httpErrors.BadRequest(EFU.NOTHING_TO_DELETE)
|
|
169
|
-
|
|
170
|
-
throw new httpErrors.InternalServerError(GE.INTERNAL_SERVER_ERROR)
|
|
171
|
-
} catch (e) {
|
|
172
|
-
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
private async _getOne(): Promise<IUser> {
|
|
177
|
-
const { id } = this._args as DtoUser
|
|
178
|
-
|
|
179
|
-
try {
|
|
180
|
-
const user = await UserModel.findById(id)
|
|
181
|
-
|
|
182
|
-
if (!user) throw new httpErrors.NotFound(EFU.NOT_FOUND)
|
|
183
|
-
|
|
184
|
-
return user
|
|
185
|
-
} catch (e) {
|
|
186
|
-
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
187
|
-
}
|
|
84
|
+
interface CustomRequest extends ExpressRequest {
|
|
85
|
+
body: {
|
|
86
|
+
args?: DtoUser
|
|
188
87
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
try {
|
|
194
|
-
const updatedUser = await UserModel.findByIdAndUpdate(
|
|
195
|
-
id,
|
|
196
|
-
{ lastName, name },
|
|
197
|
-
{ new: true }
|
|
198
|
-
)
|
|
199
|
-
|
|
200
|
-
if (!updatedUser) throw new httpErrors.NotFound(EFU.NOT_FOUND)
|
|
201
|
-
|
|
202
|
-
return updatedUser
|
|
203
|
-
} catch (e) {
|
|
204
|
-
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
private async _delete(): Promise<string> {
|
|
209
|
-
const { id } = this._args as DtoUser
|
|
210
|
-
|
|
211
|
-
try {
|
|
212
|
-
const deletedUser = await UserModel.findByIdAndRemove(id)
|
|
213
|
-
|
|
214
|
-
if (!deletedUser) throw new httpErrors.NotFound(EFU.NOT_FOUND)
|
|
215
|
-
|
|
216
|
-
return MFU.USER_DELETED
|
|
217
|
-
} catch (e) {
|
|
218
|
-
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
219
|
-
}
|
|
88
|
+
// We can add custom headers via intersection, remember that for some reason
|
|
89
|
+
// headers must be in Snake-Pascal-Case
|
|
90
|
+
headers: import('http').IncomingHttpHeaders & {
|
|
91
|
+
'Custom-Header'?: string
|
|
220
92
|
}
|
|
221
93
|
}
|
|
222
|
-
|
|
223
|
-
export { User }
|
|
224
94
|
`,
|
|
225
|
-
file: `${projectName}/src/
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
index: {
|
|
230
|
-
content: `import httpErrors from 'http-errors'
|
|
231
|
-
|
|
232
|
-
import { EFU, MFU, GE } from './messages'
|
|
233
|
-
|
|
234
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
235
|
-
const errorHandling = (e: any, message?: string): never => {
|
|
236
|
-
console.error(e)
|
|
237
|
-
|
|
238
|
-
if (e instanceof httpErrors.HttpError) throw e
|
|
95
|
+
file: `${projectName}/src/@types/custom/request.d.ts`
|
|
96
|
+
},
|
|
97
|
+
response: {
|
|
98
|
+
content: `type ExpressResponse = import('express').Response
|
|
239
99
|
|
|
240
|
-
|
|
100
|
+
interface CustomResponse extends ExpressResponse {
|
|
101
|
+
newValue?: string
|
|
241
102
|
}
|
|
242
|
-
|
|
243
|
-
export { EFU, MFU, GE, errorHandling }
|
|
244
103
|
`,
|
|
245
|
-
file: `${projectName}/src/
|
|
104
|
+
file: `${projectName}/src/@types/custom/response.d.ts`
|
|
246
105
|
}
|
|
247
106
|
},
|
|
248
|
-
'
|
|
249
|
-
index: {
|
|
250
|
-
content: `import { EFU, MFU } from './user'
|
|
251
|
-
|
|
252
|
-
enum GenericErrors {
|
|
253
|
-
INTERNAL_SERVER_ERROR = 'Something went wrong'
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
export { EFU, MFU, GenericErrors as GE }
|
|
257
|
-
`,
|
|
258
|
-
file: `${projectName}/src/controllers/utils/messages/index.ts`
|
|
259
|
-
},
|
|
107
|
+
'@types/models': {
|
|
260
108
|
user: {
|
|
261
|
-
content: `
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
enum MessageForUser {
|
|
267
|
-
ALL_USERS_DELETED = 'All the users were deleted successfully',
|
|
268
|
-
USER_DELETED = 'The requested user was successfully deleted'
|
|
109
|
+
content: `interface IUser {
|
|
110
|
+
_id: import('mongoose').Types.ObjectId
|
|
111
|
+
name: string
|
|
112
|
+
lastName: string
|
|
113
|
+
updatedAt: Date
|
|
269
114
|
}
|
|
270
|
-
|
|
271
|
-
export { ErrorForUser as EFU, MessageForUser as MFU }
|
|
272
115
|
`,
|
|
273
|
-
file: `${projectName}/src/
|
|
116
|
+
file: `${projectName}/src/@types/models/user.d.ts`
|
|
274
117
|
}
|
|
275
118
|
},
|
|
276
|
-
|
|
119
|
+
database: {
|
|
277
120
|
index: {
|
|
278
|
-
content:
|
|
279
|
-
|
|
280
|
-
export { DtoUser }
|
|
281
|
-
`,
|
|
282
|
-
file: `${projectName}/src/dto-interfaces/index.ts`
|
|
283
|
-
},
|
|
284
|
-
user: {
|
|
285
|
-
content: `interface DtoUser {
|
|
286
|
-
id: string
|
|
287
|
-
lastName?: string
|
|
288
|
-
name?: string
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
export { DtoUser }
|
|
292
|
-
`,
|
|
293
|
-
file: `${projectName}/src/dto-interfaces/user.ts`
|
|
121
|
+
content: "export * from './mongo'\n",
|
|
122
|
+
file: `${projectName}/src/database/index.ts`
|
|
294
123
|
}
|
|
295
124
|
},
|
|
296
|
-
|
|
125
|
+
'database/mongo': {
|
|
297
126
|
index: {
|
|
298
|
-
content: `
|
|
299
|
-
|
|
300
|
-
export { IUser, UserModel }
|
|
127
|
+
content: `export * from './models'
|
|
128
|
+
export * from './queries'
|
|
301
129
|
`,
|
|
302
|
-
file: `${projectName}/src/
|
|
130
|
+
file: `${projectName}/src/database/mongo/index.ts`
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
'database/mongo/models': {
|
|
134
|
+
index: {
|
|
135
|
+
content: "export * from './user'\n",
|
|
136
|
+
file: `${projectName}/src/database/mongo/models/index.ts`
|
|
303
137
|
},
|
|
304
138
|
user: {
|
|
305
|
-
content:
|
|
306
|
-
import { Document, model, Schema } from 'mongoose'
|
|
139
|
+
content: `import { model, Schema } from 'mongoose'
|
|
307
140
|
|
|
308
|
-
|
|
309
|
-
lastName: string
|
|
310
|
-
name: string
|
|
311
|
-
updatedAt: Date
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
const User = new Schema(
|
|
141
|
+
const User = new Schema<IUser>(
|
|
315
142
|
{
|
|
316
143
|
lastName: {
|
|
317
144
|
required: true,
|
|
@@ -326,36 +153,98 @@ const User = new Schema(
|
|
|
326
153
|
timestamps: {
|
|
327
154
|
createdAt: false,
|
|
328
155
|
updatedAt: true
|
|
156
|
+
},
|
|
157
|
+
toJSON: {
|
|
158
|
+
transform(_, ret) {
|
|
159
|
+
ret.id = ret._id
|
|
160
|
+
delete ret._id
|
|
161
|
+
delete ret.__v
|
|
162
|
+
delete ret.updatedAt
|
|
163
|
+
},
|
|
164
|
+
versionKey: false,
|
|
165
|
+
virtuals: true
|
|
329
166
|
}
|
|
330
167
|
}
|
|
331
168
|
)
|
|
332
169
|
|
|
333
|
-
User.set('toJSON', {
|
|
334
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
335
|
-
transform: function (_: any, ret: any) {
|
|
336
|
-
ret.id = ret._id
|
|
337
|
-
delete ret._id
|
|
338
|
-
delete ret.__v
|
|
339
|
-
delete ret.updatedAt
|
|
340
|
-
},
|
|
341
|
-
versionKey: false,
|
|
342
|
-
virtuals: true
|
|
343
|
-
})
|
|
344
|
-
|
|
345
170
|
const UserModel = model<IUser>('users', User)
|
|
346
171
|
|
|
347
|
-
export {
|
|
172
|
+
export { UserModel }
|
|
348
173
|
`,
|
|
349
|
-
file: `${projectName}/src/models/user.ts`
|
|
174
|
+
file: `${projectName}/src/database/mongo/models/user.ts`
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
'database/mongo/queries': {
|
|
178
|
+
index: {
|
|
179
|
+
content: "export * from './user'\n",
|
|
180
|
+
file: `${projectName}/src/database/mongo/queries/index.ts`
|
|
181
|
+
},
|
|
182
|
+
user: {
|
|
183
|
+
content: `import { UserModel } from '../models'
|
|
184
|
+
|
|
185
|
+
const store = async (userData: DtoUser): Promise<IUser> => {
|
|
186
|
+
const user = new UserModel(userData)
|
|
187
|
+
|
|
188
|
+
return await user.save()
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const remove = async (
|
|
192
|
+
id: string | null = null
|
|
193
|
+
): Promise<IUser | number | null> => {
|
|
194
|
+
if (id) return await UserModel.findByIdAndRemove(id)
|
|
195
|
+
|
|
196
|
+
return (await UserModel.deleteMany({})).deletedCount
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const get = async (
|
|
200
|
+
id: string | null = null
|
|
201
|
+
): Promise<IUser[] | IUser | null> => {
|
|
202
|
+
if (id) return await UserModel.findById(id)
|
|
203
|
+
|
|
204
|
+
return await UserModel.find({})
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const update = async (userData: DtoUser): Promise<IUser | null> => {
|
|
208
|
+
const { id, ...rest } = userData
|
|
209
|
+
|
|
210
|
+
return await UserModel.findByIdAndUpdate(id, rest, { new: true })
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export { store, remove, get, update }
|
|
214
|
+
`,
|
|
215
|
+
file: `${projectName}/src/database/mongo/queries/user.ts`
|
|
350
216
|
}
|
|
351
217
|
},
|
|
352
218
|
network: {
|
|
353
|
-
|
|
219
|
+
index: {
|
|
220
|
+
content: `export * from './routes'
|
|
221
|
+
export * from './server'
|
|
222
|
+
`,
|
|
223
|
+
file: `${projectName}/src/network/index.ts`
|
|
224
|
+
},
|
|
225
|
+
response: {
|
|
226
|
+
content: `interface ResponseProps {
|
|
227
|
+
error: boolean
|
|
228
|
+
message: unknown
|
|
229
|
+
res: CustomResponse
|
|
230
|
+
status: number
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const response = ({ error, message, res, status }: ResponseProps): void => {
|
|
234
|
+
res.status(status).send({ error, message })
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export { response }
|
|
238
|
+
`,
|
|
239
|
+
file: `${projectName}/src/network/response.ts`
|
|
240
|
+
},
|
|
241
|
+
router: {
|
|
354
242
|
content: `import { Application, Response, Request, Router, NextFunction } from 'express'
|
|
355
243
|
import swaggerUi from 'swagger-ui-express'
|
|
356
244
|
import httpErrors from 'http-errors'
|
|
357
245
|
|
|
358
|
-
import {
|
|
246
|
+
import { response } from './response'
|
|
247
|
+
import { Home, User } from './routes'
|
|
359
248
|
import { docs } from 'utils'
|
|
360
249
|
|
|
361
250
|
const routers = [User]
|
|
@@ -389,14 +278,14 @@ const applyRoutes = (app: Application): void => {
|
|
|
389
278
|
|
|
390
279
|
export { applyRoutes }
|
|
391
280
|
`,
|
|
392
|
-
file: `${projectName}/src/network/
|
|
281
|
+
file: `${projectName}/src/network/router.ts`
|
|
393
282
|
},
|
|
394
283
|
server: {
|
|
395
284
|
content: `import express from 'express'
|
|
396
285
|
import mongoose from 'mongoose'
|
|
397
286
|
import morgan from 'morgan'
|
|
398
287
|
|
|
399
|
-
import { applyRoutes } from './
|
|
288
|
+
import { applyRoutes } from './router'
|
|
400
289
|
|
|
401
290
|
const PORT = (process.env.PORT as string) || '1996'
|
|
402
291
|
|
|
@@ -430,16 +319,6 @@ class Server {
|
|
|
430
319
|
}
|
|
431
320
|
)
|
|
432
321
|
|
|
433
|
-
// setting up the global response
|
|
434
|
-
global.response = ({
|
|
435
|
-
error,
|
|
436
|
-
message,
|
|
437
|
-
res,
|
|
438
|
-
status
|
|
439
|
-
}: ResponseProps): void => {
|
|
440
|
-
res.status(status).send({ error, message })
|
|
441
|
-
}
|
|
442
|
-
|
|
443
322
|
applyRoutes(this._app)
|
|
444
323
|
}
|
|
445
324
|
|
|
@@ -495,20 +374,14 @@ const server = new Server()
|
|
|
495
374
|
export { server as Server }
|
|
496
375
|
`,
|
|
497
376
|
file: `${projectName}/src/network/server.ts`
|
|
498
|
-
},
|
|
499
|
-
index: {
|
|
500
|
-
content: `import { applyRoutes } from './routes'
|
|
501
|
-
import { Server } from './server'
|
|
502
|
-
|
|
503
|
-
export { applyRoutes, Server }
|
|
504
|
-
`,
|
|
505
|
-
file: `${projectName}/src/network/index.ts`
|
|
506
377
|
}
|
|
507
378
|
},
|
|
508
|
-
routes: {
|
|
379
|
+
'network/routes': {
|
|
509
380
|
home: {
|
|
510
381
|
content: `import { Response, Request, Router } from 'express'
|
|
511
382
|
|
|
383
|
+
import { response } from 'network/response'
|
|
384
|
+
|
|
512
385
|
const Home = Router()
|
|
513
386
|
|
|
514
387
|
Home.route('').get((req: Request, res: Response) => {
|
|
@@ -522,24 +395,22 @@ Home.route('').get((req: Request, res: Response) => {
|
|
|
522
395
|
|
|
523
396
|
export { Home }
|
|
524
397
|
`,
|
|
525
|
-
file: `${projectName}/src/routes/home.ts`
|
|
398
|
+
file: `${projectName}/src/network/routes/home.ts`
|
|
526
399
|
},
|
|
527
400
|
index: {
|
|
528
|
-
content: `
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
export { Home, User }
|
|
401
|
+
content: `export * from './home'
|
|
402
|
+
export * from './user'
|
|
532
403
|
`,
|
|
533
|
-
file: `${projectName}/src/routes/index.ts`
|
|
404
|
+
file: `${projectName}/src/network/routes/index.ts`
|
|
534
405
|
},
|
|
535
406
|
user: {
|
|
536
407
|
content: `import { Router, NextFunction } from 'express'
|
|
537
408
|
import httpErrors from 'http-errors'
|
|
538
409
|
import { ValidationError } from 'joi'
|
|
539
410
|
|
|
540
|
-
import {
|
|
541
|
-
import {
|
|
542
|
-
import { idSchema, userSchema } from 'schemas'
|
|
411
|
+
import { response } from 'network/response'
|
|
412
|
+
import { UserService } from 'services/user'
|
|
413
|
+
import { idSchema, userSchema } from './schemas'
|
|
543
414
|
|
|
544
415
|
const User = Router()
|
|
545
416
|
|
|
@@ -553,10 +424,10 @@ User.route('/users')
|
|
|
553
424
|
const {
|
|
554
425
|
body: { args }
|
|
555
426
|
} = req
|
|
556
|
-
const
|
|
427
|
+
const us = new UserService(args as DtoUser)
|
|
557
428
|
|
|
558
429
|
try {
|
|
559
|
-
const result = await
|
|
430
|
+
const result = await us.process({ type: 'store' })
|
|
560
431
|
response({ error: false, message: result, res, status: 201 })
|
|
561
432
|
} catch (e) {
|
|
562
433
|
next(e)
|
|
@@ -569,10 +440,10 @@ User.route('/users')
|
|
|
569
440
|
res: CustomResponse,
|
|
570
441
|
next: NextFunction
|
|
571
442
|
): Promise<void> => {
|
|
572
|
-
const
|
|
443
|
+
const us = new UserService()
|
|
573
444
|
|
|
574
445
|
try {
|
|
575
|
-
const result = await
|
|
446
|
+
const result = await us.process({ type: 'getAll' })
|
|
576
447
|
response({ error: false, message: result, res, status: 200 })
|
|
577
448
|
} catch (e) {
|
|
578
449
|
next(e)
|
|
@@ -585,10 +456,10 @@ User.route('/users')
|
|
|
585
456
|
res: CustomResponse,
|
|
586
457
|
next: NextFunction
|
|
587
458
|
): Promise<void> => {
|
|
588
|
-
const
|
|
459
|
+
const us = new UserService()
|
|
589
460
|
|
|
590
461
|
try {
|
|
591
|
-
const result = await
|
|
462
|
+
const result = await us.process({ type: 'deleteAll' })
|
|
592
463
|
response({ error: false, message: result, res, status: 200 })
|
|
593
464
|
} catch (e) {
|
|
594
465
|
next(e)
|
|
@@ -609,8 +480,8 @@ User.route('/user/:id')
|
|
|
609
480
|
|
|
610
481
|
try {
|
|
611
482
|
await idSchema.validateAsync(id)
|
|
612
|
-
const
|
|
613
|
-
const result = await
|
|
483
|
+
const us = new UserService({ id } as DtoUser)
|
|
484
|
+
const result = await us.process({ type: 'getOne' })
|
|
614
485
|
response({ error: false, message: result, res, status: 200 })
|
|
615
486
|
} catch (e) {
|
|
616
487
|
if (e instanceof ValidationError)
|
|
@@ -637,8 +508,8 @@ User.route('/user/:id')
|
|
|
637
508
|
|
|
638
509
|
try {
|
|
639
510
|
await userSchema.validateAsync(user)
|
|
640
|
-
const
|
|
641
|
-
const result = await
|
|
511
|
+
const us = new UserService(user)
|
|
512
|
+
const result = await us.process({ type: 'update' })
|
|
642
513
|
response({ error: false, message: result, res, status: 200 })
|
|
643
514
|
} catch (e) {
|
|
644
515
|
if (e instanceof ValidationError)
|
|
@@ -660,8 +531,8 @@ User.route('/user/:id')
|
|
|
660
531
|
|
|
661
532
|
try {
|
|
662
533
|
await idSchema.validateAsync(id)
|
|
663
|
-
const
|
|
664
|
-
const result = await
|
|
534
|
+
const us = new UserService({ id } as DtoUser)
|
|
535
|
+
const result = await us.process({ type: 'delete' })
|
|
665
536
|
response({ error: false, message: result, res, status: 200 })
|
|
666
537
|
} catch (e) {
|
|
667
538
|
if (e instanceof ValidationError)
|
|
@@ -674,20 +545,19 @@ User.route('/user/:id')
|
|
|
674
545
|
|
|
675
546
|
export { User }
|
|
676
547
|
`,
|
|
677
|
-
file: `${projectName}/src/routes/user.ts`
|
|
548
|
+
file: `${projectName}/src/network/routes/user.ts`
|
|
678
549
|
}
|
|
679
550
|
},
|
|
680
|
-
schemas: {
|
|
551
|
+
'network/routes/schemas': {
|
|
681
552
|
index: {
|
|
682
553
|
content: `import Joi from 'joi'
|
|
683
554
|
|
|
684
|
-
import { userSchema } from './user'
|
|
685
|
-
|
|
686
555
|
const idSchema = Joi.string().length(24).required()
|
|
687
556
|
|
|
688
|
-
export { idSchema
|
|
557
|
+
export { idSchema }
|
|
558
|
+
export * from './user'
|
|
689
559
|
`,
|
|
690
|
-
file: `${projectName}/src/schemas/index.ts`
|
|
560
|
+
file: `${projectName}/src/network/routes/schemas/index.ts`
|
|
691
561
|
},
|
|
692
562
|
user: {
|
|
693
563
|
content: `import Joi from 'joi'
|
|
@@ -700,7 +570,175 @@ const userSchema = Joi.object().keys({
|
|
|
700
570
|
|
|
701
571
|
export { userSchema }
|
|
702
572
|
`,
|
|
703
|
-
file: `${projectName}/src/schemas/user.ts`
|
|
573
|
+
file: `${projectName}/src/network/routes/schemas/user.ts`
|
|
574
|
+
}
|
|
575
|
+
},
|
|
576
|
+
services: {
|
|
577
|
+
index: {
|
|
578
|
+
content: "export * from './user'\n",
|
|
579
|
+
file: `${projectName}/src/services/index.ts`
|
|
580
|
+
},
|
|
581
|
+
user: {
|
|
582
|
+
content: `import httpErrors from 'http-errors'
|
|
583
|
+
|
|
584
|
+
import { store, remove, get, update } from 'database'
|
|
585
|
+
import { EFU, MFU, GE, errorHandling } from './utils'
|
|
586
|
+
|
|
587
|
+
type Process = {
|
|
588
|
+
type: 'store' | 'getAll' | 'deleteAll' | 'getOne' | 'update' | 'delete'
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
class UserService {
|
|
592
|
+
private _args: DtoUser | null
|
|
593
|
+
|
|
594
|
+
constructor(args: DtoUser | null = null) {
|
|
595
|
+
this._args = args
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
public process({ type }: Process): Promise<string | IUser[] | IUser> {
|
|
599
|
+
switch (type) {
|
|
600
|
+
case 'store':
|
|
601
|
+
return this._store()
|
|
602
|
+
case 'getAll':
|
|
603
|
+
return this._getAll()
|
|
604
|
+
case 'deleteAll':
|
|
605
|
+
return this._deleteAll()
|
|
606
|
+
case 'getOne':
|
|
607
|
+
return this._getOne()
|
|
608
|
+
case 'update':
|
|
609
|
+
return this._update()
|
|
610
|
+
case 'delete':
|
|
611
|
+
return this._delete()
|
|
612
|
+
default:
|
|
613
|
+
throw new httpErrors.InternalServerError(GE.INTERNAL_SERVER_ERROR)
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
private async _store(): Promise<IUser> {
|
|
618
|
+
try {
|
|
619
|
+
const result = await store(this._args as DtoUser)
|
|
620
|
+
|
|
621
|
+
return result
|
|
622
|
+
} catch (e) {
|
|
623
|
+
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
private async _getAll(): Promise<IUser[]> {
|
|
628
|
+
try {
|
|
629
|
+
const users = (await get()) as IUser[]
|
|
630
|
+
|
|
631
|
+
return users
|
|
632
|
+
} catch (e) {
|
|
633
|
+
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
private async _deleteAll(): Promise<string> {
|
|
638
|
+
try {
|
|
639
|
+
const usersDeleted = (await remove()) as number
|
|
640
|
+
|
|
641
|
+
if (usersDeleted >= 1) return MFU.ALL_USERS_DELETED
|
|
642
|
+
|
|
643
|
+
if (usersDeleted === 0)
|
|
644
|
+
throw new httpErrors.Conflict(EFU.NOTHING_TO_DELETE)
|
|
645
|
+
|
|
646
|
+
throw new httpErrors.InternalServerError(GE.INTERNAL_SERVER_ERROR)
|
|
647
|
+
} catch (e) {
|
|
648
|
+
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
private async _getOne(): Promise<IUser> {
|
|
653
|
+
const { id } = this._args as DtoUser
|
|
654
|
+
|
|
655
|
+
try {
|
|
656
|
+
const user = (await get(id as string)) as IUser | null
|
|
657
|
+
|
|
658
|
+
if (!user) throw new httpErrors.NotFound(EFU.NOT_FOUND)
|
|
659
|
+
|
|
660
|
+
return user
|
|
661
|
+
} catch (e) {
|
|
662
|
+
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
private async _update(): Promise<IUser> {
|
|
667
|
+
try {
|
|
668
|
+
const updatedUser = await update(this._args as DtoUser)
|
|
669
|
+
|
|
670
|
+
if (!updatedUser) throw new httpErrors.NotFound(EFU.NOT_FOUND)
|
|
671
|
+
|
|
672
|
+
return updatedUser
|
|
673
|
+
} catch (e) {
|
|
674
|
+
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
private async _delete(): Promise<string> {
|
|
679
|
+
const { id } = this._args as DtoUser
|
|
680
|
+
|
|
681
|
+
try {
|
|
682
|
+
const deletedUser = await remove(id)
|
|
683
|
+
|
|
684
|
+
if (!deletedUser) throw new httpErrors.NotFound(EFU.NOT_FOUND)
|
|
685
|
+
|
|
686
|
+
return MFU.USER_DELETED
|
|
687
|
+
} catch (e) {
|
|
688
|
+
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
export { UserService }
|
|
694
|
+
`,
|
|
695
|
+
file: `${projectName}/src/services/user.ts`
|
|
696
|
+
}
|
|
697
|
+
},
|
|
698
|
+
'services/utils': {
|
|
699
|
+
index: {
|
|
700
|
+
content: `import httpErrors from 'http-errors'
|
|
701
|
+
|
|
702
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
703
|
+
const errorHandling = (e: any, message?: string): never => {
|
|
704
|
+
console.error(e)
|
|
705
|
+
|
|
706
|
+
if (e instanceof httpErrors.HttpError) throw e
|
|
707
|
+
|
|
708
|
+
throw new httpErrors.InternalServerError(message ?? e.message)
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
export { errorHandling }
|
|
712
|
+
export * from './messages'
|
|
713
|
+
`,
|
|
714
|
+
file: `${projectName}/src/services/utils/index.ts`
|
|
715
|
+
}
|
|
716
|
+
},
|
|
717
|
+
'services/utils/messages': {
|
|
718
|
+
index: {
|
|
719
|
+
content: `enum GenericErrors {
|
|
720
|
+
INTERNAL_SERVER_ERROR = 'Something went wrong'
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
export { GenericErrors as GE }
|
|
724
|
+
export * from './user'
|
|
725
|
+
`,
|
|
726
|
+
file: `${projectName}/src/services/utils/messages/index.ts`
|
|
727
|
+
},
|
|
728
|
+
user: {
|
|
729
|
+
content: `enum ErrorForUser {
|
|
730
|
+
NOT_FOUND = 'The requested user does not exists',
|
|
731
|
+
NOTHING_TO_DELETE = 'There is no user to be deleted'
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
enum MessageForUser {
|
|
735
|
+
ALL_USERS_DELETED = 'All the users were deleted successfully',
|
|
736
|
+
USER_DELETED = 'The requested user was successfully deleted'
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
export { ErrorForUser as EFU, MessageForUser as MFU }
|
|
740
|
+
`,
|
|
741
|
+
file: `${projectName}/src/services/utils/messages/user.ts`
|
|
704
742
|
}
|
|
705
743
|
},
|
|
706
744
|
test: {
|
|
@@ -1164,10 +1202,7 @@ DELETE http://localhost:1996/api/user/60e7e3b93b01c1a7aa74cd6b
|
|
|
1164
1202
|
file: `${projectName}/src/utils/docs.json`
|
|
1165
1203
|
},
|
|
1166
1204
|
index: {
|
|
1167
|
-
content:
|
|
1168
|
-
|
|
1169
|
-
export { docs }
|
|
1170
|
-
`,
|
|
1205
|
+
content: "export { default as docs } from './docs.json'\n",
|
|
1171
1206
|
file: `${projectName}/src/utils/index.ts`
|
|
1172
1207
|
}
|
|
1173
1208
|
},
|
|
@@ -1186,14 +1221,19 @@ Server.start()
|
|
|
1186
1221
|
|
|
1187
1222
|
await exec(`mkdir ${projectName}/src \
|
|
1188
1223
|
${projectName}/src/@types \
|
|
1189
|
-
${projectName}/src/
|
|
1190
|
-
${projectName}/src/
|
|
1191
|
-
${projectName}/src/
|
|
1192
|
-
${projectName}/src/
|
|
1193
|
-
${projectName}/src/
|
|
1224
|
+
${projectName}/src/@types/dto \
|
|
1225
|
+
${projectName}/src/@types/custom \
|
|
1226
|
+
${projectName}/src/@types/models \
|
|
1227
|
+
${projectName}/src/services \
|
|
1228
|
+
${projectName}/src/services/utils \
|
|
1229
|
+
${projectName}/src/services/utils/messages \
|
|
1230
|
+
${projectName}/src/database \
|
|
1231
|
+
${projectName}/src/database/mongo \
|
|
1232
|
+
${projectName}/src/database/mongo/models \
|
|
1233
|
+
${projectName}/src/database/mongo/queries \
|
|
1194
1234
|
${projectName}/src/network \
|
|
1195
|
-
${projectName}/src/routes \
|
|
1196
|
-
${projectName}/src/schemas \
|
|
1235
|
+
${projectName}/src/network/routes \
|
|
1236
|
+
${projectName}/src/network/routes/schemas \
|
|
1197
1237
|
${projectName}/src/test \
|
|
1198
1238
|
${projectName}/src/utils
|
|
1199
1239
|
`)
|
|
@@ -1201,53 +1241,97 @@ ${projectName}/src/utils
|
|
|
1201
1241
|
// /@types
|
|
1202
1242
|
await writeFile(data['@types'].index.file, data['@types'].index.content)
|
|
1203
1243
|
|
|
1204
|
-
// /
|
|
1205
|
-
await writeFile(
|
|
1206
|
-
|
|
1244
|
+
// /@types/custom
|
|
1245
|
+
await writeFile(
|
|
1246
|
+
data['@types/custom'].request.file,
|
|
1247
|
+
data['@types/custom'].request.content
|
|
1248
|
+
)
|
|
1249
|
+
await writeFile(
|
|
1250
|
+
data['@types/custom'].response.file,
|
|
1251
|
+
data['@types/custom'].response.content
|
|
1252
|
+
)
|
|
1253
|
+
|
|
1254
|
+
// /@types/dto
|
|
1255
|
+
await writeFile(data['@types/dto'].user.file, data['@types/dto'].user.content)
|
|
1207
1256
|
|
|
1208
|
-
// /
|
|
1257
|
+
// /@types/models
|
|
1209
1258
|
await writeFile(
|
|
1210
|
-
data['
|
|
1211
|
-
data['
|
|
1259
|
+
data['@types/models'].user.file,
|
|
1260
|
+
data['@types/models'].user.content
|
|
1212
1261
|
)
|
|
1213
1262
|
|
|
1214
|
-
// /
|
|
1263
|
+
// /services
|
|
1264
|
+
await writeFile(data.services.user.file, data.services.user.content)
|
|
1265
|
+
await writeFile(data.services.index.file, data.services.index.content)
|
|
1266
|
+
|
|
1267
|
+
// /database
|
|
1268
|
+
await writeFile(data.database.index.file, data.database.index.content)
|
|
1215
1269
|
await writeFile(
|
|
1216
|
-
data['
|
|
1217
|
-
data['
|
|
1270
|
+
data['database/mongo'].index.file,
|
|
1271
|
+
data['database/mongo'].index.content
|
|
1218
1272
|
)
|
|
1219
1273
|
await writeFile(
|
|
1220
|
-
data['
|
|
1221
|
-
data['
|
|
1274
|
+
data['database/mongo/models'].index.file,
|
|
1275
|
+
data['database/mongo/models'].index.content
|
|
1222
1276
|
)
|
|
1223
|
-
|
|
1224
|
-
// /dto-interfaces
|
|
1225
1277
|
await writeFile(
|
|
1226
|
-
data['
|
|
1227
|
-
data['
|
|
1278
|
+
data['database/mongo/models'].user.file,
|
|
1279
|
+
data['database/mongo/models'].user.content
|
|
1228
1280
|
)
|
|
1229
1281
|
await writeFile(
|
|
1230
|
-
data['
|
|
1231
|
-
data['
|
|
1282
|
+
data['database/mongo/queries'].index.file,
|
|
1283
|
+
data['database/mongo/queries'].index.content
|
|
1284
|
+
)
|
|
1285
|
+
await writeFile(
|
|
1286
|
+
data['database/mongo/queries'].user.file,
|
|
1287
|
+
data['database/mongo/queries'].user.content
|
|
1232
1288
|
)
|
|
1233
1289
|
|
|
1234
|
-
// /
|
|
1235
|
-
await writeFile(
|
|
1236
|
-
|
|
1290
|
+
// /services/utils
|
|
1291
|
+
await writeFile(
|
|
1292
|
+
data['services/utils'].index.file,
|
|
1293
|
+
data['services/utils'].index.content
|
|
1294
|
+
)
|
|
1295
|
+
|
|
1296
|
+
// /services/utils/messages
|
|
1297
|
+
await writeFile(
|
|
1298
|
+
data['services/utils/messages'].user.file,
|
|
1299
|
+
data['services/utils/messages'].user.content
|
|
1300
|
+
)
|
|
1301
|
+
await writeFile(
|
|
1302
|
+
data['services/utils/messages'].index.file,
|
|
1303
|
+
data['services/utils/messages'].index.content
|
|
1304
|
+
)
|
|
1237
1305
|
|
|
1238
1306
|
// /network
|
|
1239
|
-
await writeFile(data.network.routes.file, data.network.routes.content)
|
|
1240
|
-
await writeFile(data.network.server.file, data.network.server.content)
|
|
1241
1307
|
await writeFile(data.network.index.file, data.network.index.content)
|
|
1308
|
+
await writeFile(data.network.response.file, data.network.response.content)
|
|
1309
|
+
await writeFile(data.network.router.file, data.network.router.content)
|
|
1310
|
+
await writeFile(data.network.server.file, data.network.server.content)
|
|
1242
1311
|
|
|
1243
|
-
// /routes
|
|
1244
|
-
await writeFile(
|
|
1245
|
-
|
|
1246
|
-
|
|
1312
|
+
// /network/routes
|
|
1313
|
+
await writeFile(
|
|
1314
|
+
data['network/routes'].home.file,
|
|
1315
|
+
data['network/routes'].home.content
|
|
1316
|
+
)
|
|
1317
|
+
await writeFile(
|
|
1318
|
+
data['network/routes'].user.file,
|
|
1319
|
+
data['network/routes'].user.content
|
|
1320
|
+
)
|
|
1321
|
+
await writeFile(
|
|
1322
|
+
data['network/routes'].index.file,
|
|
1323
|
+
data['network/routes'].index.content
|
|
1324
|
+
)
|
|
1247
1325
|
|
|
1248
|
-
// /schemas
|
|
1249
|
-
await writeFile(
|
|
1250
|
-
|
|
1326
|
+
// /network/routes/schemas
|
|
1327
|
+
await writeFile(
|
|
1328
|
+
data['network/routes/schemas'].index.file,
|
|
1329
|
+
data['network/routes/schemas'].index.content
|
|
1330
|
+
)
|
|
1331
|
+
await writeFile(
|
|
1332
|
+
data['network/routes/schemas'].user.file,
|
|
1333
|
+
data['network/routes/schemas'].user.content
|
|
1334
|
+
)
|
|
1251
1335
|
|
|
1252
1336
|
// /test
|
|
1253
1337
|
await writeFile(data.test.index.file, data.test.index.content)
|
|
@@ -6,7 +6,8 @@ const writeFile = require('../utils/writeFile')
|
|
|
6
6
|
*/
|
|
7
7
|
module.exports = async projectName => {
|
|
8
8
|
const data = {
|
|
9
|
-
|
|
9
|
+
base: {
|
|
10
|
+
content: `{
|
|
10
11
|
"ts-node": {
|
|
11
12
|
"files": true,
|
|
12
13
|
"require": ["tsconfig-paths/register"]
|
|
@@ -25,8 +26,8 @@ module.exports = async projectName => {
|
|
|
25
26
|
// "declaration": true, /* Generates corresponding '.d.ts' file. */
|
|
26
27
|
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
|
27
28
|
// "outFile": "./", /* Concatenate and emit output to single file. */
|
|
28
|
-
"outDir": "
|
|
29
|
-
"rootDir": "
|
|
29
|
+
"outDir": "dist" /* Redirect output structure to the directory. */,
|
|
30
|
+
"rootDir": "src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
|
|
30
31
|
// "composite": true, /* Enable project compilation */
|
|
31
32
|
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
|
32
33
|
// "removeComments": true, /* Do not emit comments to output. */
|
|
@@ -53,7 +54,7 @@ module.exports = async projectName => {
|
|
|
53
54
|
|
|
54
55
|
/* Module Resolution Options */
|
|
55
56
|
"moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
|
|
56
|
-
"baseUrl": "
|
|
57
|
+
"baseUrl": "src", /* Base directory to resolve non-absolute module names. */
|
|
57
58
|
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
|
58
59
|
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
|
59
60
|
// "typeRoots": [], /* List of folders to include type definitions from. */
|
|
@@ -79,12 +80,41 @@ module.exports = async projectName => {
|
|
|
79
80
|
"skipLibCheck": true /* Skip type checking of declaration files. */,
|
|
80
81
|
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
|
|
81
82
|
},
|
|
82
|
-
"include": [
|
|
83
|
-
|
|
83
|
+
"include": [
|
|
84
|
+
"src",
|
|
85
|
+
"test",
|
|
86
|
+
"tests",
|
|
87
|
+
"__test__"
|
|
88
|
+
],
|
|
89
|
+
"exclude": [
|
|
90
|
+
"node_modules"
|
|
91
|
+
]
|
|
84
92
|
}
|
|
85
93
|
`,
|
|
86
|
-
|
|
94
|
+
file: 'tsconfig.base.json'
|
|
95
|
+
},
|
|
96
|
+
prod: {
|
|
97
|
+
content: `{
|
|
98
|
+
"compilerOptions": {
|
|
99
|
+
"rootDir": "src"
|
|
100
|
+
},
|
|
101
|
+
"extends": "./tsconfig.base.json",
|
|
102
|
+
"exclude": [
|
|
103
|
+
"node_modules",
|
|
104
|
+
"test",
|
|
105
|
+
"tests",
|
|
106
|
+
"__test__",
|
|
107
|
+
"dist"
|
|
108
|
+
],
|
|
109
|
+
"include": [
|
|
110
|
+
"src"
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
`,
|
|
114
|
+
file: 'tsconfig.json'
|
|
115
|
+
}
|
|
87
116
|
}
|
|
88
117
|
|
|
89
|
-
await writeFile(`${projectName}/${data.
|
|
118
|
+
await writeFile(`${projectName}/${data.base.file}`, data.base.content)
|
|
119
|
+
await writeFile(`${projectName}/${data.prod.file}`, data.prod.content)
|
|
90
120
|
}
|
package/lib/src/installation.js
CHANGED
|
@@ -56,7 +56,7 @@ module.exports = async ({
|
|
|
56
56
|
cliProgress.Presets.shades_classic
|
|
57
57
|
)
|
|
58
58
|
|
|
59
|
-
const prodPackages = `${manager} express
|
|
59
|
+
const prodPackages = `${manager} express http-errors joi mongoose morgan swagger-ui-express`
|
|
60
60
|
const devPackages = `${manager} -D \
|
|
61
61
|
@types/express \
|
|
62
62
|
@types/http-errors \
|
|
@@ -71,8 +71,6 @@ eslint-config-prettier \
|
|
|
71
71
|
eslint-config-standard \
|
|
72
72
|
eslint-plugin-import \
|
|
73
73
|
eslint-plugin-prettier \
|
|
74
|
-
eslint-plugin-sort-keys-fix \
|
|
75
|
-
eslint-plugin-typescript-sort-keys \
|
|
76
74
|
nodemon \
|
|
77
75
|
prettier \
|
|
78
76
|
standard-version \
|