@anthonylzq/simba.js 9.0.1 → 9.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 +59 -30
- package/lib/index.js +42 -5
- package/lib/src/functions/api/database.js +40 -218
- package/lib/src/functions/api/express.js +100 -604
- package/lib/src/functions/api/fastify.js +93 -645
- package/lib/src/functions/api/hono.js +157 -0
- package/lib/src/functions/api/index.js +37 -59
- package/lib/src/functions/api/schemas.js +20 -84
- package/lib/src/functions/api/services.js +28 -210
- package/lib/src/functions/api/utils.js +10 -432
- package/lib/src/functions/biome.js +3 -2
- package/lib/src/functions/changelog.js +5 -5
- package/lib/src/functions/docker.js +7 -39
- package/lib/src/functions/ghat.js +12 -94
- package/lib/src/functions/gitignore.js +3 -134
- package/lib/src/functions/index.js +1 -2
- package/lib/src/functions/license.js +10 -2
- package/lib/src/functions/packageJson.js +13 -37
- package/lib/src/functions/readme.js +6 -5
- package/lib/src/functions/tests.js +17 -320
- package/lib/src/functions/tsconfig.js +13 -114
- package/lib/src/index.js +45 -21
- package/lib/src/utils/entity.js +115 -0
- package/lib/src/utils/index.js +2 -0
- package/lib/src/utils/mkdirs.js +9 -0
- package/lib/src/utils/renderTemplate.js +22 -0
- package/lib/src/utils/titleCase.js +5 -10
- package/lib/src/utils/writeFile.js +3 -10
- package/lib/templates/api/database/connection.ts.ejs +40 -0
- package/lib/templates/api/database/db-index.ts.ejs +2 -0
- package/lib/templates/api/database/index.ts.ejs +1 -0
- package/lib/templates/api/database/queries-entity.ts.ejs +98 -0
- package/lib/templates/api/database/queries-index.ts.ejs +1 -0
- package/lib/templates/api/database/schema.prisma.ejs +25 -0
- package/lib/templates/api/express/network/index.ts.ejs +2 -0
- package/lib/templates/api/express/network/models/entity.ts.ejs +21 -0
- package/lib/templates/api/express/network/models/index.ts.ejs +1 -0
- package/lib/templates/api/express/network/resolvers/entity.ts.ejs +41 -0
- package/lib/templates/api/express/network/resolvers/index.ts.ejs +13 -0
- package/lib/templates/api/express/network/response.ts.ejs +17 -0
- package/lib/templates/api/express/network/router.ts.ejs +39 -0
- package/lib/templates/api/express/network/routes/docs.ts.ejs +43 -0
- package/lib/templates/api/express/network/routes/entity.ts.ejs +165 -0
- package/lib/templates/api/express/network/routes/home.ts.ejs +16 -0
- package/lib/templates/api/express/network/routes/index.ts.ejs +5 -0
- package/lib/templates/api/express/network/server.ts.ejs +139 -0
- package/lib/templates/api/express/network/utils/index.ts.ejs +45 -0
- package/lib/templates/api/express/types/graphQL/context.d.ts.ejs +3 -0
- package/lib/templates/api/express/types/index.d.ts.ejs +4 -0
- package/lib/templates/api/fastify/network/index.ts.ejs +2 -0
- package/lib/templates/api/fastify/network/models/entity.ts.ejs +21 -0
- package/lib/templates/api/fastify/network/models/index.ts.ejs +1 -0
- package/lib/templates/api/fastify/network/resolvers/entity.ts.ejs +41 -0
- package/lib/templates/api/fastify/network/resolvers/index.ts.ejs +13 -0
- package/lib/templates/api/fastify/network/response.ts.ejs +17 -0
- package/lib/templates/api/fastify/network/router.ts.ejs +36 -0
- package/lib/templates/api/fastify/network/routes/docs.ts.ejs +41 -0
- package/lib/templates/api/fastify/network/routes/entity.ts.ejs +116 -0
- package/lib/templates/api/fastify/network/routes/home.ts.ejs +15 -0
- package/lib/templates/api/fastify/network/routes/index.ts.ejs +5 -0
- package/lib/templates/api/fastify/network/server.ts.ejs +129 -0
- package/lib/templates/api/fastify/types/graphQL/context.d.ts.ejs +3 -0
- package/lib/templates/api/fastify/types/index.d.ts.ejs +4 -0
- package/lib/templates/api/hono/network/index.ts.ejs +2 -0
- package/lib/templates/api/hono/network/models/entity.ts.ejs +21 -0
- package/lib/templates/api/hono/network/models/index.ts.ejs +1 -0
- package/lib/templates/api/hono/network/resolvers/entity.ts.ejs +41 -0
- package/lib/templates/api/hono/network/resolvers/index.ts.ejs +13 -0
- package/lib/templates/api/hono/network/response.ts.ejs +18 -0
- package/lib/templates/api/hono/network/router.ts.ejs +45 -0
- package/lib/templates/api/hono/network/routes/docs.ts.ejs +39 -0
- package/lib/templates/api/hono/network/routes/entity.ts.ejs +104 -0
- package/lib/templates/api/hono/network/routes/home.ts.ejs +15 -0
- package/lib/templates/api/hono/network/routes/index.ts.ejs +5 -0
- package/lib/templates/api/hono/network/server.ts.ejs +160 -0
- package/lib/templates/api/hono/network/utils/index.ts.ejs +23 -0
- package/lib/templates/api/hono/types/graphQL/context.d.ts.ejs +3 -0
- package/lib/templates/api/hono/types/index.d.ts.ejs +4 -0
- package/lib/templates/api/schemas/entity.ts.ejs +43 -0
- package/lib/templates/api/schemas/id.ts.ejs +11 -0
- package/lib/templates/api/schemas/index.ts.ejs +2 -0
- package/lib/templates/api/services/BaseHttp.ts.ejs +73 -0
- package/lib/templates/api/services/entity.ts.ejs +75 -0
- package/lib/templates/api/services/index.ts.ejs +1 -0
- package/lib/templates/api/services/utils/index.ts.ejs +1 -0
- package/lib/templates/api/services/utils/messages/entity.ts.ejs +11 -0
- package/lib/templates/api/services/utils/messages/index.ts.ejs +6 -0
- package/lib/templates/api/utils/Logger.ts.ejs +41 -0
- package/lib/templates/api/utils/index.ts.ejs +1 -0
- package/lib/templates/config/.dockerignore.ejs +20 -0
- package/lib/templates/config/.env.ejs +3 -0
- package/lib/templates/config/.gitignore.ejs +129 -0
- package/lib/templates/config/CHANGELOG.md.ejs +1 -0
- package/lib/templates/config/Dockerfile.ejs +13 -0
- package/lib/templates/config/README.md.ejs +3 -0
- package/lib/templates/config/ghat/lint.yml.ejs +46 -0
- package/lib/templates/config/ghat/test.yml.ejs +29 -0
- package/lib/templates/config/index.ts.ejs +3 -0
- package/lib/templates/config/package.json.ejs +30 -0
- package/lib/templates/config/test/index.test.ts.ejs +260 -0
- package/lib/templates/config/tsconfig.base.json.ejs +43 -0
- package/lib/templates/config/tsconfig.json.ejs +16 -0
- package/lib/templates/config/vitest.config.ts.ejs +19 -0
- package/package.json +45 -17
- package/lib/src/functions/api/types.js +0 -108
- package/lib/src/functions/eslint.js +0 -125
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
[](https://reactjs.org/docs/how-to-contribute.html#your-first-pull-request)
|
|
11
11
|
[](https://github.com/AnthonyLzq/TypeScriptProjectGenerator/actions/workflows/publish.yml)
|
|
12
12
|
|
|
13
|
-
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 `
|
|
13
|
+
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`, `Fastify` or `Hono`. 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.
|
|
14
14
|
|
|
15
15
|
## Installation
|
|
16
16
|
|
|
@@ -38,8 +38,9 @@ By doing this your prompt will ask you the following questions:
|
|
|
38
38
|
- `Project version:` the initial version of the project, `0.1.0` as default.
|
|
39
39
|
- `License:`, the license you have chosen for the project.
|
|
40
40
|
- `License year (current year):`, the year where your license starts, current year as default.
|
|
41
|
+
- `Main entity/model name (PascalCase):`, the name of the main entity for the generated project. Default: `User`.
|
|
41
42
|
- `Would you want to have a basic GitHub Action for the suit of tests and linting? [y/n]:`.
|
|
42
|
-
- `Express or
|
|
43
|
+
- `Express, Fastify or Hono?`, only one of them is valid (lowercase).
|
|
43
44
|
- `Will this project use GraphQL? [y/n]:`, yes or no question, only **y** or **n** is accepted. This is not case sensitive.
|
|
44
45
|
- `Which database do you want to use?`, `MongoDB`, `PostgreSQL`, `MySQL`, `MariaDB`, `Sqlite` and `Microsoft SQL Server` are available.
|
|
45
46
|
|
|
@@ -68,7 +69,7 @@ Options:
|
|
|
68
69
|
and AGPL 3.0, in lowercase without its version.
|
|
69
70
|
[default: "unlicensed"]
|
|
70
71
|
-v, --version Project initial version. [default: "0.1.0"]
|
|
71
|
-
-y, --licenseYear Year when the license starts. [default: "
|
|
72
|
+
-y, --licenseYear Year when the license starts. [default: "2026"]
|
|
72
73
|
-m, --manager Which package manager you want to use,
|
|
73
74
|
available package managers are: npm, yarn and
|
|
74
75
|
pnpm. [default: "pnpm"]
|
|
@@ -79,12 +80,16 @@ Options:
|
|
|
79
80
|
one. [boolean] [default: false]
|
|
80
81
|
-F, --fastify Whether or not you want to use Fastify for your
|
|
81
82
|
project. [boolean] [default: false]
|
|
83
|
+
-O, --hono Whether or not you want to use Hono for your
|
|
84
|
+
project. [boolean] [default: false]
|
|
82
85
|
-g, --graphql Whether or not you want to use GraphQL for your
|
|
83
86
|
project. [boolean] [default: false]
|
|
84
87
|
--ghat, --gh-action-tests Whether or not you want to have a GitHub Action
|
|
85
88
|
with a CI for your tests and linting. If this
|
|
86
89
|
option is set to true, the tests flag must be
|
|
87
90
|
set to true. [default: false]
|
|
91
|
+
-E, --entity Name of the main entity/model to generate
|
|
92
|
+
(PascalCase). Default: User. [default: "User"]
|
|
88
93
|
-d, --database Which database you want to use, available
|
|
89
94
|
databases are: MongoDB (mongo), PostgreSQL
|
|
90
95
|
(postgres), MySQL (mysql), MariaDB (mariadb),
|
|
@@ -94,37 +99,43 @@ Options:
|
|
|
94
99
|
|
|
95
100
|
Examples:
|
|
96
101
|
simba -N 'Project Name' -D 'Project description' -a Anthony -e
|
|
97
|
-
sluzquinosa@uni.pe -l mit -F -
|
|
102
|
+
sluzquinosa@uni.pe -l mit -F -d mongo --ghat
|
|
98
103
|
|
|
99
104
|
Developed by AnthonyLzq
|
|
100
105
|
```
|
|
101
106
|
|
|
102
107
|
### Examples
|
|
103
108
|
|
|
104
|
-
Let's suppose you want to build a project
|
|
109
|
+
Let's suppose you want to build a project with Express (the default framework):
|
|
105
110
|
|
|
106
111
|
```bash
|
|
107
|
-
simba -N myProject -D 'This is a test' -l mit -a myName -e myEmail@email.com
|
|
112
|
+
simba -N myProject -D 'This is a test' -l mit -a myName -e myEmail@email.com
|
|
108
113
|
```
|
|
109
114
|
|
|
110
|
-
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
|
|
115
|
+
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`.
|
|
111
116
|
|
|
112
117
|
As default, `pnpm` is selected as package manager, but if you don't want to use it, you can pass the flag `-m` or `--manager` as follows:
|
|
113
118
|
|
|
114
119
|
```bash
|
|
115
|
-
simba -N myProject -D 'This is a test' -l mit -a myName -e myEmail@email.com -
|
|
120
|
+
simba -N myProject -D 'This is a test' -l mit -a myName -e myEmail@email.com -m yarn
|
|
116
121
|
```
|
|
117
122
|
|
|
118
123
|
What if I want to use Fastify instead Express? Well, you only have to pass the `-F` flag:
|
|
119
124
|
|
|
120
125
|
```bash
|
|
121
|
-
simba -N myProject -D 'This is a test' -l mit -a myName -e myEmail@email.com -
|
|
126
|
+
simba -N myProject -D 'This is a test' -l mit -a myName -e myEmail@email.com -F
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
And if I want to use Hono? Pass the `-O` flag:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
simba -N myProject -D 'This is a test' -l mit -a myName -e myEmail@email.com -O
|
|
122
133
|
```
|
|
123
134
|
|
|
124
135
|
If I want to use a relational database instead MongoDB? Well, you only have to pass the `-d` flag:
|
|
125
136
|
|
|
126
137
|
```bash
|
|
127
|
-
simba -N myProject -D 'This is a test' -l mit -a myName -e myEmail@email.com -
|
|
138
|
+
simba -N myProject -D 'This is a test' -l mit -a myName -e myEmail@email.com -d postgres
|
|
128
139
|
```
|
|
129
140
|
|
|
130
141
|
The available databases are:
|
|
@@ -138,18 +149,26 @@ The available databases are:
|
|
|
138
149
|
And how can I use GraphQL? Well, you only have to pass the `-g` flag:
|
|
139
150
|
|
|
140
151
|
```bash
|
|
141
|
-
simba -N myProject -D 'This is a test' -l mit -a myName -e myEmail@email.com -
|
|
152
|
+
simba -N myProject -D 'This is a test' -l mit -a myName -e myEmail@email.com -F -g
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
What if I want my project scaffolded around a different entity instead of `User`? Pass the `-E` flag with a PascalCase name:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
simba -N myProject -D 'This is a test' -l mit -a myName -e myEmail@email.com -E Product
|
|
142
159
|
```
|
|
143
160
|
|
|
161
|
+
The default entity (`User`) generates `lastName` and `name` fields. A custom entity generates `name` and `description` fields. Routes, services, schemas, Prisma models, and tests are all scaffolded around the provided entity name.
|
|
162
|
+
|
|
144
163
|
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:
|
|
145
164
|
|
|
146
165
|
```bash
|
|
147
|
-
simba -N myProject -D 'This is a test' -a myName -e myEmail@email.com
|
|
166
|
+
simba -N myProject -D 'This is a test' -a myName -e myEmail@email.com
|
|
148
167
|
```
|
|
149
168
|
|
|
150
169
|
## <a name="project-structure"></a>Project structure
|
|
151
170
|
|
|
152
|
-
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
|
|
171
|
+
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 find an example for Express, Fastify and Hono (REST and GraphQL versions). Regardless of the option chosen, a new folder will be generated with the name of the project.
|
|
153
172
|
|
|
154
173
|
Also, if you are interested in the folder structure of each case, please take a look at:
|
|
155
174
|
|
|
@@ -161,11 +180,15 @@ Also, if you are interested in the folder structure of each case, please take a
|
|
|
161
180
|
- [Fastify-GraphQL](./projectStructureExamples/fastify-graphql.txt)
|
|
162
181
|
- [Fastify-Mongo](./projectStructureExamples/fastify-mongo.txt)
|
|
163
182
|
- [Fastify-Mongo-GraphQL](./projectStructureExamples/fastify-mongo-graphql.txt)
|
|
183
|
+
- [Hono](./projectStructureExamples/hono.txt)
|
|
184
|
+
- [Hono-GraphQL](./projectStructureExamples/hono-graphql.txt)
|
|
185
|
+
- [Hono-Mongo](./projectStructureExamples/hono-mongo.txt)
|
|
186
|
+
- [Hono-Mongo-GraphQL](./projectStructureExamples/hono-mongo-graphql.txt)
|
|
164
187
|
|
|
165
188
|
### Some considerations
|
|
166
189
|
|
|
167
190
|
- **Prisma v6**: Generated projects use Prisma v6 (pinned). Prisma v7 is **not** used because it does not support MongoDB. When Prisma v7 adds MongoDB support, Simba.js will be updated accordingly.
|
|
168
|
-
- You are able to run a server that has one main route, `home` (`/`),
|
|
191
|
+
- You are able to run a server that has one main route, `home` (`/`), your entity route (e.g. `api/user` or `api/user/:id` for the default `User` entity) and `docs` (`api/docs`), in case you are not using GraphQL. The route name is derived from the entity name you provide.
|
|
169
192
|
- In case you are using GraphQL, there are 3 mutations (`store`, `update`, and `deleteById`) and 1 query available (`getById`), you can find them in the playground under the route `/api`.
|
|
170
193
|
- To connect your server with your database, you need to provide your database url in the `.env`, except if you choose `sqlite`. By default, Simba will try to connect to a local database. The content of the `.env` file is:
|
|
171
194
|
|
|
@@ -242,31 +265,26 @@ Please check the [`changelog.md`](https://github.com/AnthonyLzq/simba.js/blob/ma
|
|
|
242
265
|
|
|
243
266
|
Here is the list of the packages that are being installed, as `dependencies`:
|
|
244
267
|
|
|
268
|
+
- [`@prisma/client`](https://www.npmjs.com/package/@prisma/client)
|
|
245
269
|
- [`debug`](https://www.npmjs.com/package/debug)
|
|
246
|
-
- [`zod`](https://www.npmjs.com/package/zod)
|
|
247
270
|
- [`http-errors`](https://www.npmjs.com/package/http-errors)
|
|
248
|
-
- [
|
|
271
|
+
- [`zod`](https://www.npmjs.com/package/zod)
|
|
249
272
|
|
|
250
273
|
As `devDependencies`:
|
|
251
274
|
|
|
252
275
|
- [`@biomejs/biome`](https://www.npmjs.com/package/@biomejs/biome)
|
|
253
|
-
- [`@jest/types`](https://www.npmjs.com/package/@jest/types)
|
|
254
276
|
- [`@types/debug`](https://www.npmjs.com/package/@types/debug)
|
|
255
277
|
- [`@types/http-errors`](https://www.npmjs.com/package/@types/http-errors)
|
|
256
|
-
- [`@types/jest`](https://www.npmjs.com/package/@types/jest)
|
|
257
278
|
- [`@types/node`](https://www.npmjs.com/package/@types/node)
|
|
258
279
|
- [`axios`](https://www.npmjs.com/package/axios)
|
|
259
280
|
- [`dotenv`](https://www.npmjs.com/package/dotenv)
|
|
260
|
-
- [`jest`](https://www.npmjs.com/package/jest)
|
|
261
|
-
- [`jest-unit`](https://www.npmjs.com/package/jest-unit)
|
|
262
281
|
- [`nodemon`](https://www.npmjs.com/package/nodemon)
|
|
263
282
|
- [`prisma`](https://www.npmjs.com/package/prisma)
|
|
264
|
-
- [`
|
|
265
|
-
- [`
|
|
266
|
-
- [`ts-node`](https://www.npmjs.com/package/ts-node)
|
|
267
|
-
- [`tsconfig-paths`](https://www.npmjs.com/package/tsconfig-paths)
|
|
268
|
-
- [`ts-jest`](https://www.npmjs.com/package/ts-jest)
|
|
283
|
+
- [`commit-and-tag-version`](https://www.npmjs.com/package/commit-and-tag-version)
|
|
284
|
+
- [`tsx`](https://www.npmjs.com/package/tsx)
|
|
269
285
|
- [`typescript`](https://www.npmjs.com/package/typescript)
|
|
286
|
+
- [`vite-tsconfig-paths`](https://www.npmjs.com/package/vite-tsconfig-paths)
|
|
287
|
+
- [`vitest`](https://www.npmjs.com/package/vitest)
|
|
270
288
|
|
|
271
289
|
### In case you are using GraphQL
|
|
272
290
|
|
|
@@ -278,36 +296,47 @@ As `dependencies`:
|
|
|
278
296
|
- [`reflect-metadata`](https://www.npmjs.com/package/reflect-metadata)
|
|
279
297
|
- [`type-graphql`](https://www.npmjs.com/package/type-graphql/v/2.0.0-rc.3)
|
|
280
298
|
|
|
299
|
+
As `devDependencies`:
|
|
300
|
+
- [`@swc/core`](https://www.npmjs.com/package/@swc/core)
|
|
301
|
+
- [`unplugin-swc`](https://www.npmjs.com/package/unplugin-swc)
|
|
302
|
+
|
|
281
303
|
### Express case
|
|
282
304
|
|
|
283
305
|
As `dependencies`:
|
|
284
306
|
|
|
285
307
|
- [`@as-integrations/express5`](https://www.npmjs.com/package/@as-integrations/express5) (only when using GraphQL)
|
|
308
|
+
- [`@asteasolutions/zod-to-openapi`](https://www.npmjs.com/package/@asteasolutions/zod-to-openapi)
|
|
286
309
|
- [`cors`](https://www.npmjs.com/package/cors)
|
|
287
310
|
- [`express`](https://www.npmjs.com/package/express)
|
|
288
311
|
- [`swagger-ui-express`](https://www.npmjs.com/package/swagger-ui-express)
|
|
289
312
|
|
|
290
313
|
As `devDependencies`:
|
|
291
314
|
|
|
292
|
-
- [`@types/express`](https://www.npmjs.com/package/@types/express)
|
|
293
315
|
- [`@types/cors`](https://www.npmjs.com/package/@types/cors)
|
|
316
|
+
- [`@types/express`](https://www.npmjs.com/package/@types/express)
|
|
294
317
|
- [`@types/swagger-ui-express`](https://www.npmjs.com/package/@types/swagger-ui-express)
|
|
295
318
|
|
|
296
319
|
### Fastify case
|
|
297
320
|
|
|
298
321
|
As `dependencies`:
|
|
299
322
|
|
|
300
|
-
- [
|
|
323
|
+
- [`@as-integrations/fastify`](https://www.npmjs.com/package/@as-integrations/fastify) (only when using GraphQL)
|
|
324
|
+
- [`@fastify/cors`](https://www.npmjs.com/package/@fastify/cors)
|
|
301
325
|
- [`@fastify/swagger`](https://www.npmjs.com/package/@fastify/swagger)
|
|
302
326
|
- [`@fastify/swagger-ui`](https://www.npmjs.com/package/@fastify/swagger-ui)
|
|
303
|
-
- [
|
|
327
|
+
- [`fastify`](https://www.npmjs.com/package/fastify)
|
|
304
328
|
- [`fastify-type-provider-zod`](https://www.npmjs.com/package/fastify-type-provider-zod)
|
|
305
329
|
|
|
306
|
-
|
|
330
|
+
### Hono case
|
|
307
331
|
|
|
308
332
|
As `dependencies`:
|
|
309
|
-
- [`@as-integrations/fastify`](https://www.npmjs.com/package/@as-integrations/fastify)
|
|
310
333
|
|
|
334
|
+
- [`@hono/node-server`](https://www.npmjs.com/package/@hono/node-server)
|
|
335
|
+
- [`@hono/swagger-ui`](https://www.npmjs.com/package/@hono/swagger-ui)
|
|
336
|
+
- [`@hono/zod-openapi`](https://www.npmjs.com/package/@hono/zod-openapi)
|
|
337
|
+
- [`hono`](https://www.npmjs.com/package/hono)
|
|
338
|
+
|
|
339
|
+
### Database drivers
|
|
311
340
|
|
|
312
341
|
#### PostgreSQL case
|
|
313
342
|
|
package/lib/index.js
CHANGED
|
@@ -12,7 +12,8 @@ const {
|
|
|
12
12
|
EMAIL_REGEX,
|
|
13
13
|
PROJECT_VERSION,
|
|
14
14
|
MAIN_FILE
|
|
15
|
-
}
|
|
15
|
+
},
|
|
16
|
+
entity: { buildEntityContext }
|
|
16
17
|
} = require('./src/utils')
|
|
17
18
|
const POSSIBLE_LICENSES = Object.keys(LICENSES)
|
|
18
19
|
|
|
@@ -67,6 +68,8 @@ const argv = yargs(hideBin(process.argv))
|
|
|
67
68
|
)
|
|
68
69
|
.alias('F', 'fastify')
|
|
69
70
|
.describe('F', 'Whether or not you want to use Fastify for your project.')
|
|
71
|
+
.alias('O', 'hono')
|
|
72
|
+
.describe('O', 'Whether or not you want to use Hono for your project.')
|
|
70
73
|
.alias('g', 'graphql')
|
|
71
74
|
.describe('g', 'Whether or not you want to use GraphQL for your project.')
|
|
72
75
|
.alias('ghat', 'gh-action-tests')
|
|
@@ -74,6 +77,12 @@ const argv = yargs(hideBin(process.argv))
|
|
|
74
77
|
'ghat',
|
|
75
78
|
'Whether or not you want to have a GitHub Action with a CI for your tests and linting. If this option is set to true, the tests flag must be set to true.'
|
|
76
79
|
)
|
|
80
|
+
.alias('E', 'entity')
|
|
81
|
+
.nargs('E', 1)
|
|
82
|
+
.describe(
|
|
83
|
+
'E',
|
|
84
|
+
'Name of the main entity/model to generate (PascalCase). Default: User.'
|
|
85
|
+
)
|
|
77
86
|
.describe(
|
|
78
87
|
'd',
|
|
79
88
|
'Which database you want to use, available databases are: MongoDB (mongo), PostgreSQL (postgres), MySQL (mysql), MariaDB (mariadb), Sqlite (sqlite) and Microsoft SQL Server (sqlServer).'
|
|
@@ -87,12 +96,14 @@ const argv = yargs(hideBin(process.argv))
|
|
|
87
96
|
f: 'src/index.ts',
|
|
88
97
|
q: false,
|
|
89
98
|
F: false,
|
|
99
|
+
O: false,
|
|
90
100
|
g: false,
|
|
91
101
|
ghat: false,
|
|
102
|
+
E: 'User',
|
|
92
103
|
d: 'mongo',
|
|
93
104
|
m: 'pnpm'
|
|
94
105
|
})
|
|
95
|
-
.boolean(['q', 'F', 'g'])
|
|
106
|
+
.boolean(['q', 'F', 'O', 'g'])
|
|
96
107
|
.help('h')
|
|
97
108
|
.alias('h', 'help')
|
|
98
109
|
.epilog('Developed by AnthonyLzq').argv
|
|
@@ -109,10 +120,12 @@ const config = {
|
|
|
109
120
|
manager: 'pnpm i',
|
|
110
121
|
mainFile: MAIN_FILE,
|
|
111
122
|
fastify: false,
|
|
123
|
+
hono: false,
|
|
112
124
|
graphql: false,
|
|
113
125
|
tests: true,
|
|
114
126
|
ghat: true,
|
|
115
|
-
database: 'mongo'
|
|
127
|
+
database: 'mongo',
|
|
128
|
+
entity: 'User'
|
|
116
129
|
}
|
|
117
130
|
|
|
118
131
|
const main = async () => {
|
|
@@ -203,10 +216,11 @@ const main = async () => {
|
|
|
203
216
|
{
|
|
204
217
|
type: 'select',
|
|
205
218
|
name: 'framework',
|
|
206
|
-
message: '
|
|
219
|
+
message: 'Which framework do you want to use?',
|
|
207
220
|
choices: [
|
|
208
221
|
{ title: 'Express', value: 'express' },
|
|
209
|
-
{ title: 'Fastify', value: 'fastify' }
|
|
222
|
+
{ title: 'Fastify', value: 'fastify' },
|
|
223
|
+
{ title: 'Hono', value: 'hono' }
|
|
210
224
|
]
|
|
211
225
|
},
|
|
212
226
|
{
|
|
@@ -224,6 +238,13 @@ const main = async () => {
|
|
|
224
238
|
title: value,
|
|
225
239
|
value: key
|
|
226
240
|
}))
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
type: 'text',
|
|
244
|
+
name: 'entity',
|
|
245
|
+
message: 'Main entity/model name (PascalCase):',
|
|
246
|
+
initial: 'User',
|
|
247
|
+
format: value => value.charAt(0).toUpperCase() + value.slice(1)
|
|
227
248
|
}
|
|
228
249
|
],
|
|
229
250
|
{
|
|
@@ -244,8 +265,10 @@ const main = async () => {
|
|
|
244
265
|
config.manager = responses.manager
|
|
245
266
|
config.mainFile = responses.mainFile
|
|
246
267
|
config.fastify = responses.framework === 'fastify'
|
|
268
|
+
config.hono = responses.framework === 'hono'
|
|
247
269
|
config.graphql = responses.graphql
|
|
248
270
|
config.database = responses.database
|
|
271
|
+
config.entity = responses.entity
|
|
249
272
|
config.ghat = responses.ghat
|
|
250
273
|
} else {
|
|
251
274
|
if (!argv.author) return console.log('Error! An author is required!')
|
|
@@ -271,6 +294,13 @@ const main = async () => {
|
|
|
271
294
|
|
|
272
295
|
if (argv.fastify) config.fastify = true
|
|
273
296
|
|
|
297
|
+
if (argv.hono) config.hono = true
|
|
298
|
+
|
|
299
|
+
if (config.fastify && config.hono)
|
|
300
|
+
return console.log(
|
|
301
|
+
'Error! You cannot use both Fastify and Hono at the same time.'
|
|
302
|
+
)
|
|
303
|
+
|
|
274
304
|
if (!argv.license || argv.license === UNLICENSED)
|
|
275
305
|
console.log('License was not provided')
|
|
276
306
|
else {
|
|
@@ -323,8 +353,12 @@ const main = async () => {
|
|
|
323
353
|
if (argv.ghat) config.ghat = true
|
|
324
354
|
|
|
325
355
|
if (argv.database) config.database = argv.database
|
|
356
|
+
|
|
357
|
+
if (argv.entity) config.entity = argv.entity
|
|
326
358
|
}
|
|
327
359
|
|
|
360
|
+
config.entityContext = buildEntityContext(config.entity)
|
|
361
|
+
|
|
328
362
|
await installation(config)
|
|
329
363
|
}
|
|
330
364
|
|
|
@@ -342,6 +376,9 @@ module.exports = main
|
|
|
342
376
|
* @property {'yarn add'|'npm i'|'pnpm i'} manager command that will be used to install packages
|
|
343
377
|
* @property {String} mainFile main file of the project
|
|
344
378
|
* @property {Boolean} fastify true means that the project will be using Fastify
|
|
379
|
+
* @property {Boolean} hono true means that the project will be using Hono
|
|
345
380
|
* @property {Boolean} graphql true means that the project will be using GraphQL
|
|
346
381
|
* @property {'mongo'|'postgres'|'mysql'|'mariadb'|'sqlite'|'sqlServer'} database project database
|
|
382
|
+
* @property {String} entity PascalCase name of the main entity/model (default: 'User')
|
|
383
|
+
* @property {import('./src/utils/entity').EntityContext} entityContext computed entity naming context
|
|
347
384
|
*/
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
const
|
|
2
|
-
const { promisify } = require('node:util')
|
|
3
|
-
const exec = promisify(require('node:child_process').exec)
|
|
1
|
+
const mkdirs = require('../../utils/mkdirs')
|
|
4
2
|
const writeFile = require('../../utils/writeFile')
|
|
3
|
+
const { renderTemplate } = require('../../utils/renderTemplate')
|
|
5
4
|
|
|
6
5
|
const dbPrismaName = {
|
|
7
6
|
postgres: 'postgresql',
|
|
@@ -25,222 +24,49 @@ const dbPrettyName = {
|
|
|
25
24
|
* @param {Object} args
|
|
26
25
|
* @param {String} args.projectName
|
|
27
26
|
* @param {import('../../../../').Config['database']} args.db
|
|
27
|
+
* @param {import('../../utils/entity').EntityContext} args.entityContext
|
|
28
28
|
*/
|
|
29
|
-
const db = async ({ projectName, db }) => {
|
|
29
|
+
const db = async ({ projectName, db, entityContext }) => {
|
|
30
30
|
const isMongo = db === 'mongo'
|
|
31
|
-
const createFoldersCommands = `mkdir ${projectName}/prisma \
|
|
32
|
-
${projectName}/src/database/${db} \
|
|
33
|
-
${projectName}/src/database/${db}/queries`
|
|
34
31
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
await mkdirs(
|
|
33
|
+
`${projectName}/prisma`,
|
|
34
|
+
`${projectName}/src/database/${db}/queries`
|
|
35
|
+
)
|
|
38
36
|
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
content: `generator client {
|
|
42
|
-
provider = "prisma-client-js"
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
datasource db {
|
|
46
|
-
provider = "${dbPrismaName[db]}"
|
|
47
|
-
url = ${db !== 'sqlite' ? 'env("DATABASE_URL")' : '"file:./dev.db"'}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
model User {
|
|
51
|
-
${
|
|
52
|
-
isMongo
|
|
53
|
-
? 'id String @id @default(auto()) @map("_id") @db.ObjectId'
|
|
54
|
-
: 'id Int @id @default(autoincrement())'
|
|
55
|
-
}
|
|
56
|
-
lastName String
|
|
57
|
-
name String
|
|
58
|
-
|
|
59
|
-
createdAt DateTime @default(now())
|
|
60
|
-
updatedAt DateTime @updatedAt
|
|
61
|
-
|
|
62
|
-
@@map("users")
|
|
63
|
-
}
|
|
64
|
-
`,
|
|
65
|
-
file: `${projectName}/prisma/schema.prisma`
|
|
66
|
-
},
|
|
67
|
-
index: {
|
|
68
|
-
content: `export * from './${db}'\n`,
|
|
69
|
-
file: `${projectName}/src/database/index.ts`
|
|
70
|
-
},
|
|
71
|
-
[db]: {
|
|
72
|
-
index: {
|
|
73
|
-
content: `export * from './connection'
|
|
74
|
-
export * from './queries'\n`,
|
|
75
|
-
file: `${projectName}/src/database/${db}/index.ts`
|
|
76
|
-
},
|
|
77
|
-
connection: {
|
|
78
|
-
content: `import { PrismaClient } from '@prisma/client'
|
|
79
|
-
import { type Debugger } from 'debug'
|
|
80
|
-
|
|
81
|
-
let dbConnected = false
|
|
82
|
-
|
|
83
|
-
declare global {
|
|
84
|
-
// eslint-disable-next-line no-var
|
|
85
|
-
var __client__: PrismaClient
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const dbConnection = (
|
|
89
|
-
d?: Debugger
|
|
90
|
-
): {
|
|
91
|
-
connect: () => Promise<PrismaClient>
|
|
92
|
-
disconnect: () => Promise<boolean>
|
|
93
|
-
} => {
|
|
94
|
-
return {
|
|
95
|
-
connect: async () => {
|
|
96
|
-
if (!global.__client__) {
|
|
97
|
-
global.__client__ = new PrismaClient()
|
|
98
|
-
await global.__client__.$connect()
|
|
99
|
-
dbConnected = true
|
|
100
|
-
d?.('${dbPrettyName[db]} connection established.')
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return global.__client__
|
|
104
|
-
},
|
|
105
|
-
disconnect: async () => {
|
|
106
|
-
if (global.__client__) {
|
|
107
|
-
dbConnected = false
|
|
108
|
-
await global.__client__.$disconnect()
|
|
109
|
-
d?.('${dbPrettyName[db]} connection closed.')
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return dbConnected
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export { dbConnection }\n`,
|
|
118
|
-
file: `${projectName}/src/database/${db}/connection.ts`
|
|
119
|
-
},
|
|
120
|
-
queries: {
|
|
121
|
-
index: {
|
|
122
|
-
content: "export * from './user'\n",
|
|
123
|
-
file: `${projectName}/src/database/${db}/queries/index.ts`
|
|
124
|
-
},
|
|
125
|
-
user: {
|
|
126
|
-
content: `import { User } from '@prisma/client'
|
|
127
|
-
import debug from 'debug'
|
|
128
|
-
|
|
129
|
-
import { dbConnection } from '../connection'
|
|
130
|
-
import { Id, User as UserSchema, UserDTO } from 'schemas'
|
|
131
|
-
import { Logger } from 'utils'
|
|
132
|
-
|
|
133
|
-
const logger = new Logger(debug('App:Database:Queries:User'))
|
|
134
|
-
|
|
135
|
-
const userDBOtoDTO = (userDBO: User) =>
|
|
136
|
-
({
|
|
137
|
-
...userDBO,
|
|
138
|
-
createdAt: userDBO.createdAt.toISOString(),
|
|
139
|
-
updatedAt: userDBO.updatedAt.toISOString()
|
|
140
|
-
}) satisfies UserDTO
|
|
141
|
-
|
|
142
|
-
const store = async (userData: UserSchema) => {
|
|
143
|
-
try {
|
|
144
|
-
const client = await dbConnection().connect()
|
|
145
|
-
const user = await client.user.create({
|
|
146
|
-
data: userData
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
return userDBOtoDTO(user)
|
|
150
|
-
} catch (error) {
|
|
151
|
-
logger.log({
|
|
152
|
-
origin: 'queries/user.ts',
|
|
153
|
-
method: store.name,
|
|
154
|
-
value: 'error',
|
|
155
|
-
content: error
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
return null
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const removeById = async (id: Id) => {
|
|
163
|
-
try {
|
|
164
|
-
const client = await dbConnection().connect()
|
|
165
|
-
await client.user.delete({
|
|
166
|
-
where: { id }
|
|
167
|
-
})
|
|
168
|
-
|
|
169
|
-
return true
|
|
170
|
-
} catch (error) {
|
|
171
|
-
logger.log({
|
|
172
|
-
origin: 'queries/user.ts',
|
|
173
|
-
method: removeById.name,
|
|
174
|
-
value: 'error',
|
|
175
|
-
content: error
|
|
176
|
-
})
|
|
177
|
-
|
|
178
|
-
return false
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const getById = async (id: Id) => {
|
|
183
|
-
try {
|
|
184
|
-
const client = await dbConnection().connect()
|
|
185
|
-
const user = await client.user.findUnique({
|
|
186
|
-
where: { id }
|
|
187
|
-
})
|
|
188
|
-
|
|
189
|
-
if (!user) return null
|
|
190
|
-
|
|
191
|
-
return userDBOtoDTO(user)
|
|
192
|
-
} catch (error) {
|
|
193
|
-
logger.log({
|
|
194
|
-
origin: 'queries/user.ts',
|
|
195
|
-
method: getById.name,
|
|
196
|
-
value: 'error',
|
|
197
|
-
content: error
|
|
198
|
-
})
|
|
199
|
-
|
|
200
|
-
return null
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
const update = async (id: Id, user: UserSchema) => {
|
|
205
|
-
try {
|
|
206
|
-
const client = await dbConnection().connect()
|
|
207
|
-
const userUpdated = await client.user.update({
|
|
208
|
-
where: { id },
|
|
209
|
-
data: user
|
|
210
|
-
})
|
|
211
|
-
|
|
212
|
-
if (!userUpdated) return null
|
|
213
|
-
|
|
214
|
-
return userDBOtoDTO(userUpdated)
|
|
215
|
-
} catch (error) {
|
|
216
|
-
logger.log({
|
|
217
|
-
origin: 'queries/user.ts',
|
|
218
|
-
method: update.name,
|
|
219
|
-
value: 'error',
|
|
220
|
-
content: error
|
|
221
|
-
})
|
|
222
|
-
|
|
223
|
-
return null
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
export { store, removeById, getById, update }\n`,
|
|
228
|
-
file: `${projectName}/src/database/${db}/queries/user.ts`
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
37
|
+
const t = (templatePath, data = {}) =>
|
|
38
|
+
renderTemplate(`api/database/${templatePath}`, data)
|
|
233
39
|
|
|
234
40
|
await Promise.all([
|
|
235
|
-
writeFile(database.schema.file, database.schema.content),
|
|
236
|
-
writeFile(database.index.file, database.index.content),
|
|
237
|
-
writeFile(database[db].connection.file, database[db].connection.content),
|
|
238
|
-
writeFile(database[db].index.file, database[db].index.content),
|
|
239
41
|
writeFile(
|
|
240
|
-
|
|
241
|
-
|
|
42
|
+
`${projectName}/prisma/schema.prisma`,
|
|
43
|
+
t('schema.prisma.ejs', {
|
|
44
|
+
dbPrismaName: dbPrismaName[db],
|
|
45
|
+
db,
|
|
46
|
+
isMongo,
|
|
47
|
+
...entityContext
|
|
48
|
+
})
|
|
49
|
+
),
|
|
50
|
+
writeFile(
|
|
51
|
+
`${projectName}/src/database/index.ts`,
|
|
52
|
+
t('index.ts.ejs', { db })
|
|
242
53
|
),
|
|
243
|
-
writeFile(
|
|
54
|
+
writeFile(
|
|
55
|
+
`${projectName}/src/database/${db}/index.ts`,
|
|
56
|
+
t('db-index.ts.ejs')
|
|
57
|
+
),
|
|
58
|
+
writeFile(
|
|
59
|
+
`${projectName}/src/database/${db}/connection.ts`,
|
|
60
|
+
t('connection.ts.ejs', { dbPrettyName: dbPrettyName[db] })
|
|
61
|
+
),
|
|
62
|
+
writeFile(
|
|
63
|
+
`${projectName}/src/database/${db}/queries/index.ts`,
|
|
64
|
+
t('queries-index.ts.ejs', entityContext)
|
|
65
|
+
),
|
|
66
|
+
writeFile(
|
|
67
|
+
`${projectName}/src/database/${db}/queries/${entityContext.entity}.ts`,
|
|
68
|
+
t('queries-entity.ts.ejs', entityContext)
|
|
69
|
+
)
|
|
244
70
|
])
|
|
245
71
|
}
|
|
246
72
|
|
|
@@ -249,12 +75,8 @@ export { store, removeById, getById, update }\n`,
|
|
|
249
75
|
* @param {import('../../../../').Config['database']} args.database
|
|
250
76
|
* @param {String} args.projectName
|
|
251
77
|
*/
|
|
252
|
-
module.exports = async ({ database, projectName }) => {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
if (platform() === 'win32')
|
|
256
|
-
await exec(createFoldersCommand.replaceAll('/', '\\'))
|
|
257
|
-
else await exec(createFoldersCommand)
|
|
78
|
+
module.exports = async ({ database, projectName, entityContext }) => {
|
|
79
|
+
await mkdirs(`${projectName}/src/database`)
|
|
258
80
|
|
|
259
|
-
await db({ db: database, projectName })
|
|
81
|
+
await db({ db: database, projectName, entityContext })
|
|
260
82
|
}
|