@anthonylzq/simba.js 2.1.0 → 3.1.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
 
@@ -30,12 +15,6 @@ npm i -g @anthonylzq/simba.js
30
15
 
31
16
  ## Usage
32
17
 
33
- <!-- Also, if you don't want to install it globally, you can use npx as follows:
34
-
35
- ```bash
36
- npx simba.js
37
- ``` -->
38
-
39
18
  As developer you have two main options to create your new project, one is by running:
40
19
 
41
20
  ```bash
@@ -44,7 +23,8 @@ simba -q
44
23
 
45
24
  By doing this your prompt will ask you the following questions:
46
25
 
47
- - `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).
48
28
  - `Project name:`, at least one character must be provided.
49
29
  - `Project description:`, at least one character must be provided.
50
30
  - `Author:`, at least one character must be provided.
@@ -63,8 +43,8 @@ simba -h
63
43
  This will generate the following output:
64
44
 
65
45
  ```bash
66
- simba [options] (if you it installed globally) or only simba if you want to be
67
- 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
68
48
 
69
49
  Options:
70
50
  -N, --projectName Project name
@@ -78,13 +58,15 @@ Options:
78
58
  3.0, in lowercase without its version
79
59
  [default: "unlicensed"]
80
60
  -v, --version Project initial version [default: "0.1.0"]
81
- -y, --licenseYear Year when the license starts [default: "2021"]
61
+ -y, --licenseYear Year when the license starts [default: "2022"]
82
62
  -n, --npm Whether or not the project should use npm as package
83
63
  manager [boolean] [default: false]
84
64
  -f, --mainFile Main file of the project [default: "src/index.ts"]
85
65
  -q, --questions Whether or not you want to be asked to answer the
86
66
  questions related to the project one by one
87
67
  [boolean] [default: false]
68
+ -F, --fastify Whether or not you want to use Fastify for your
69
+ project [boolean] [default: false]
88
70
  -h, --help Show help [boolean]
89
71
 
90
72
  Examples:
@@ -94,7 +76,39 @@ Examples:
94
76
  Developed by AnthonyLzq
95
77
  ```
96
78
 
97
- 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
98
112
 
99
113
  ```
100
114
  📂node_modules
@@ -149,6 +163,7 @@ Regardless of the option chosen, a new folder will be generated with the name of
149
163
  📜CHANGELOG.md
150
164
  📜Dockerfile
151
165
  📜heroku.yml
166
+ 📜index.http
152
167
  📜LICENSE
153
168
  📜nodemon.json
154
169
  📜package.json
@@ -160,27 +175,69 @@ Regardless of the option chosen, a new folder will be generated with the name of
160
175
  📜yarn.lock (or package-lock.json)
161
176
  ```
162
177
 
163
- ### Examples
164
-
165
- Let's suppose you want to build a project that will be deployed to Heroku, so should run:
178
+ ### Fastify case
166
179
 
167
- ```bash
168
- simba -N myProject -D 'This is a test' -l mit -a myName -e myEmail@email.com -H
169
180
  ```
170
-
171
- 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.
172
-
173
- 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:
174
-
175
- ```bash
176
- 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)
177
238
  ```
178
239
 
179
- 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:
180
-
181
- ```bash
182
- simba -N myProject -D 'This is a test' -a myName -e myEmail@email.com -H
183
- ```
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.
184
241
 
185
242
  ### Some considerations
186
243
 
@@ -225,17 +282,14 @@ simba -N myProject -D 'This is a test' -a myName -e myEmail@email.com -H
225
282
 
226
283
  ## What is new?
227
284
 
228
- Please check the `changelog.md` file.
285
+ Please check the [`changelog.md`](https://github.com/AnthonyLzq/simba.js/blob/master/CHANGELOG.md) file. Also, if you want to check what is coming, check the [road map](https://simbajs.notion.site/simbajs/783092dc7d444067b4c56a25d671f658?v=31060f3d17524ca58870e86c2960a6df).
229
286
 
230
287
  ## <a name="notes"></a>Notes
231
288
 
232
289
  Here is the list of the packages that are being installed, as `devDependencies`:
233
290
 
234
- - [`@types/express`](https://www.npmjs.com/package/@types/express)
235
291
  - [`@types/http-errors`](https://www.npmjs.com/package/@types/http-errors)
236
- - [`@types/morgan`](https://www.npmjs.com/package/@types/morgan)
237
- - [`@types/node`](https://www.npmjs.com/package/@types/node/v/14.17.5)
238
- - [`@types/swagger-ui-express`](https://www.npmjs.com/package/@types/swagger-ui-express)
292
+ - [`@types/node`](https://www.npmjs.com/package/@types/node)
239
293
  - [`@typescript-eslint/eslint-plugin`](https://www.npmjs.com/package/@typescript-eslint/eslint-plugin)
240
294
  - [`@typescript-eslint/parser`](https://www.npmjs.com/package/@typescript-eslint/parser)
241
295
  - [`dotenv`](https://www.npmjs.com/package/dotenv)
@@ -258,15 +312,38 @@ Here is the list of the packages that are being installed, as `devDependencies`:
258
312
 
259
313
  As `dependencies`:
260
314
 
261
- - [`express`](https://expressjs.com/)
262
315
  - [`http-errors`](https://www.npmjs.com/package/http-errors)
263
- - [`joi`](https://joi.dev/api/?v=17.4.2)
264
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)
265
330
  - [`morgan`](https://www.npmjs.com/package/morgan)
266
331
  - [`swagger-ui-express`](https://www.npmjs.com/package/swagger-ui-express)
267
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
+
268
341
  Feel free to contribute to this project. Every contribution will be appreciated.
269
342
 
270
343
  ## Author
271
344
 
272
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,14 +2,14 @@ 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))
9
9
  .version(false)
10
10
  // Pending to test it using npx
11
11
  .usage(
12
- 'simba [options] (if you it installed globally) or only simba if you want to be asked for the options one by one'
12
+ '"simba [options]" (if you it installed globally) or only "simba -q" if you want to be asked for the options one by one'
13
13
  )
14
14
  .example(
15
15
  "simba -N 'Project Name' -D 'Project description' -a Anthony -e sluzquinosa@uni.pe"
@@ -46,11 +46,12 @@ const argv = yargs(hideBin(process.argv))
46
46
  .nargs('f', 1)
47
47
  .describe('f', 'Main file of the project')
48
48
  .alias('q', 'questions')
49
- .nargs('q', 1)
50
49
  .describe(
51
50
  'q',
52
51
  'Whether or not you want to be asked to answer the questions related to the project one by one'
53
52
  )
53
+ .alias('F', 'fastify')
54
+ .describe('F', 'Whether or not you want to use Fastify for your project')
54
55
  .default({
55
56
  H: false,
56
57
  n: false,
@@ -58,9 +59,10 @@ const argv = yargs(hideBin(process.argv))
58
59
  l: 'unlicensed',
59
60
  v: '0.1.0',
60
61
  f: 'src/index.ts',
61
- q: false
62
+ q: false,
63
+ F: false
62
64
  })
63
- .boolean(['H', 'n', 'q'])
65
+ .boolean(['H', 'n', 'q', 'F'])
64
66
  .help('h')
65
67
  .alias('h', 'help')
66
68
  .epilog('Developed by AnthonyLzq').argv
@@ -77,7 +79,8 @@ const config = {
77
79
  licenseYear: CURRENT_YEAR,
78
80
  npm: false,
79
81
  manager: 'yarn add',
80
- mainFile: 'src/index.ts'
82
+ mainFile: 'src/index.ts',
83
+ fastify: false
81
84
  }
82
85
  const UNLICENSED = 'unlicensed'
83
86
  const LICENSES = [
@@ -114,6 +117,22 @@ const main = async () => {
114
117
 
115
118
  if (config.npm) config.manager = 'npm i'
116
119
 
120
+ readLineSync.promptCLLoop(
121
+ {
122
+ express: () => true,
123
+ fastify: () => {
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
+
117
136
  readLineSync.promptLoop(
118
137
  input => {
119
138
  config.projectName = input.toLowerCase()
@@ -219,6 +238,8 @@ const main = async () => {
219
238
 
220
239
  if (argv.heroku) config.heroku = true
221
240
 
241
+ if (argv.fastify) config.fastify = true
242
+
222
243
  if (!argv.license || argv.license === UNLICENSED)
223
244
  console.log('License was not provided')
224
245
  else {
@@ -266,6 +287,8 @@ const main = async () => {
266
287
  else config.mainFile = argv.mainFile
267
288
  }
268
289
 
290
+ console.log(config)
291
+
269
292
  await installation(config)
270
293
  }
271
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.0",
3
+ "version": "3.1.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"
@@ -31,7 +37,7 @@
31
37
  "author": "AnthonyLzq",
32
38
  "license": "MIT",
33
39
  "dependencies": {
34
- "cli-progress": "^3.9.1",
40
+ "cli-progress": "^3.10.0",
35
41
  "colors": "^1.4.0",
36
42
  "readline-sync": "^1.4.10",
37
43
  "underscore": "^1.13.2",
@@ -39,10 +45,10 @@
39
45
  },
40
46
  "devDependencies": {
41
47
  "dotenv": "^14.3.2",
42
- "eslint": "^8.5.0",
48
+ "eslint": "^8.7.0",
43
49
  "eslint-config-prettier": "^8.3.0",
44
50
  "eslint-config-standard": "^16.0.3",
45
- "eslint-plugin-import": "^2.25.3",
51
+ "eslint-plugin-import": "^2.25.4",
46
52
  "eslint-plugin-node": "^11.1.0",
47
53
  "eslint-plugin-prettier": "^4.0.0",
48
54
  "standard-version": "^9.3.2"