@anthonylzq/simba.js 2.1.1 → 3.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 CHANGED
@@ -1,24 +1,9 @@
1
1
  # Simba.js
2
2
 
3
+ [![NPM version](https://img.shields.io/npm/v/@anthonylzq/simba.js.svg?style=flat)](https://www.npmjs.com/package/@anthonylzq/simba.js)
3
4
  [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
4
5
 
5
- Set up a modern backend app by running one command. This project has the goal to create a complete setup for a backend application using `TypeScript` and `Express`. It will create many files that are usually created manually. Currently the following files are being created:
6
-
7
- - `.env`
8
- - `.eslintignore`
9
- - `.eslintrc`
10
- - `.gitignore`
11
- - `CHANGELOG.md`
12
- - `Dockerfile`
13
- - `heroku.yml` (optional)
14
- - `LICENSE` (optional, `MIT` as example)
15
- - `nodemon.json`
16
- - `package.json`
17
- - `README.md`
18
- - `tsconfig.base.json`
19
- - `tsconfig.json`
20
- - `webpack.config.js`
21
- - `yarn.lock` (or `package-lock.json`)
6
+ Set up a modern backend app by running one command. This project has the goal to create a complete setup for a backend application using `TypeScript` and `Express` or `Fastify`. It will create many files that are usually created manually. Think about Simba.js like a [CRA](https://create-react-app.dev/), but for backend development. Check the [**project structure**](#project-structure) for more information.
22
7
 
23
8
  ## Installation
24
9
 
@@ -38,7 +23,8 @@ simba -q
38
23
 
39
24
  By doing this your prompt will ask you the following questions:
40
25
 
41
- - `Yarn or npm?`, only one of them is valid.
26
+ - `Yarn or npm?`, only one of them is valid (lowercase).
27
+ - `Express or Fastify?`, only one of them is valid (lowercase).
42
28
  - `Project name:`, at least one character must be provided.
43
29
  - `Project description:`, at least one character must be provided.
44
30
  - `Author:`, at least one character must be provided.
@@ -57,8 +43,8 @@ simba -h
57
43
  This will generate the following output:
58
44
 
59
45
  ```bash
60
- simba [options] (if you it installed globally) or only simba if you want to be
61
- asked for the options one by one
46
+ "simba [options]" (if you it installed globally) or only "simba -q" if you want
47
+ to be asked for the options one by one
62
48
 
63
49
  Options:
64
50
  -N, --projectName Project name
@@ -72,13 +58,15 @@ Options:
72
58
  3.0, in lowercase without its version
73
59
  [default: "unlicensed"]
74
60
  -v, --version Project initial version [default: "0.1.0"]
75
- -y, --licenseYear Year when the license starts [default: "2021"]
61
+ -y, --licenseYear Year when the license starts [default: "2022"]
76
62
  -n, --npm Whether or not the project should use npm as package
77
63
  manager [boolean] [default: false]
78
64
  -f, --mainFile Main file of the project [default: "src/index.ts"]
79
65
  -q, --questions Whether or not you want to be asked to answer the
80
66
  questions related to the project one by one
81
67
  [boolean] [default: false]
68
+ -F, --fastify Whether or not you want to use Fastify for your
69
+ project [boolean] [default: false]
82
70
  -h, --help Show help [boolean]
83
71
 
84
72
  Examples:
@@ -88,7 +76,39 @@ Examples:
88
76
  Developed by AnthonyLzq
89
77
  ```
90
78
 
91
- Regardless of the option chosen, a new folder will be generated with the name of the project, it will contain the following structure:
79
+ ### Examples
80
+
81
+ Let's suppose you want to build a project that will be deployed to Heroku, so should run:
82
+
83
+ ```bash
84
+ simba -N myProject -D 'This is a test' -l mit -a myName -e myEmail@email.com -H
85
+ ```
86
+
87
+ Here we are specifying that we want to create a new project called `myProject` using the `MIT` license, my name and my email are respectively: `myName` and `myEmail@email.com` and I want to use heroku to deploy this server.
88
+
89
+ As default, `yarn` is selected as package manager, but if you don't want to use it, you can pass the flag `-n` or `--npm` as follows:
90
+
91
+ ```bash
92
+ simba -N myProject -D 'This is a test' -l mit -a myName -e myEmail@email.com -H -n
93
+ ```
94
+
95
+ And what if I want to use Fastify instead Express? Well, you only have to pass the `-F` flag:
96
+
97
+ ```bash
98
+ simba -N myProject -D 'This is a test' -l mit -a myName -e myEmail@email.com -H -F
99
+ ```
100
+
101
+ Finally, you may not want to use a license or one of the available licenses, don't worry, just don't pass the flag `-l` neither `--license` as follows:
102
+
103
+ ```bash
104
+ simba -N myProject -D 'This is a test' -a myName -e myEmail@email.com -H
105
+ ```
106
+
107
+ ## <a name="project-structure"></a>Project structure
108
+
109
+ Regardless of the option chosen, a new folder will be generated with the name of the project, it will contain the following structure, depending if you have chosen Express or Fastify:
110
+
111
+ ### Express case
92
112
 
93
113
  ```
94
114
  📂node_modules
@@ -143,6 +163,7 @@ Regardless of the option chosen, a new folder will be generated with the name of
143
163
  📜CHANGELOG.md
144
164
  📜Dockerfile
145
165
  📜heroku.yml
166
+ 📜index.http
146
167
  📜LICENSE
147
168
  📜nodemon.json
148
169
  📜package.json
@@ -154,27 +175,69 @@ Regardless of the option chosen, a new folder will be generated with the name of
154
175
  📜yarn.lock (or package-lock.json)
155
176
  ```
156
177
 
157
- ### Examples
158
-
159
- Let's suppose you want to build a project that will be deployed to Heroku, so should run:
178
+ ### Fastify case
160
179
 
161
- ```bash
162
- simba -N myProject -D 'This is a test' -l mit -a myName -e myEmail@email.com -H
163
180
  ```
164
-
165
- Here we are specifying that we want to create a new project called `myProject` using the `MIT` license, my name and my email are respectively: `myName` and `myEmail@email.com` and I want to use heroku to deploy this server.
166
-
167
- As default, `yarn` is selected as package manager, but if you don't want to use it, you can pass the flag `-n` or `--npm` as follows:
168
-
169
- ```bash
170
- simba -N myProject -D 'This is a test' -l mit -a myName -e myEmail@email.com -H -n
181
+ 📂node_modules
182
+ 📂src
183
+ ┣ 📂@types
184
+ 📂dto
185
+ ┃ ┃ ┗ 📜user.d.ts
186
+ ┃ ┣ 📂models
187
+ 📜user.d.ts
188
+ ┃ ┗ 📜index.d.ts
189
+ ┣ 📂database
190
+ ┃ ┣ 📂mongo
191
+ ┃ ┃ ┣ 📂models
192
+ ┃ ┃ ┃ ┣ 📜index.ts
193
+ ┃ ┃ ┃ ┗ 📜user.ts
194
+ ┃ ┃ ┣ 📂queries
195
+ ┃ ┃ ┃ ┣ 📜index.ts
196
+ ┃ ┃ ┃ ┗ 📜user.ts
197
+ ┃ ┃ ┗ 📜index.ts
198
+ ┃ ┗ 📜index.ts
199
+ ┣ 📂network
200
+ ┃ ┣ 📂routes
201
+ ┃ ┃ ┣ 📂schemas
202
+ ┃ ┃ ┃ ┣ 📜index.ts
203
+ ┃ ┃ ┃ ┗ 📜user.ts
204
+ ┃ ┃ ┣ 📜docs.ts
205
+ ┃ ┃ ┣ 📜home.ts
206
+ ┃ ┃ ┣ 📜index.ts
207
+ ┃ ┃ ┗ 📜user.ts
208
+ ┃ ┣ 📜index.ts
209
+ ┃ ┣ 📜response.ts
210
+ ┃ ┣ 📜routes.ts
211
+ ┃ ┗ 📜server.ts
212
+ ┣ 📂services
213
+ ┃ ┣ 📂utils
214
+ ┃ ┃ ┣ 📂messages
215
+ ┃ ┃ ┃ ┣ 📜index.ts
216
+ ┃ ┃ ┃ ┗ 📜user.ts
217
+ ┃ ┃ ┗ 📜index.ts
218
+ ┃ ┣ 📜index.ts
219
+ ┃ ┗ 📜user.ts
220
+ ┗ 📜index.ts
221
+ 📜.env
222
+ 📜.eslintignore
223
+ 📜.eslintrc
224
+ 📜.gitignore
225
+ 📜CHANGELOG.md
226
+ 📜Dockerfile
227
+ 📜heroku.yml
228
+ 📜index.http
229
+ 📜LICENSE
230
+ 📜nodemon.json
231
+ 📜package.json
232
+ 📜README.md
233
+ 📜index.http
234
+ 📜tsconfig.base.json
235
+ 📜tsconfig.json
236
+ 📜webpack.config.js
237
+ 📜yarn.lock (or package-lock.json)
171
238
  ```
172
239
 
173
- Finally, you may not want to use a license or one of the available licenses, don't worry, just don't pass the flag `-l` neither `--license` as follows:
174
-
175
- ```bash
176
- simba -N myProject -D 'This is a test' -a myName -e myEmail@email.com -H
177
- ```
240
+ If you want to check the content of the files, please check the [example](https://github.com/AnthonyLzq/simba.js/tree/master/example) folder, there you will an example for both, Express and Fastify.
178
241
 
179
242
  ### Some considerations
180
243
 
@@ -219,17 +282,14 @@ simba -N myProject -D 'This is a test' -a myName -e myEmail@email.com -H
219
282
 
220
283
  ## What is new?
221
284
 
222
- Please check the `changelog.md` file.
285
+ Please check the [`changelog.md`](https://github.com/AnthonyLzq/simba.js/blob/master/CHANGELOG.md) file.
223
286
 
224
287
  ## <a name="notes"></a>Notes
225
288
 
226
289
  Here is the list of the packages that are being installed, as `devDependencies`:
227
290
 
228
- - [`@types/express`](https://www.npmjs.com/package/@types/express)
229
291
  - [`@types/http-errors`](https://www.npmjs.com/package/@types/http-errors)
230
- - [`@types/morgan`](https://www.npmjs.com/package/@types/morgan)
231
- - [`@types/node`](https://www.npmjs.com/package/@types/node/v/14.17.5)
232
- - [`@types/swagger-ui-express`](https://www.npmjs.com/package/@types/swagger-ui-express)
292
+ - [`@types/node`](https://www.npmjs.com/package/@types/node)
233
293
  - [`@typescript-eslint/eslint-plugin`](https://www.npmjs.com/package/@typescript-eslint/eslint-plugin)
234
294
  - [`@typescript-eslint/parser`](https://www.npmjs.com/package/@typescript-eslint/parser)
235
295
  - [`dotenv`](https://www.npmjs.com/package/dotenv)
@@ -252,15 +312,38 @@ Here is the list of the packages that are being installed, as `devDependencies`:
252
312
 
253
313
  As `dependencies`:
254
314
 
255
- - [`express`](https://expressjs.com/)
256
315
  - [`http-errors`](https://www.npmjs.com/package/http-errors)
257
- - [`joi`](https://joi.dev/api/?v=17.4.2)
258
316
  - [`mongoose`](https://mongoosejs.com/)
317
+
318
+ ### Express case
319
+
320
+ As `devDependencies`:
321
+
322
+ - [`@types/express`](https://www.npmjs.com/package/@types/express)
323
+ - [`@types/morgan`](https://www.npmjs.com/package/@types/morgan)
324
+ - [`@types/swagger-ui-express`](https://www.npmjs.com/package/@types/swagger-ui-express)
325
+
326
+ As `dependencies`:
327
+
328
+ - [`express`](https://expressjs.com/)
329
+ - [`joi`](https://joi.dev/api/?v=17.4.2)
259
330
  - [`morgan`](https://www.npmjs.com/package/morgan)
260
331
  - [`swagger-ui-express`](https://www.npmjs.com/package/swagger-ui-express)
261
332
 
333
+ ### Fastify case
334
+
335
+ As `dependencies`:
336
+
337
+ - [`@sinclair/typebox`](https://www.npmjs.com/package/@sinclair/typebox)
338
+ - [`fastify`](https://www.npmjs.com/package/fastify)
339
+ - [`fastify-swagger`](https://www.npmjs.com/package/fastify-swagger)
340
+
262
341
  Feel free to contribute to this project. Every contribution will be appreciated.
263
342
 
264
343
  ## Author
265
344
 
266
345
  - **Anthony Luzquiños** - _Initial Work_ - _Documentation_ - [AnthonyLzq](https://github.com/AnthonyLzq).
346
+
347
+ ## Contributors
348
+
349
+ - **Andree Anchi** - _Bug reports_ - [andreewaD](https://github.com/andreewD).
package/lib/index.js CHANGED
@@ -2,7 +2,7 @@ const readLineSync = require('readline-sync')
2
2
  const yargs = require('yargs/yargs')
3
3
  const { hideBin } = require('yargs/helpers')
4
4
 
5
- const installation = require('./src/installation')
5
+ const installation = require('./src')
6
6
 
7
7
  const CURRENT_YEAR = `${new Date().getFullYear()}`
8
8
  const argv = yargs(hideBin(process.argv))
@@ -50,6 +50,8 @@ const argv = yargs(hideBin(process.argv))
50
50
  'q',
51
51
  'Whether or not you want to be asked to answer the questions related to the project one by one'
52
52
  )
53
+ .alias('F', 'fastify')
54
+ .describe('F', 'Whether or not you want to use Fastify for your project')
53
55
  .default({
54
56
  H: false,
55
57
  n: false,
@@ -57,9 +59,10 @@ const argv = yargs(hideBin(process.argv))
57
59
  l: 'unlicensed',
58
60
  v: '0.1.0',
59
61
  f: 'src/index.ts',
60
- q: false
62
+ q: false,
63
+ F: false
61
64
  })
62
- .boolean(['H', 'n', 'q'])
65
+ .boolean(['H', 'n', 'q', 'F'])
63
66
  .help('h')
64
67
  .alias('h', 'help')
65
68
  .epilog('Developed by AnthonyLzq').argv
@@ -76,7 +79,8 @@ const config = {
76
79
  licenseYear: CURRENT_YEAR,
77
80
  npm: false,
78
81
  manager: 'yarn add',
79
- mainFile: 'src/index.ts'
82
+ mainFile: 'src/index.ts',
83
+ fastify: false
80
84
  }
81
85
  const UNLICENSED = 'unlicensed'
82
86
  const LICENSES = [
@@ -113,6 +117,22 @@ const main = async () => {
113
117
 
114
118
  if (config.npm) config.manager = 'npm i'
115
119
 
120
+ readLineSync.promptCLLoop(
121
+ {
122
+ express: () => true,
123
+ yarn: () => {
124
+ config.fastify = true
125
+
126
+ return true
127
+ }
128
+ },
129
+ {
130
+ caseSensitive: false,
131
+ limitMessage: 'That is not a valid option',
132
+ prompt: '> Express or Fastify? '
133
+ }
134
+ )
135
+
116
136
  readLineSync.promptLoop(
117
137
  input => {
118
138
  config.projectName = input.toLowerCase()
@@ -218,6 +238,8 @@ const main = async () => {
218
238
 
219
239
  if (argv.heroku) config.heroku = true
220
240
 
241
+ if (argv.fastify) config.fastify = true
242
+
221
243
  if (!argv.license || argv.license === UNLICENSED)
222
244
  console.log('License was not provided')
223
245
  else {
@@ -265,6 +287,8 @@ const main = async () => {
265
287
  else config.mainFile = argv.mainFile
266
288
  }
267
289
 
290
+ console.log(config)
291
+
268
292
  await installation(config)
269
293
  }
270
294
 
@@ -4,8 +4,12 @@ const exec = util.promisify(require('child_process').exec)
4
4
  const writeFile = require('../utils/writeFile')
5
5
 
6
6
  /*
7
+ * Express api:
7
8
  * src
8
9
  * |- @types:
10
+ * |- |- custom:
11
+ * |- |- |- request: content, file
12
+ * |- |- |- response: content, file
9
13
  * |- |- dto:
10
14
  * |- |- |- user: content, file
11
15
  * |- |- models:
@@ -27,9 +31,9 @@ const writeFile = require('../utils/writeFile')
27
31
  * | | | |- user: content, file
28
32
  * | | | |- index: content, file
29
33
  * | | |- home: content, file
30
- * | | |- user: content, file
31
34
  * | | |- index: content, file
32
- * | | |- response: content, file
35
+ * | | |- user: content, file
36
+ * | |- response: content, file
33
37
  * | |- router: content, file
34
38
  * | |- server: content, file
35
39
  * | |- index: content, file
@@ -49,12 +53,63 @@ const writeFile = require('../utils/writeFile')
49
53
  * index.http: content, file
50
54
  */
51
55
 
56
+ /*
57
+ * Fastify api:
58
+ * src
59
+ * |- @types:
60
+ * |- |- dto:
61
+ * |- |- |- user: content, file
62
+ * |- |- models:
63
+ * |- |- |- user: content, file
64
+ * | |- index: content, file
65
+ * |- database:
66
+ * | |- mongo:
67
+ * | |- |- models:
68
+ * | |- |- |- index: content, file
69
+ * | |- |- |- user: content, file
70
+ * | |- |- queries:
71
+ * | |- |- |- index: content, file
72
+ * | |- |- |- user: content, file
73
+ * | |- |- index: content, file
74
+ * | |- index: content, file
75
+ * |- network:
76
+ * | |- routes:
77
+ * | | |- schemas:
78
+ * | | | |- user: content, file
79
+ * | | | |- index: content, file
80
+ * | | |- home: content, file
81
+ * | | |- user: content, file
82
+ * | | |- index: content, file
83
+ * | |- response: content, file
84
+ * | |- router: content, file
85
+ * | |- server: content, file
86
+ * | |- index: content, file
87
+ * |- services:
88
+ * | |- utils:
89
+ * | | |- messages:
90
+ * | | | |- user: content, file
91
+ * | | | |- index: content, file
92
+ * | | |- index: content, file
93
+ * | |- user: content, file
94
+ * | |- index: content, file
95
+ * |- .env: content, file
96
+ * |- index: content, file
97
+ * index.http: content, file
98
+ */
99
+
52
100
  /**
53
- * @param {String} projectName
54
- * @param {String} projectVersion
55
- * @param {String} email
101
+ * @param {Object} args
102
+ * @param {String} args.projectName
103
+ * @param {String} args.projectVersion
104
+ * @param {String} args.email
105
+ * @param {Boolean|undefined} args.fastify
56
106
  */
57
- module.exports = async (projectName, projectVersion, email) => {
107
+ module.exports = async ({
108
+ projectName,
109
+ projectVersion,
110
+ email,
111
+ fastify = false
112
+ }) => {
58
113
  const data = {
59
114
  '@types': {
60
115
  index: {
@@ -1245,6 +1300,464 @@ export { userSchema, storeUserSchema }
1245
1300
  }
1246
1301
  }
1247
1302
 
1303
+ const fastifyData = {
1304
+ network: {
1305
+ response: {
1306
+ content: `import { FastifyReply } from 'fastify'
1307
+
1308
+ const response = ({
1309
+ error,
1310
+ message,
1311
+ reply,
1312
+ status
1313
+ }: {
1314
+ error: boolean
1315
+ message: unknown
1316
+ reply: FastifyReply
1317
+ status: number
1318
+ }): void => {
1319
+ reply.code(status).send({ error, message })
1320
+ }
1321
+
1322
+ export { response }
1323
+ `,
1324
+ file: `${projectName}/src/network/response.ts`
1325
+ },
1326
+ router: {
1327
+ content: `import { FastifyInstance } from 'fastify'
1328
+ import { HttpError } from 'http-errors'
1329
+
1330
+ import { response } from './response'
1331
+ import { Home, User, Docs } from './routes'
1332
+
1333
+ const routers = [Docs, User]
1334
+
1335
+ const applyRoutes = (app: FastifyInstance): void => {
1336
+ Home(app)
1337
+ routers.forEach(router => router(app))
1338
+
1339
+ // Handling 404 error
1340
+ app.setNotFoundHandler((request, reply) => {
1341
+ response({
1342
+ error: true,
1343
+ message: 'This route does not exists',
1344
+ reply,
1345
+ status: 404
1346
+ })
1347
+ })
1348
+ app.setErrorHandler<HttpError>((error, request, reply) => {
1349
+ response({
1350
+ error: true,
1351
+ message: error.message,
1352
+ reply,
1353
+ status: error.status ?? 500
1354
+ })
1355
+ })
1356
+ }
1357
+
1358
+ export { applyRoutes }
1359
+ `,
1360
+ file: `${projectName}/src/network/router.ts`
1361
+ },
1362
+ server: {
1363
+ content: `import Fastify, { FastifyInstance } from 'fastify'
1364
+ import mongoose from 'mongoose'
1365
+
1366
+ import { applyRoutes } from './router'
1367
+
1368
+ const PORT = process.env.PORT ?? '1996'
1369
+
1370
+ class Server {
1371
+ private _app: FastifyInstance
1372
+ private _connection: mongoose.Connection | undefined
1373
+
1374
+ constructor() {
1375
+ this._app = Fastify({ logger: true })
1376
+ this._config()
1377
+ }
1378
+
1379
+ private _config() {
1380
+ this._app.addHook('preHandler', (req, reply, done) => {
1381
+ reply.header('Access-Control-Allow-Methods', 'GET, POST, PATCH, DELETE')
1382
+ reply.header('Access-Control-Allow-Origin', '*')
1383
+ reply.header(
1384
+ 'Access-Control-Allow-Headers',
1385
+ 'Authorization, Content-Type'
1386
+ )
1387
+ done()
1388
+ })
1389
+ applyRoutes(this._app)
1390
+ }
1391
+
1392
+ private async _mongo(): Promise<void> {
1393
+ this._connection = mongoose.connection
1394
+ const connection = {
1395
+ keepAlive: true,
1396
+ useNewUrlParser: true,
1397
+ useUnifiedTopology: true
1398
+ }
1399
+ this._connection.on('connected', () => {
1400
+ this._app.log.info('Mongo connection established.')
1401
+ })
1402
+ this._connection.on('reconnected', () => {
1403
+ this._app.log.info('Mongo connection reestablished')
1404
+ })
1405
+ this._connection.on('disconnected', () => {
1406
+ this._app.log.info('Mongo connection disconnected')
1407
+ this._app.log.info('Trying to reconnected to Mongo...')
1408
+ setTimeout(() => {
1409
+ mongoose.connect(process.env.MONGO_URI as string, {
1410
+ ...connection,
1411
+ connectTimeoutMS: 3000,
1412
+ socketTimeoutMS: 3000
1413
+ })
1414
+ }, 3000)
1415
+ })
1416
+ this._connection.on('close', () => {
1417
+ this._app.log.info('Mongo connection closed')
1418
+ })
1419
+ this._connection.on('error', (e: Error) => {
1420
+ this._app.log.info('Mongo connection error:')
1421
+ this._app.log.error(e)
1422
+ })
1423
+ await mongoose.connect(process.env.MONGO_URI as string, connection)
1424
+ }
1425
+
1426
+ public async start(): Promise<void> {
1427
+ try {
1428
+ await this._app.listen(PORT)
1429
+ this._mongo()
1430
+ } catch (e) {
1431
+ console.error(e)
1432
+ }
1433
+ }
1434
+ }
1435
+
1436
+ const server = new Server()
1437
+
1438
+ export { server as Server }
1439
+ `,
1440
+ file: `${projectName}/src/network/server.ts`
1441
+ }
1442
+ },
1443
+ 'network/routes': {
1444
+ docs: {
1445
+ content: `import { FastifyInstance } from 'fastify'
1446
+ import fastifySwagger from 'fastify-swagger'
1447
+
1448
+ const Docs = (app: FastifyInstance, prefix = '/api'): void => {
1449
+ app.register(fastifySwagger, {
1450
+ routePrefix: \`\${prefix}/docs\`,
1451
+ openapi: {
1452
+ info: {
1453
+ title: 'Test swagger',
1454
+ description: 'Testing the Fastify swagger API',
1455
+ version: '0.1.0',
1456
+ contact: {
1457
+ email: 'sluzquinosa@uni.pe'
1458
+ },
1459
+ license: {
1460
+ name: 'MIT',
1461
+ url: 'https://opensource.org/licenses/MIT'
1462
+ }
1463
+ },
1464
+ servers: [
1465
+ {
1466
+ url: 'http://localhost:1996/api',
1467
+ description: 'test-fastify local API'
1468
+ }
1469
+ ],
1470
+ tags: [
1471
+ {
1472
+ name: 'user',
1473
+ description: 'User related endpoints'
1474
+ }
1475
+ ]
1476
+ },
1477
+ exposeRoute: true
1478
+ })
1479
+ }
1480
+
1481
+ export { Docs }
1482
+ `,
1483
+ file: `${projectName}/src/network/routes/docs.ts`
1484
+ },
1485
+ home: {
1486
+ content: `import { FastifyInstance } from 'fastify'
1487
+ import { response } from 'network/response'
1488
+
1489
+ const Home = (app: FastifyInstance, prefix = '/'): void => {
1490
+ app.get(\`\${prefix}\`, (request, reply) => {
1491
+ response({
1492
+ error: false,
1493
+ message: 'Welcome to your Fastify Backend!',
1494
+ reply,
1495
+ status: 200
1496
+ })
1497
+ })
1498
+ }
1499
+
1500
+ export { Home }
1501
+ `,
1502
+ file: `${projectName}/src/network/routes/home.ts`
1503
+ },
1504
+ index: {
1505
+ content: `export * from './home'
1506
+ export * from './user'
1507
+ export * from './docs'
1508
+ `,
1509
+ file: `${projectName}/src/network/routes/index.ts`
1510
+ },
1511
+ user: {
1512
+ content: `import { FastifyInstance } from 'fastify'
1513
+
1514
+ import { response } from 'network/response'
1515
+ import { userSchema, idSchema, storeUserSchema } from './schemas'
1516
+ import { UserService } from 'services'
1517
+
1518
+ const User = (app: FastifyInstance, prefix = '/api'): void => {
1519
+ app
1520
+ .post<{ Body: { args: Omit<DtoUser, 'id'> } }>(
1521
+ \`\${prefix}/users\`,
1522
+ {
1523
+ schema: {
1524
+ body: {
1525
+ args: storeUserSchema
1526
+ },
1527
+ response: {
1528
+ 200: {
1529
+ error: {
1530
+ type: 'boolean'
1531
+ },
1532
+ message: userSchema
1533
+ }
1534
+ },
1535
+ tags: ['user']
1536
+ }
1537
+ },
1538
+ async (request, reply) => {
1539
+ const {
1540
+ body: {
1541
+ args: { lastName, name }
1542
+ }
1543
+ } = request
1544
+ const us = new UserService({ lastName, name })
1545
+ const user = await us.process({ type: 'store' })
1546
+
1547
+ response({
1548
+ error: false,
1549
+ message: user,
1550
+ reply,
1551
+ status: 200
1552
+ })
1553
+ }
1554
+ )
1555
+ .get(
1556
+ \`\${prefix}/users\`,
1557
+ {
1558
+ schema: {
1559
+ response: {
1560
+ 200: {
1561
+ error: {
1562
+ type: 'boolean'
1563
+ },
1564
+ message: {
1565
+ type: 'array',
1566
+ items: userSchema
1567
+ }
1568
+ }
1569
+ },
1570
+ tags: ['user']
1571
+ }
1572
+ },
1573
+ async (request, reply) => {
1574
+ const us = new UserService()
1575
+ const users = await us.process({ type: 'getAll' })
1576
+
1577
+ response({
1578
+ error: false,
1579
+ message: users,
1580
+ reply,
1581
+ status: 200
1582
+ })
1583
+ }
1584
+ )
1585
+ .delete(
1586
+ \`\${prefix}/users\`,
1587
+ {
1588
+ schema: {
1589
+ response: {
1590
+ 200: {
1591
+ error: {
1592
+ type: 'boolean'
1593
+ },
1594
+ message: {
1595
+ type: 'string'
1596
+ }
1597
+ }
1598
+ },
1599
+ tags: ['user']
1600
+ }
1601
+ },
1602
+ async (request, reply) => {
1603
+ const us = new UserService()
1604
+ const result = await us.process({ type: 'deleteAll' })
1605
+
1606
+ response({
1607
+ error: false,
1608
+ message: result,
1609
+ reply,
1610
+ status: 200
1611
+ })
1612
+ }
1613
+ )
1614
+ .get<{ Params: { id: string } }>(
1615
+ \`\${prefix}/user/:id\`,
1616
+ {
1617
+ schema: {
1618
+ params: {
1619
+ id: idSchema
1620
+ },
1621
+ response: {
1622
+ 200: {
1623
+ error: {
1624
+ type: 'boolean'
1625
+ },
1626
+ message: userSchema
1627
+ }
1628
+ },
1629
+ tags: ['user']
1630
+ }
1631
+ },
1632
+ async (request, reply) => {
1633
+ const {
1634
+ params: { id }
1635
+ } = request
1636
+ const us = new UserService({ id })
1637
+ const user = await us.process({ type: 'getOne' })
1638
+
1639
+ response({
1640
+ error: false,
1641
+ message: user,
1642
+ reply,
1643
+ status: 200
1644
+ })
1645
+ }
1646
+ )
1647
+ .patch<{ Body: { args: Omit<DtoUser, 'id'> }; Params: { id: string } }>(
1648
+ \`\${prefix}/user/:id\`,
1649
+ {
1650
+ schema: {
1651
+ body: {
1652
+ args: userSchema
1653
+ },
1654
+ params: {
1655
+ id: idSchema
1656
+ },
1657
+ response: {
1658
+ 200: {
1659
+ error: {
1660
+ type: 'boolean'
1661
+ },
1662
+ message: userSchema
1663
+ }
1664
+ },
1665
+ tags: ['user']
1666
+ }
1667
+ },
1668
+ async (request, reply) => {
1669
+ const {
1670
+ body: {
1671
+ args: { name, lastName }
1672
+ },
1673
+ params: { id }
1674
+ } = request
1675
+ const us = new UserService({ name, lastName, id })
1676
+ const user = await us.process({ type: 'update' })
1677
+
1678
+ response({
1679
+ error: false,
1680
+ message: user,
1681
+ reply,
1682
+ status: 200
1683
+ })
1684
+ }
1685
+ )
1686
+ .delete<{ Params: { id: string } }>(
1687
+ \`\${prefix}/user/:id\`,
1688
+ {
1689
+ schema: {
1690
+ params: {
1691
+ id: idSchema
1692
+ },
1693
+ response: {
1694
+ 200: {
1695
+ error: {
1696
+ type: 'boolean'
1697
+ },
1698
+ message: {
1699
+ type: 'string'
1700
+ }
1701
+ }
1702
+ },
1703
+ tags: ['user']
1704
+ }
1705
+ },
1706
+ async (request, reply) => {
1707
+ const {
1708
+ params: { id }
1709
+ } = request
1710
+ const us = new UserService({ id })
1711
+ const result = await us.process({ type: 'delete' })
1712
+
1713
+ response({
1714
+ error: false,
1715
+ message: result,
1716
+ reply,
1717
+ status: 200
1718
+ })
1719
+ }
1720
+ )
1721
+ }
1722
+
1723
+ export { User }
1724
+ `,
1725
+ file: `${projectName}/src/network/routes/user.ts`
1726
+ }
1727
+ },
1728
+ 'network/routes/schemas': {
1729
+ index: {
1730
+ content: `import { Type } from '@sinclair/typebox'
1731
+
1732
+ const idSchema = Type.String({ minLength: 24, maxLength: 24 })
1733
+
1734
+ export { idSchema }
1735
+ export * from './user'
1736
+ `,
1737
+ file: `${projectName}/src/network/routes/schemas/index.ts`
1738
+ },
1739
+ user: {
1740
+ content: `import { Type } from '@sinclair/typebox'
1741
+
1742
+ const userSchema = Type.Object({
1743
+ id: Type.Optional(Type.String({ minLength: 24, maxLength: 24 })),
1744
+ lastName: Type.Optional(Type.String()),
1745
+ name: Type.Optional(Type.String()),
1746
+ updatedAt: Type.Optional(Type.String())
1747
+ })
1748
+
1749
+ const storeUserSchema = Type.Object({
1750
+ lastName: Type.String(),
1751
+ name: Type.String()
1752
+ })
1753
+
1754
+ export { userSchema, storeUserSchema }
1755
+ `,
1756
+ file: `${projectName}/src/network/routes/schemas/user.ts`
1757
+ }
1758
+ }
1759
+ }
1760
+
1248
1761
  const expressFolders = `${projectName}/src/utils`
1249
1762
 
1250
1763
  const createFoldersCommands = `mkdir ${projectName}/src \
@@ -1262,7 +1775,7 @@ ${projectName}/src/network/routes/schemas \
1262
1775
  ${projectName}/src/services \
1263
1776
  ${projectName}/src/services/utils \
1264
1777
  ${projectName}/src/services/utils/messages \
1265
- ${expressFolders}
1778
+ ${fastify ? '' : `${expressFolders}`}
1266
1779
  `
1267
1780
 
1268
1781
  if (os.platform() === 'win32')
@@ -1272,16 +1785,6 @@ ${expressFolders}
1272
1785
  // /@types
1273
1786
  await writeFile(data['@types'].index.file, data['@types'].index.content)
1274
1787
 
1275
- // /@types/custom
1276
- await writeFile(
1277
- expressData['@types/custom'].request.file,
1278
- expressData['@types/custom'].request.content
1279
- )
1280
- await writeFile(
1281
- expressData['@types/custom'].response.file,
1282
- expressData['@types/custom'].response.content
1283
- )
1284
-
1285
1788
  // /@types/dto
1286
1789
  await writeFile(data['@types/dto'].user.file, data['@types/dto'].user.content)
1287
1790
 
@@ -1336,53 +1839,112 @@ ${expressFolders}
1336
1839
 
1337
1840
  // /network
1338
1841
  await writeFile(data.network.index.file, data.network.index.content)
1339
- await writeFile(
1340
- expressData.network.response.file,
1341
- expressData.network.response.content
1342
- )
1343
- await writeFile(
1344
- expressData.network.router.file,
1345
- expressData.network.router.content
1346
- )
1347
- await writeFile(
1348
- expressData.network.server.file,
1349
- expressData.network.server.content
1350
- )
1351
-
1352
- // /network/routes
1353
- await writeFile(
1354
- expressData['network/routes'].home.file,
1355
- expressData['network/routes'].home.content
1356
- )
1357
- await writeFile(
1358
- expressData['network/routes'].user.file,
1359
- expressData['network/routes'].user.content
1360
- )
1361
- await writeFile(
1362
- expressData['network/routes'].index.file,
1363
- expressData['network/routes'].index.content
1364
- )
1365
-
1366
- // /network/routes/schemas
1367
- await writeFile(
1368
- expressData['network/routes/schemas'].index.file,
1369
- expressData['network/routes/schemas'].index.content
1370
- )
1371
- await writeFile(
1372
- expressData['network/routes/schemas'].user.file,
1373
- expressData['network/routes/schemas'].user.content
1374
- )
1375
1842
 
1376
1843
  // /test
1377
1844
  await writeFile(data.test.index.file, data.test.index.content)
1378
1845
 
1379
- // /utils
1380
- await writeFile(expressData.utils.docs.file, expressData.utils.docs.content)
1381
- await writeFile(expressData.utils.index.file, expressData.utils.index.content)
1382
-
1383
1846
  // .env
1384
1847
  await writeFile(data['.env'].file, data['.env'].content)
1385
1848
 
1386
1849
  // index
1387
1850
  await writeFile(data.index.file, data.index.content)
1851
+
1852
+ if (fastify) {
1853
+ // /network
1854
+ await writeFile(
1855
+ fastifyData.network.response.file,
1856
+ fastifyData.network.response.content
1857
+ )
1858
+ await writeFile(
1859
+ fastifyData.network.router.file,
1860
+ fastifyData.network.router.content
1861
+ )
1862
+ await writeFile(
1863
+ fastifyData.network.server.file,
1864
+ fastifyData.network.server.content
1865
+ )
1866
+
1867
+ // /network/routes
1868
+ await writeFile(
1869
+ fastifyData['network/routes'].docs.file,
1870
+ fastifyData['network/routes'].docs.content
1871
+ )
1872
+ await writeFile(
1873
+ fastifyData['network/routes'].home.file,
1874
+ fastifyData['network/routes'].home.content
1875
+ )
1876
+ await writeFile(
1877
+ fastifyData['network/routes'].user.file,
1878
+ fastifyData['network/routes'].user.content
1879
+ )
1880
+ await writeFile(
1881
+ fastifyData['network/routes'].index.file,
1882
+ fastifyData['network/routes'].index.content
1883
+ )
1884
+
1885
+ // /network/routes/schemas
1886
+ await writeFile(
1887
+ fastifyData['network/routes/schemas'].index.file,
1888
+ fastifyData['network/routes/schemas'].index.content
1889
+ )
1890
+ await writeFile(
1891
+ fastifyData['network/routes/schemas'].user.file,
1892
+ fastifyData['network/routes/schemas'].user.content
1893
+ )
1894
+ } else {
1895
+ // /network
1896
+ await writeFile(
1897
+ expressData.network.response.file,
1898
+ expressData.network.response.content
1899
+ )
1900
+ await writeFile(
1901
+ expressData.network.router.file,
1902
+ expressData.network.router.content
1903
+ )
1904
+ await writeFile(
1905
+ expressData.network.server.file,
1906
+ expressData.network.server.content
1907
+ )
1908
+
1909
+ // /network/routes
1910
+ await writeFile(
1911
+ expressData['network/routes'].home.file,
1912
+ expressData['network/routes'].home.content
1913
+ )
1914
+ await writeFile(
1915
+ expressData['network/routes'].user.file,
1916
+ expressData['network/routes'].user.content
1917
+ )
1918
+ await writeFile(
1919
+ expressData['network/routes'].index.file,
1920
+ expressData['network/routes'].index.content
1921
+ )
1922
+
1923
+ // /network/routes/schemas
1924
+ await writeFile(
1925
+ expressData['network/routes/schemas'].index.file,
1926
+ expressData['network/routes/schemas'].index.content
1927
+ )
1928
+ await writeFile(
1929
+ expressData['network/routes/schemas'].user.file,
1930
+ expressData['network/routes/schemas'].user.content
1931
+ )
1932
+
1933
+ // /utils
1934
+ await writeFile(expressData.utils.docs.file, expressData.utils.docs.content)
1935
+ await writeFile(
1936
+ expressData.utils.index.file,
1937
+ expressData.utils.index.content
1938
+ )
1939
+
1940
+ // /@types/custom
1941
+ await writeFile(
1942
+ expressData['@types/custom'].request.file,
1943
+ expressData['@types/custom'].request.content
1944
+ )
1945
+ await writeFile(
1946
+ expressData['@types/custom'].response.file,
1947
+ expressData['@types/custom'].response.content
1948
+ )
1949
+ }
1388
1950
  }
@@ -18,7 +18,10 @@ module.exports = async ({
18
18
  }
19
19
 
20
20
  data.content = `{
21
- "name": "${projectName.toLowerCase().replace(/ /g, '-')}",
21
+ "name": "${projectName
22
+ .toLowerCase()
23
+ .replaceAll(' ', '-')
24
+ .replaceAll('/', '-')}",
22
25
  "version": "${projectVersion}",
23
26
  "main": "${mainFile}",
24
27
  "description": "${projectDescription}",
package/lib/src/index.js CHANGED
@@ -14,7 +14,7 @@ const eslint = require('./functions/eslint')
14
14
  const webpack = require('./functions/webpack')
15
15
  const docker = require('./functions/docker')
16
16
  const herokuF = require('./functions/heroku')
17
- const express = require('./functions/api')
17
+ const api = require('./functions/api')
18
18
 
19
19
  /**
20
20
  * @param {Number} process number of process
@@ -45,7 +45,8 @@ module.exports = async ({
45
45
  version,
46
46
  licenseYear,
47
47
  manager,
48
- mainFile
48
+ mainFile,
49
+ fastify
49
50
  }) => {
50
51
  const process = 4
51
52
  let i = 0
@@ -57,9 +58,13 @@ module.exports = async ({
57
58
  )
58
59
 
59
60
  const expressProdPackages = 'express joi morgan swagger-ui-express'
60
- const prodPackages = `${manager} http-errors mongoose ${expressProdPackages}`
61
+ const fastifyProdPackages = '@sinclair/typebox fastify fastify-swagger'
62
+ const prodPackages = `${manager} http-errors mongoose ${
63
+ fastify ? fastifyProdPackages : expressProdPackages
64
+ }`
61
65
 
62
66
  const expressDevPackages = `@types/express @types/morgan @types/swagger-ui-express`
67
+ const fastifyDevPackages = ''
63
68
  const devPackages = `${manager} -D \
64
69
  @types/http-errors \
65
70
  @types/node \
@@ -84,7 +89,7 @@ typescript \
84
89
  webpack \
85
90
  webpack-cli \
86
91
  webpack-node-externals \
87
- ${expressDevPackages}`
92
+ ${fastify ? fastifyDevPackages : expressDevPackages}`
88
93
 
89
94
  bar.start(process, i)
90
95
 
@@ -109,7 +114,7 @@ ${expressDevPackages}`
109
114
  eslint(projectName),
110
115
  webpack(projectName),
111
116
  docker(projectName),
112
- express(projectName, version, email),
117
+ api({ projectName, version, email, fastify }),
113
118
  exec('git init', { cwd: `./${projectName}` })
114
119
  ]
115
120
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anthonylzq/simba.js",
3
- "version": "2.1.1",
3
+ "version": "3.0.0",
4
4
  "description": "set up a modern backend app by running one command",
5
5
  "main": "lib/index.js",
6
6
  "directories": {
@@ -10,10 +10,16 @@
10
10
  "scripts": {
11
11
  "service": "node ./bin",
12
12
  "release": "standard-version",
13
- "test": "npm run rm && node -r dotenv/config ./bin -N example -D 'This is a test' -a AnthonyLzq -e sluzquinosa@uni.pe -l mit -H && npm run rm-git-example",
13
+ "test": "npm run rm && npm run test-express && npm run test-fastify",
14
+ "test-express": "npm run rm-express && npm run cd-mv-example && node -r dotenv/config ./bin -N example/express -D 'This is a test using express' -a AnthonyLzq -e sluzquinosa@uni.pe -l mit -H && npm run rm-git-express",
15
+ "test-fastify": "npm run rm-fastify && npm run cd-mv-example && node -r dotenv/config ./bin -N example/fastify -D 'This is a test using fastify' -a AnthonyLzq -e sluzquinosa@uni.pe -l mit -H -F && npm run rm-git-fastify",
14
16
  "lint": "eslint --ext js lib/ --fix",
15
17
  "rm": "if [ -d \"example\" ]; then rm -rf example; fi",
16
- "rm-git-example": "if [ -d \"example/.git\" ]; then rm -rf example/.git; fi"
18
+ "rm-express": "if [ -d \"example/express\" ]; then rm -rf example/express; fi",
19
+ "rm-fastify": "if [ -d \"example/fastify\" ]; then rm -rf example/fastify; fi",
20
+ "rm-git-express": "if [ -d \"example/express/.git\" ]; then rm -rf example/express/.git; fi",
21
+ "rm-git-fastify": "if [ -d \"example/fastify/.git\" ]; then rm -rf example/fastify/.git; fi",
22
+ "cd-mv-example": "if [ ! -d \"example\" ]; then mkdir example && cd example; fi"
17
23
  },
18
24
  "bin": {
19
25
  "simba": "./bin/index.js"