tspace-spear 1.2.7 → 1.2.9

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.
Files changed (80) hide show
  1. package/README.md +299 -146
  2. package/dist/cli/generators/app/index.d.ts +1 -0
  3. package/dist/cli/generators/app/index.js +124 -0
  4. package/dist/cli/generators/app/index.js.map +1 -0
  5. package/dist/cli/generators/app/template.d.ts +1 -0
  6. package/dist/cli/{app.js → generators/app/template.js} +22 -8
  7. package/dist/cli/generators/app/template.js.map +1 -0
  8. package/dist/cli/generators/client/template.d.ts +1 -0
  9. package/dist/cli/generators/client/template.js +30 -0
  10. package/dist/cli/generators/client/template.js.map +1 -0
  11. package/dist/cli/generators/controller/index.d.ts +1 -0
  12. package/dist/cli/generators/controller/index.js +78 -0
  13. package/dist/cli/generators/controller/index.js.map +1 -0
  14. package/dist/cli/generators/controller/template.d.ts +1 -0
  15. package/dist/cli/generators/controller/template.js +106 -0
  16. package/dist/cli/generators/controller/template.js.map +1 -0
  17. package/dist/cli/generators/dto/index.d.ts +1 -0
  18. package/dist/cli/generators/dto/index.js +57 -0
  19. package/dist/cli/generators/dto/index.js.map +1 -0
  20. package/dist/cli/generators/dto/template.d.ts +1 -0
  21. package/dist/cli/generators/dto/template.js +32 -0
  22. package/dist/cli/generators/dto/template.js.map +1 -0
  23. package/dist/cli/generators/middleware/index.d.ts +1 -0
  24. package/dist/cli/generators/middleware/index.js +38 -0
  25. package/dist/cli/generators/middleware/index.js.map +1 -0
  26. package/dist/cli/generators/middleware/template.d.ts +1 -0
  27. package/dist/cli/generators/middleware/template.js +16 -0
  28. package/dist/cli/generators/middleware/template.js.map +1 -0
  29. package/dist/cli/generators/module/index.d.ts +1 -0
  30. package/dist/cli/generators/module/index.js +173 -0
  31. package/dist/cli/generators/module/index.js.map +1 -0
  32. package/dist/cli/generators/service/index.d.ts +1 -0
  33. package/dist/cli/generators/service/index.js +53 -0
  34. package/dist/cli/generators/service/index.js.map +1 -0
  35. package/dist/cli/generators/service/template.d.ts +1 -0
  36. package/dist/cli/generators/service/template.js +74 -0
  37. package/dist/cli/generators/service/template.js.map +1 -0
  38. package/dist/cli/generators/shared/index.d.ts +3 -0
  39. package/dist/cli/generators/shared/index.js +22 -0
  40. package/dist/cli/generators/shared/index.js.map +1 -0
  41. package/dist/cli/index.js +53 -96
  42. package/dist/cli/index.js.map +1 -1
  43. package/dist/lib/core/client/index.d.ts +13 -43
  44. package/dist/lib/core/client/index.js +47 -26
  45. package/dist/lib/core/client/index.js.map +1 -1
  46. package/dist/lib/core/{compiler → client}/types.d.ts +29 -0
  47. package/dist/lib/core/client/types.js.map +1 -0
  48. package/dist/lib/core/compiler/generator.d.ts +4 -6
  49. package/dist/lib/core/compiler/generator.js +186 -39
  50. package/dist/lib/core/compiler/generator.js.map +1 -1
  51. package/dist/lib/core/compiler/index.d.ts +2 -2
  52. package/dist/lib/core/compiler/index.js +2 -2
  53. package/dist/lib/core/compiler/index.js.map +1 -1
  54. package/dist/lib/core/compiler/pre-routes.d.ts +170 -34
  55. package/dist/lib/core/compiler/pre-routes.js +45 -25
  56. package/dist/lib/core/compiler/pre-routes.js.map +1 -1
  57. package/dist/lib/core/decorators/context.d.ts +78 -8
  58. package/dist/lib/core/decorators/context.js +84 -9
  59. package/dist/lib/core/decorators/context.js.map +1 -1
  60. package/dist/lib/core/decorators/statusCode.js +3 -1
  61. package/dist/lib/core/decorators/statusCode.js.map +1 -1
  62. package/dist/lib/core/package/index.d.ts +11 -0
  63. package/dist/lib/core/package/index.js +42 -0
  64. package/dist/lib/core/package/index.js.map +1 -0
  65. package/dist/lib/core/server/fast-router.d.ts +2 -2
  66. package/dist/lib/core/server/fast-router.js +17 -3
  67. package/dist/lib/core/server/fast-router.js.map +1 -1
  68. package/dist/lib/core/server/index.js +2 -2
  69. package/dist/lib/core/server/index.js.map +1 -1
  70. package/dist/lib/core/server/response.js +21 -1
  71. package/dist/lib/core/server/response.js.map +1 -1
  72. package/dist/lib/core/types/index.d.ts +32 -27
  73. package/package.json +7 -4
  74. package/dist/cli/app.d.ts +0 -1
  75. package/dist/cli/app.js.map +0 -1
  76. package/dist/cli/controller.d.ts +0 -1
  77. package/dist/cli/controller.js +0 -158
  78. package/dist/cli/controller.js.map +0 -1
  79. package/dist/lib/core/compiler/types.js.map +0 -1
  80. /package/dist/lib/core/{compiler → client}/types.js +0 -0
package/README.md CHANGED
@@ -12,12 +12,19 @@ It is designed with a strong focus on developer experience and provides end-to-e
12
12
  ## Features
13
13
 
14
14
  - ⚡ High-performance core built on native Node.js HTTP
15
- - 🚀 Optional uWebSockets.js support via adapter for ultra-low latency and maximum throughput
16
- - 🧠 End-to-end (E2E) type safety across request → response lifecycle
17
- - 🧪 Built-in testing support for E2E validation
15
+ - 🚀 Optional [uWebSockets.js](#adapter) adapter support for ultra-low latency and maximum throughput
16
+ - 🧠 End-to-end [E2E](#e2e) type safety across the entire request → response lifecycle
17
+ - 🎮 Built-in support for [Controllers](#controller) and route-based architecture
18
+ - 🏷️ Powerful Decorator system for routes, middleware, validation, and metadata
19
+ - 📦 [DTO](#dto) (Data Transfer Object) support for structured and type-safe request handling
20
+ - 📂 Built-in [File Upload](#file-upload) support via `useFileUpload()` with zero configuration required
21
+ - 🔌 Native [WebSocket](#web-socket) support for real-time applications and event-driven systems
22
+ - ⚛️ [GraphQL](#graphql) support with flexible schema integration and HTTP adapters
23
+ - 🖥️ Built-in [cluster mode](#cluster) support for multi-core scalability and higher throughput
24
+ - 🧪 Built-in testing utilities for [E2E](#e2e) validation
18
25
  - 🧩 Simple and intuitive developer experience
19
- - 🔌 Flexible architecture for plugins and extensions
20
- - 📘 Auto-generated Swagger documentation via `app.useSwagger()` (zero manual configuration required)
26
+ - 📘 Auto-generated [Swagger](#swagger) documentation via `app.useSwagger()` with zero manual configuration
27
+ - 🔥 Lightweight and optimized for high-performance APIs and microservices
21
28
 
22
29
  ---
23
30
 
@@ -36,7 +43,7 @@ See the [`docs`](https://thanathip41.github.io/tspace-spear) directory for full
36
43
 
37
44
  ## Basic Usage
38
45
  - [Getting Started](#getting-started)
39
- - [Cli](#cli)
46
+ - [Quick Started](#quick-started)
40
47
  - [Adapter](#adapter)
41
48
  - [Cluster](#cluster)
42
49
  - [Global Prefix](#global-prefix)
@@ -55,8 +62,8 @@ See the [`docs`](https://thanathip41.github.io/tspace-spear) directory for full
55
62
  - [Router](#router)
56
63
  - [Swagger](#swagger)
57
64
  - [WebSocket](#websocket)
65
+ - [Graphql](#graphql)
58
66
  - [E2E](#e2e)
59
- - [Example CRUD](#example-crud)
60
67
 
61
68
  ## Getting Started
62
69
  ```js
@@ -72,29 +79,49 @@ new Spear()
72
79
  .listen(8000 , () => console.log(`Server is now listening http://localhost:8000`))
73
80
  ```
74
81
 
75
- ## Cli
82
+ ## Quick Started
83
+ Generate applications, modules, controllers, services, and middleware with the Spear CLI.
76
84
  ```sh
77
85
  # Install CLI globally
78
86
  npm install -g tspace-spear
79
87
 
80
88
  # Create a new application structure
81
- tspace-spear create app src
89
+ spear create new my-app
82
90
 
83
- # Create a new controller
84
- tspace-spear create controller src/controllers/dog
91
+ Successfully created project "my-app"
92
+
93
+ 📦 Project Structure
85
94
 
86
- # Generated structure
87
95
  src/
88
- ├── controllers/
89
- │ └── cat-controller.ts
90
- └── dog-controller.ts
96
+ ├── common/
97
+ │ └── middlewares/
98
+ └── log.middleware.ts
99
+
100
+ ├── modules/
101
+ │ └── cats/
102
+ │ ├── cat.controller.ts
103
+ │ ├── cat.service.ts
104
+ │ └── cat.dto.ts
105
+
106
+ ├── client.ts
91
107
  └── index.ts
92
108
 
93
- npm install ts-node --save-dev
109
+ 🚀 Next Steps
110
+
111
+ cd my-app
112
+
113
+ npm run dev
114
+
115
+ ✔ Server is running at:
116
+ http://localhost:8000
117
+
118
+ ✔ Swagger Docs:
119
+ http://localhost:8000/api/docs
94
120
 
95
- ts-node src/index.ts
96
- ## Server is now listening http://localhost:8000
97
- ## Docs is now listening http://localhost:8000/api/docs
121
+ Run E2E client:
122
+ ts-node src/client.ts
123
+
124
+ ts-node src/client.ts // for E2E
98
125
  ```
99
126
 
100
127
  ## Adapter
@@ -580,8 +607,9 @@ DTO (Data Transfer Object) is used to validate and transform incoming request da
580
607
  import {
581
608
  Controller ,
582
609
  Post,
583
- createDtoDecorator,
584
610
  Validate,
611
+ ValidateDto,
612
+ createDtoDecorator,
585
613
  type T
586
614
  } from 'tspace-spear';
587
615
 
@@ -593,8 +621,6 @@ import {
593
621
  validate
594
622
  } from "class-validator";
595
623
 
596
- import { ClassConstructor, plainToInstance } from 'class-transformer';
597
-
598
624
  const ValidateDtoCustomBody = (keys: string[]) => {
599
625
  return createDtoDecorator((ctx) => {
600
626
  const body = ctx.body ?? {};
@@ -620,13 +646,6 @@ const ValidateDtoCustomBody = (keys: string[]) => {
620
646
  });
621
647
  }
622
648
 
623
- const ValidateDtoZodBody = (schema: z.ZodTypeAny) => {
624
- return createDtoDecorator((ctx) => {
625
- const result = schema.parse(ctx.body);
626
- ctx.body = result as T.Body;
627
- });
628
- }
629
-
630
649
  const ValidateDtoPromiseBody = (keys: string[]) => {
631
650
  return createDtoDecorator(async (ctx) => {
632
651
  await new Promise(resolve => setTimeout(resolve,500));
@@ -646,39 +665,6 @@ const ValidateDtoPromiseBody = (keys: string[]) => {
646
665
  });
647
666
  }
648
667
 
649
- const ValidateDtoClsBody = <T extends object>(
650
- cls: ClassConstructor<T>
651
- ) => {
652
- return createDtoDecorator(async (ctx) => {
653
-
654
- const dto = plainToInstance(
655
- cls,
656
- ctx.body
657
- );
658
-
659
- const errors = await validate(dto);
660
-
661
- if (errors.length > 0) {
662
- throw {
663
- message: "Validation failed",
664
- issues: errors.flatMap((error) => {
665
- const constraints = error.constraints ?? {};
666
-
667
- const firstError = Object.values(constraints)[0] ?? "Validation error";
668
-
669
- return {
670
- path: error.property,
671
- message: firstError,
672
- };
673
- })
674
- };
675
- }
676
-
677
- ctx.body = dto;
678
- }
679
- );
680
- };
681
-
682
668
  const catSchema = z.object({
683
669
  name: z.string(),
684
670
  age: z.number(),
@@ -692,7 +678,6 @@ class CreateCatDto {
692
678
  age!: number;
693
679
  }
694
680
 
695
-
696
681
  // file cat-controller.ts
697
682
  @Controller('/cats')
698
683
  export class CatController {
@@ -701,47 +686,40 @@ export class CatController {
701
686
  // only required validation without type checking
702
687
  @Validate(["name", "age"], { required: { allowEmptyString: false, allowNull: false } })
703
688
  public async basic(ctx : T.Context<{ body : { name : any , age : any }}>) {
704
- const body = ctx.body;
705
689
  return {
706
- body
690
+ body : ctx.body
707
691
  }
708
692
  }
709
693
 
710
- @Post('/')
694
+ @Post('/custom')
711
695
  @ValidateDtoCustomBody(["name", "age"])
712
696
  public async custom(ctx : T.Context<{ body : { name : string , age : number }}>) {
713
- const body = ctx.body;
714
697
  return {
715
- body
716
- }
717
- }
718
-
719
- @Post('/zod')
720
- @ValidateDtoZodBody(catSchema)
721
- public async zod(ctx : T.Context<z.infer<typeof catSchema>>) {
722
- const body = ctx.body;
723
- return {
724
- body
698
+ body : ctx.body
725
699
  }
726
700
  }
727
701
 
728
702
  @Post('/promise')
729
703
  @ValidateDtoPromiseBody(['name'])
730
704
  public async promise(ctx : T.Context<{ body : { name : string }}>) {
731
- const body = ctx.body;
705
+ return {
706
+ body : ctx.body
707
+ }
708
+ }
732
709
 
710
+ @Post('/zod')
711
+ @ValidateDto(catSchema, { adaptor : "zod" })
712
+ public async zod(ctx : T.Context<{ body : z.infer<typeof catSchema>}>) {
733
713
  return {
734
- body
714
+ body : ctx.body
735
715
  }
736
716
  }
737
717
 
738
718
  @Post('/cls')
739
- @ValidateDtoClsBody(CreateCatDto)
719
+ @ValidateDto(CreateCatDto)
740
720
  public async cls(ctx : T.Context<{ body : CreateCatDto }>) {
741
- const body = ctx.body;
742
-
743
721
  return {
744
- body
722
+ body : ctx.body
745
723
  }
746
724
  }
747
725
  }
@@ -1112,6 +1090,244 @@ new Spear()
1112
1090
 
1113
1091
  ```
1114
1092
 
1093
+ ## Graphql
1094
+ GraphQL CRUD Example with graphql-http + tspace-spear
1095
+
1096
+ This example shows how to build a simple GraphQL CRUD API using graphql-http and tspace-spear.
1097
+
1098
+ It includes:
1099
+
1100
+ - GraphQL schema setup
1101
+ - Query and Mutation examples
1102
+ - Create / Read / Update / Delete operations
1103
+ - HTTP integration with graphql-http
1104
+ - cURL testing examples
1105
+
1106
+ The server uses an in-memory array as a fake database for simplicity.
1107
+
1108
+ Features
1109
+ - High performance HTTP server with tspace-spear
1110
+ - Native GraphQL schema definitions
1111
+ - Full CRUD operations
1112
+ - Simple and dependency-light setup
1113
+ - Works with standard GraphQL clients and tools
1114
+
1115
+ ```sh
1116
+ npm install graphql graphql-http
1117
+ ```
1118
+
1119
+ ```js
1120
+
1121
+ import {
1122
+ GraphQLSchema,
1123
+ GraphQLObjectType,
1124
+ GraphQLString,
1125
+ GraphQLList,
1126
+ GraphQLNonNull,
1127
+ GraphQLID,
1128
+ } from 'graphql';
1129
+
1130
+ import { createHandler } from 'graphql-http/lib/use/http';
1131
+ import { type T, Spear } from "tspace-spear";
1132
+
1133
+ /**
1134
+ * Fake database
1135
+ */
1136
+ const users : {
1137
+ id : string;
1138
+ name : string;
1139
+ email :string
1140
+ }[] = [];
1141
+
1142
+ /**
1143
+ * User Type
1144
+ */
1145
+ const UserType = new GraphQLObjectType({
1146
+ name: 'User',
1147
+
1148
+ fields: {
1149
+ id: { type: GraphQLID },
1150
+ name: { type: GraphQLString },
1151
+ email: { type: GraphQLString },
1152
+ },
1153
+ });
1154
+
1155
+ /**
1156
+ * Queries (READ)
1157
+ */
1158
+ const QueryType = new GraphQLObjectType({
1159
+ name: 'Query',
1160
+
1161
+ fields: {
1162
+ users: {
1163
+ type: new GraphQLList(UserType),
1164
+
1165
+ resolve: () => {
1166
+ return users;
1167
+ },
1168
+ },
1169
+
1170
+ user: {
1171
+ type: UserType,
1172
+
1173
+ args: {
1174
+ id: { type: new GraphQLNonNull(GraphQLID) },
1175
+ },
1176
+
1177
+ resolve: (_, args) => {
1178
+ return users.find((v) => v.id === args.id);
1179
+ },
1180
+ },
1181
+ },
1182
+ });
1183
+
1184
+ /**
1185
+ * Mutations (CREATE UPDATE DELETE)
1186
+ */
1187
+ const MutationType = new GraphQLObjectType({
1188
+ name: 'Mutation',
1189
+
1190
+ fields: {
1191
+ /**
1192
+ * CREATE
1193
+ */
1194
+ createUser: {
1195
+ type: UserType,
1196
+
1197
+ args: {
1198
+ name: { type: new GraphQLNonNull(GraphQLString) },
1199
+ email: { type: new GraphQLNonNull(GraphQLString) },
1200
+ },
1201
+
1202
+ resolve: (_, args) => {
1203
+ const user = {
1204
+ id: String(users.length + 1),
1205
+ name: args.name,
1206
+ email: args.email,
1207
+ };
1208
+
1209
+ users.push(user);
1210
+
1211
+ return user;
1212
+ },
1213
+ },
1214
+
1215
+ /**
1216
+ * UPDATE
1217
+ */
1218
+ updateUser: {
1219
+ type: UserType,
1220
+
1221
+ args: {
1222
+ id: { type: new GraphQLNonNull(GraphQLID) },
1223
+ name: { type: GraphQLString },
1224
+ email: { type: GraphQLString },
1225
+ },
1226
+
1227
+ resolve: (_, args) => {
1228
+ const user = users.find((v) => v.id === args.id);
1229
+
1230
+ if (!user) {
1231
+ throw new Error('User not found');
1232
+ }
1233
+
1234
+ if (args.name !== undefined) {
1235
+ user.name = args.name;
1236
+ }
1237
+
1238
+ if (args.email !== undefined) {
1239
+ user.email = args.email;
1240
+ }
1241
+
1242
+ return user;
1243
+ },
1244
+ },
1245
+
1246
+ /**
1247
+ * DELETE
1248
+ */
1249
+ deleteUser: {
1250
+ type: GraphQLString,
1251
+
1252
+ args: {
1253
+ id: { type: new GraphQLNonNull(GraphQLID) },
1254
+ },
1255
+
1256
+ resolve: (_, args) => {
1257
+ const index = users.findIndex((v) => v.id === args.id);
1258
+
1259
+ if (index === -1) {
1260
+ throw new Error('User not found');
1261
+ }
1262
+
1263
+ users.splice(index, 1);
1264
+
1265
+ return 'Deleted';
1266
+ },
1267
+ },
1268
+ },
1269
+ });
1270
+
1271
+ /**
1272
+ * Schema
1273
+ */
1274
+ const schema = new GraphQLSchema({
1275
+ query: QueryType,
1276
+ mutation: MutationType,
1277
+ });
1278
+
1279
+ /**
1280
+ * Handler
1281
+ */
1282
+ const graphqlHandler = createHandler({
1283
+ schema,
1284
+ });
1285
+
1286
+ const app = new Spear()
1287
+ .post('/graphql',({ req , res }) => graphqlHandler(req , res))
1288
+
1289
+ app.listen(4000 , ({ port , server }) => {
1290
+ console.log(`server listening on : http://localhost:${port}/graphql`)
1291
+ })
1292
+ ```
1293
+
1294
+ ```sh
1295
+ ## Create
1296
+ curl -X POST http://localhost:4000/graphql \
1297
+ -H "Content-Type: application/json" \
1298
+ -d '{
1299
+ "query": "mutation { createUser(name:\"John\", email:\"john@example.com\") { id name email } }"
1300
+ }'
1301
+
1302
+ ## Read all
1303
+ curl -X POST http://localhost:4000/graphql \
1304
+ -H "Content-Type: application/json" \
1305
+ -d '{
1306
+ "query": "query { users { id name email } }"
1307
+ }'
1308
+
1309
+ ## Read one
1310
+ curl -X POST http://localhost:4000/graphql \
1311
+ -H "Content-Type: application/json" \
1312
+ -d '{
1313
+ "query": "query { user(id:\"1\") { id name email } }"
1314
+ }'
1315
+
1316
+ ## Update
1317
+ curl -X POST http://localhost:4000/graphql \
1318
+ -H "Content-Type: application/json" \
1319
+ -d '{
1320
+ "query": "mutation { updateUser(id:\"1\", name:\"Johnny\") { id name email } }"
1321
+ }'
1322
+
1323
+ ## Delete
1324
+ curl -X POST http://localhost:4000/graphql \
1325
+ -H "Content-Type: application/json" \
1326
+ -d '{
1327
+ "query": "mutation { deleteUser(id:\"1\") }"
1328
+ }'
1329
+ ```
1330
+
1115
1331
  ## E2E
1116
1332
  Provides end-to-end type safety and testing support across the full request lifecycle, from request input to
1117
1333
  response output. It allows you to:
@@ -1293,66 +1509,3 @@ const res = await client.get("/cats");
1293
1509
 
1294
1510
  ```
1295
1511
 
1296
- ## Example CRUD
1297
- ```js
1298
- import { Spear } from "tspace-spear";
1299
-
1300
- const spears = [
1301
- {
1302
- id : 1,
1303
- damage : 100
1304
- },
1305
- {
1306
- id : 2,
1307
- damage : 75
1308
- },
1309
- {
1310
- id : 3,
1311
- damage : 50
1312
- }
1313
- ]
1314
-
1315
- new Spear()
1316
- // enable body payload
1317
- .useBodyParser()
1318
- .get('/' , () => spears)
1319
- .get('/:id' , ({ params }) => spears.find(spear => spear.id === Number(params.id ?? 0)))
1320
- .post('/' , ({ body }) => {
1321
- // please validation the your body
1322
- const damage = Number(body.damage ?? (Math.random() * 100).toFixed(0))
1323
-
1324
- const id = spears.reduce((max, spear) => spear.id > max ? spear.id : max, 0) + 1
1325
-
1326
- spears.push({ id , damage })
1327
-
1328
- return spears.find(spear => spear.id === id)
1329
- })
1330
- .patch('/:id' , ({ params , body , res }) => {
1331
-
1332
- const damage = Number(body.damage ?? (Math.random() * 100).toFixed(0))
1333
-
1334
- const id = Number(params.id)
1335
-
1336
- const spear = spears.find(spear => spear.id === id)
1337
-
1338
- if (spear == null) return res.status(404).json({ message : 'Spear not found'})
1339
-
1340
- spear.damage = damage;
1341
-
1342
- return spears.find(spear => spear.id === id)
1343
- })
1344
- .delete('/:id', ({ params , res }) => {
1345
-
1346
- const id = Number(params.id)
1347
-
1348
- const spear = spears.find(spear => spear.id === id)
1349
-
1350
- if (spear == null) return res.status(404).json({ message : 'Spear not found'})
1351
-
1352
- spears.splice(spears.findIndex(spear => spear.id === Number(params.id ?? 0)), 1)
1353
-
1354
- return res.status(204).json()
1355
- })
1356
- .listen(8000 , () => console.log(`Server is now listening http://localhost:8000`))
1357
-
1358
- ```
@@ -0,0 +1 @@
1
+ export declare function createApp(inputPath?: string): Promise<void>;
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createApp = createApp;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const child_process_1 = require("child_process");
10
+ const template_1 = require("./template");
11
+ const template_2 = require("../client/template");
12
+ const template_3 = require("../middleware/template");
13
+ const template_4 = require("../controller/template");
14
+ const template_5 = require("../service/template");
15
+ const template_6 = require("../dto/template");
16
+ const c = {
17
+ bold: (text) => `\x1b[1m${text}\x1b[0m`,
18
+ dim: (text) => `\x1b[2m${text}\x1b[0m`,
19
+ green: (text) => `\x1b[32m${text}\x1b[0m`,
20
+ cyan: (text) => `\x1b[36m${text}\x1b[0m`,
21
+ underline: (text) => `\x1b[4m${text}\x1b[0m`,
22
+ gray: (text) => `\x1b[90m${text}\x1b[0m`,
23
+ reset: "\x1b[0m"
24
+ };
25
+ async function createApp(inputPath) {
26
+ if (!inputPath) {
27
+ console.log("Missing target path, try: spear g app src");
28
+ process.exit(1);
29
+ }
30
+ const root = path_1.default.resolve(process.cwd(), inputPath);
31
+ fs_1.default.mkdirSync(root, { recursive: true });
32
+ await fs_1.default.promises.writeFile(path_1.default.join(root, "package.json"), JSON.stringify({
33
+ name: path_1.default.basename(root),
34
+ version: "1.0.0",
35
+ main: "dist/index.js",
36
+ scripts: {
37
+ build: "tsc",
38
+ start: "node dist/index.js",
39
+ dev: "ts-node src/index.ts",
40
+ },
41
+ dependencies: {
42
+ "tspace-spear": "latest",
43
+ "class-transformer": "0.5.1",
44
+ "class-validator": "0.15.1"
45
+ },
46
+ devDependencies: {
47
+ "typescript": "5.6.2",
48
+ "ts-node": "10.9.2",
49
+ "@types/node": "16.18.126"
50
+ },
51
+ }, null, 2));
52
+ await fs_1.default.promises.writeFile(path_1.default.join(root, "tsconfig.json"), JSON.stringify({
53
+ compilerOptions: {
54
+ "target": "esnext",
55
+ "module": "commonjs",
56
+ "lib": ["esnext", "DOM"],
57
+ "types": ["node"],
58
+ "allowJs": true,
59
+ "checkJs": false,
60
+ "outDir": "dist",
61
+ "rootDir": "src",
62
+ "strict": true,
63
+ "esModuleInterop": true,
64
+ "skipLibCheck": true,
65
+ "forceConsistentCasingInFileNames": true,
66
+ "emitDecoratorMetadata": true,
67
+ "experimentalDecorators": true,
68
+ },
69
+ }, null, 2));
70
+ const src = path_1.default.join(root, "src");
71
+ await fs_1.default.promises.mkdir(src, { recursive: true });
72
+ await fs_1.default.promises.mkdir(path_1.default.join(src, "common", "middlewares"), { recursive: true });
73
+ await fs_1.default.promises.mkdir(path_1.default.join(src, "modules", "cats"), { recursive: true });
74
+ await fs_1.default.promises.writeFile(path_1.default.join(src, "index.ts"), template_1.AppTemplate);
75
+ await fs_1.default.promises.writeFile(path_1.default.join(src, "client.ts"), template_2.ClientTemplate);
76
+ await fs_1.default.promises.writeFile(path_1.default.join(src, "common", "middlewares", "log.middleware.ts"), template_3.MiddlewareTemplate);
77
+ await fs_1.default.promises.writeFile(path_1.default.join(src, "modules", "cats", "cat.controller.ts"), template_4.ControllerTemplate);
78
+ await fs_1.default.promises.writeFile(path_1.default.join(src, "modules", "cats", "cat.service.ts"), template_5.ServiceTemplate);
79
+ await fs_1.default.promises.writeFile(path_1.default.join(src, "modules", "cats", "cat.dto.ts"), template_6.DtoTemplate);
80
+ console.log(`\n${c.bold("$ npm install")}\n`);
81
+ const startTime = Date.now();
82
+ const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
83
+ let i = 0;
84
+ const spinner = setInterval(() => {
85
+ process.stdout.write(`\r ${c.cyan(frames[i])} Installing dependencies...`);
86
+ i = (i + 1) % frames.length;
87
+ }, 50);
88
+ await new Promise((resolve, reject) => {
89
+ (0, child_process_1.exec)("npm install", { cwd: root }, (error) => {
90
+ if (error)
91
+ return reject(error);
92
+ return resolve();
93
+ });
94
+ });
95
+ await new Promise((resolve) => setTimeout(resolve, 500));
96
+ const nodeModulesPath = path_1.default.join(root, "node_modules");
97
+ let totalPhysicalPackages = 0;
98
+ if (fs_1.default.existsSync(nodeModulesPath)) {
99
+ const files = await fs_1.default.promises.readdir(nodeModulesPath);
100
+ const packages = files.filter(file => !file.startsWith(".") && !file.startsWith("@"));
101
+ totalPhysicalPackages = packages.length;
102
+ }
103
+ clearInterval(spinner);
104
+ process.stdout.write("\r\x1b[K");
105
+ const endTime = Date.now();
106
+ const elapsedSeconds = ((endTime - startTime) / 1000).toFixed(2);
107
+ console.log(`${c.bold(c.cyan("dependencies"))}`);
108
+ console.log(`${c.gray("├──")} ${c.green("+")} tspace-spear${c.dim("@latest")}`);
109
+ console.log(`${c.gray("├──")} ${c.green("+")} class-transformer${c.dim("@0.5.1")}`);
110
+ console.log(`${c.gray("└──")} ${c.green("+")} class-validator${c.dim("@0.15.1")}`);
111
+ console.log(`${c.gray("│")}`);
112
+ console.log(`${c.bold(c.gray("devDependencies"))}`);
113
+ console.log(`${c.gray("├──")} ${c.green("+")} typescript${c.dim("@5.6.2")}`);
114
+ console.log(`${c.gray("├──")} ${c.green("+")} ts-node${c.dim("@10.9.2")}`);
115
+ console.log(`${c.gray("└──")} ${c.green("+")} @types/node${c.dim("@16.18.126")}\n`);
116
+ console.log(`\n${c.green(`${totalPhysicalPackages} packages installed`)} ${c.dim(`[${elapsedSeconds}s]`)}`);
117
+ console.log(`${c.dim(`[${elapsedSeconds}s] npm install`)}`);
118
+ console.log(`\n--------`);
119
+ console.log("A local project was created for you and dependencies were installed automatically.\n");
120
+ console.log(`${c.green("Created spear project successfully")}\n`);
121
+ console.log(c.bold(c.gray("# To get started, run:")));
122
+ console.log(`\n cd ${inputPath}\n ${c.cyan("npm run dev")}\n`);
123
+ }
124
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/cli/generators/app/index.ts"],"names":[],"mappings":";;;;;AAsBA,8BAsJC;AA5KD,4CAAoB;AACpB,gDAAwB;AACxB,iDAAqC;AACrC,yCAAyC;AACzC,iDAAoD;AACpD,qDAA4D;AAC5D,qDAA4D;AAC5D,kDAAsD;AACtD,8CAA8C;AAG9C,MAAM,CAAC,GAAG;IACR,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,UAAU,IAAI,SAAS;IAC/C,GAAG,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,UAAU,IAAI,SAAS;IAC9C,KAAK,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,WAAW,IAAI,SAAS;IACjD,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,WAAW,IAAI,SAAS;IAChD,SAAS,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,UAAU,IAAI,SAAS;IACpD,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,WAAW,IAAI,SAAS;IAChD,KAAK,EAAE,SAAS;CACjB,CAAC;AAGK,KAAK,UAAU,SAAS,CAAC,SAAkB;IAChD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;QACzD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,IAAI,GAAG,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,CAAC,CAAC;IAEpD,YAAE,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAExC,MAAM,YAAE,CAAC,QAAQ,CAAC,SAAS,CACzB,cAAI,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,EAC/B,IAAI,CAAC,SAAS,CACZ;QACE,IAAI,EAAE,cAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QACzB,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE,eAAe;QACrB,OAAO,EAAE;YACP,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,oBAAoB;YAC3B,GAAG,EAAE,sBAAsB;SAC5B;QACD,YAAY,EAAE;YACZ,cAAc,EAAE,QAAQ;YACxB,mBAAmB,EAAE,OAAO;YAC5B,iBAAiB,EAAE,QAAQ;SAC5B;QACD,eAAe,EAAE;YACf,YAAY,EAAE,OAAO;YACrB,SAAS,EAAE,QAAQ;YACnB,aAAa,EAAE,WAAW;SAC3B;KACF,EACD,IAAI,EACJ,CAAC,CACF,CACF,CAAC;IAEF,MAAM,YAAE,CAAC,QAAQ,CAAC,SAAS,CACzB,cAAI,CAAC,IAAI,CAAC,IAAI,EAAE,eAAe,CAAC,EAChC,IAAI,CAAC,SAAS,CACZ;QACE,eAAe,EAAE;YACf,QAAQ,EAAE,QAAQ;YAClB,QAAQ,EAAE,UAAU;YACpB,KAAK,EAAE,CAAC,QAAQ,EAAC,KAAK,CAAC;YACvB,OAAO,EAAE,CAAC,MAAM,CAAC;YACjB,SAAS,EAAE,IAAI;YACf,SAAS,EAAE,KAAK;YAChB,QAAQ,EAAE,MAAM;YAChB,SAAS,EAAE,KAAK;YAChB,QAAQ,EAAE,IAAI;YACd,iBAAiB,EAAE,IAAI;YACvB,cAAc,EAAE,IAAI;YACpB,kCAAkC,EAAE,IAAI;YACxC,uBAAuB,EAAE,IAAI;YAC7B,wBAAwB,EAAE,IAAI;SAC/B;KACF,EACD,IAAI,EACJ,CAAC,CACF,CACF,CAAC;IAEF,MAAM,GAAG,GAAG,cAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAEnC,MAAM,YAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAElD,MAAM,YAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,aAAa,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtF,MAAM,YAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEhF,MAAM,YAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,sBAAW,CAAC,CAAC;IACrE,MAAM,YAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,EAAE,yBAAc,CAAC,CAAC;IAEzE,MAAM,YAAE,CAAC,QAAQ,CAAC,SAAS,CACzB,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,aAAa,EAAE,mBAAmB,CAAC,EAC5D,6BAAkB,CACnB,CAAC;IAEF,MAAM,YAAE,CAAC,QAAQ,CAAC,SAAS,CACzB,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,mBAAmB,CAAC,EACtD,6BAAkB,CACnB,CAAC;IAEF,MAAM,YAAE,CAAC,QAAQ,CAAC,SAAS,CACzB,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,CAAC,EACnD,0BAAe,CAChB,CAAC;IAEF,MAAM,YAAE,CAAC,QAAQ,CAAC,SAAS,CACzB,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,CAAC,EAC/C,sBAAW,CACZ,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;IAE9C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IAClE,IAAI,CAAC,GAAG,CAAC,CAAC;IAEV,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE;QAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC;QAC5E,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC;IAC9B,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,IAAA,oBAAI,EAAC,aAAa,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE;YAC3C,IAAI,KAAK;gBAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;YAChC,OAAO,OAAO,EAAE,CAAC;QACnB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;IAEzD,MAAM,eAAe,GAAG,cAAI,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;IACxD,IAAI,qBAAqB,GAAG,CAAC,CAAC;IAE9B,IAAI,YAAE,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,MAAM,YAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QACzD,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;QACtF,qBAAqB,GAAG,QAAQ,CAAC,MAAM,CAAC;IAC1C,CAAC;IAED,aAAa,CAAC,OAAO,CAAC,CAAC;IACvB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAEjC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC3B,MAAM,cAAc,GAAG,CAAC,CAAC,OAAO,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAEjE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAChF,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACpF,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IACnF,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAE9B,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC7E,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAC3E,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IAEpF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,qBAAqB,qBAAqB,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,cAAc,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5G,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,cAAc,gBAAgB,CAAC,EAAE,CAAC,CAAC;IAE5D,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;IACzB,OAAO,CAAC,GAAG,CAAC,sFAAsF,CAAC,CAAC;IACpG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,oCAAoC,CAAC,IAAI,CAAC,CAAC;IAElE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC;IACtD,OAAO,CAAC,GAAG,CAAC,UAAU,SAAS,OAAO,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;AACnE,CAAC"}
@@ -0,0 +1 @@
1
+ export declare const AppTemplate = "\nimport Spear from \"tspace-spear\";\n\nconst app = new Spear({\n logger: true,\n controllers: {\n folder: `${__dirname}/modules/*`,\n name: /controller\\.(ts|js)$/i,\n\n // don't forget to set this option for auto-generate route metadata for type-safe E2E usage, \n // and swagger documentation. By default if use .useSwagger() in app no need to set any description\n preRouteTypes: true\n }\n})\n\napp.cors({\n origins: [ \n /^http:\\/\\/localhost:\\d+$/ \n ],\n credentials: true\n});\n\napp.useGlobalPrefix(\"api\");\napp.useSwagger();\napp.useBodyParser();\n\napp.listen(8000 , ({ port , server }) => {\n console.log(`Server listening on : http://localhost:${port}`)\n console.log(`Docs listening on : http://localhost:${port}/api/docs`)\n});\n\ntype AppRouter = typeof app.contract;\n\nexport { AppRouter };\nexport { app };\nexport default app;\n";