@xeno-js/cli 0.1.3 → 0.1.4

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 (88) hide show
  1. package/LICENSE +18 -12
  2. package/README.md +461 -236
  3. package/dist/index.js +985 -653
  4. package/dist/index.js.map +1 -1
  5. package/package.json +91 -66
  6. package/.github/.copilot-instruction.md +0 -73
  7. package/.github/agents/git-operator.agent.md +0 -86
  8. package/.github/agents/unit-tester.agent.md +0 -68
  9. package/.husky/commit-msg +0 -1
  10. package/.husky/pre-commit +0 -1
  11. package/.husky/pre-push +0 -1
  12. package/.prettierignore +0 -7
  13. package/.prettierrc.json +0 -37
  14. package/commitlint.config.cjs +0 -39
  15. package/eslint.config.mjs +0 -306
  16. package/lint-staged.config.mjs +0 -5
  17. package/logo/logo.png +0 -0
  18. package/src/domain/contracts/icommand-cli.contracts.ts +0 -13
  19. package/src/domain/contracts/icommand-runner.contracts.ts +0 -3
  20. package/src/domain/contracts/idispatch.contracts.ts +0 -3
  21. package/src/domain/contracts/ifile-service.contracts.ts +0 -3
  22. package/src/domain/contracts/igenerator.contracts.ts +0 -5
  23. package/src/domain/contracts/index.ts +0 -6
  24. package/src/domain/contracts/iscaffold-strategy.contracts.ts +0 -7
  25. package/src/domain/index.ts +0 -1
  26. package/src/index.ts +0 -30
  27. package/src/infrastructure/bootstrap/bootstrapper.ts +0 -30
  28. package/src/infrastructure/bootstrap/index.ts +0 -1
  29. package/src/infrastructure/builder/builder.test.ts +0 -36
  30. package/src/infrastructure/builder/builder.ts +0 -15
  31. package/src/infrastructure/builder/index.ts +0 -1
  32. package/src/infrastructure/command_launcher/command.utils.ts +0 -31
  33. package/src/infrastructure/command_launcher/index.ts +0 -0
  34. package/src/infrastructure/commands/command-runner.service.ts +0 -36
  35. package/src/infrastructure/commands/generate.command.ts +0 -55
  36. package/src/infrastructure/commands/help.command.ts +0 -63
  37. package/src/infrastructure/commands/index.ts +0 -4
  38. package/src/infrastructure/commands/new-project.command.ts +0 -47
  39. package/src/infrastructure/dispatcher/dispatcher.ts +0 -45
  40. package/src/infrastructure/dispatcher/index.ts +0 -1
  41. package/src/infrastructure/file/file.service.ts +0 -14
  42. package/src/infrastructure/file/index.ts +0 -1
  43. package/src/infrastructure/generators/core/bootstrap.generator.ts +0 -118
  44. package/src/infrastructure/generators/core/command/cqrs.generator.ts +0 -63
  45. package/src/infrastructure/generators/core/command/generate-command.generator.ts +0 -191
  46. package/src/infrastructure/generators/core/command/generate-query.generator.ts +0 -150
  47. package/src/infrastructure/generators/core/drizzle-sql-lite.generator.ts +0 -77
  48. package/src/infrastructure/generators/core/drizzle.generator.ts +0 -87
  49. package/src/infrastructure/generators/core/env.generator.ts +0 -69
  50. package/src/infrastructure/generators/core/index.ts +0 -9
  51. package/src/infrastructure/generators/core/main.generator.ts +0 -41
  52. package/src/infrastructure/generators/core/packagejson.generator.ts +0 -70
  53. package/src/infrastructure/generators/core/readme.generator.ts +0 -427
  54. package/src/infrastructure/generators/core/registry.generator.ts +0 -40
  55. package/src/infrastructure/generators/core/tsconfig.generator.ts +0 -32
  56. package/src/infrastructure/generators/gitignore.generator.ts +0 -60
  57. package/src/infrastructure/generators/vue/app-vue.generator.ts +0 -21
  58. package/src/infrastructure/generators/vue/bootstrap-ts.generator.ts +0 -60
  59. package/src/infrastructure/generators/vue/command_query/cqrs.generator.ts +0 -36
  60. package/src/infrastructure/generators/vue/command_query/generate-command-vue.generator.ts +0 -153
  61. package/src/infrastructure/generators/vue/command_query/generate-query-vue.generator.ts +0 -161
  62. package/src/infrastructure/generators/vue/env.generator.ts +0 -39
  63. package/src/infrastructure/generators/vue/index-html.generator.ts +0 -24
  64. package/src/infrastructure/generators/vue/index.ts +0 -12
  65. package/src/infrastructure/generators/vue/main.generator.ts +0 -41
  66. package/src/infrastructure/generators/vue/packagejson.generator.ts +0 -50
  67. package/src/infrastructure/generators/vue/readme.generator.ts +0 -389
  68. package/src/infrastructure/generators/vue/registry-ts.generator.ts +0 -26
  69. package/src/infrastructure/generators/vue/router.generator.ts +0 -35
  70. package/src/infrastructure/generators/vue/tailwind.generator.ts +0 -17
  71. package/src/infrastructure/generators/vue/tsconfig.generator.ts +0 -38
  72. package/src/infrastructure/generators/vue/use-app.generator.ts +0 -38
  73. package/src/infrastructure/generators/vue/vite-config.generator.ts +0 -35
  74. package/src/infrastructure/index.ts +0 -5
  75. package/src/infrastructure/strategies/core-scaffold.strategy.ts +0 -100
  76. package/src/infrastructure/strategies/index.ts +0 -2
  77. package/src/infrastructure/strategies/vue-scaffold.strategy.ts +0 -79
  78. package/src/shared/constants/command.constants.ts +0 -18
  79. package/src/shared/constants/core.constants.ts +0 -7
  80. package/src/shared/constants/index.ts +0 -2
  81. package/src/shared/index.ts +0 -3
  82. package/src/shared/types/common.types.ts +0 -68
  83. package/src/shared/types/index.ts +0 -1
  84. package/src/shared/utils/guards.utils.ts +0 -334
  85. package/src/shared/utils/index.ts +0 -2
  86. package/src/shared/utils/string.utils.ts +0 -60
  87. package/tsconfig.json +0 -15
  88. package/tsup.config.ts +0 -13
@@ -1,427 +0,0 @@
1
- import path from 'node:path'
2
-
3
- import type { IFileService, IGenerator } from '../../../domain'
4
- import { type CoreOptions } from '../../../shared'
5
-
6
- export class ReadmeGenerator implements IGenerator<CoreOptions> {
7
- constructor(private readonly _fileService: IFileService) {}
8
-
9
- public async generate(projectPath: string, _options: CoreOptions): Promise<void> {
10
- const content = `
11
- <div align="center">
12
- <img src="logo/logo.png" alt="Xeno Logo" width="140" />
13
-
14
- <h1>Xeno</h1>
15
-
16
- <p><em>Enterprise-grade DDD & CQRS framework for Node.js</em></p>
17
-
18
- <p>
19
- <a href="https://github.com/xeno-js/xeno-js">
20
- <img src="https://img.shields.io/badge/Powered%20by-Xeno-blueviolet?style=flat-square" alt="Powered by Xeno" />
21
- </a>
22
- <a href="https://github.com/xeno-js/xeno-js/blob/main/LICENSE">
23
- <img src="https://img.shields.io/npm/l/@xeno?style=flat-square" alt="License: ISC" />
24
- </a>
25
- <a href="https://www.npmjs.com/package/@xeno/core">
26
- <img src="https://img.shields.io/npm/v/@xeno/core?style=flat-square" alt="NPM Version" />
27
- </a>
28
- <a href="https://buymeacoffee.com/xenojs">
29
- <img src="https://img.shields.io/badge/Buy%20Me%20A%20Coffee-Support-FFdd00?style=flat-square&logo=buy-me-a-coffee&logoColor=black" alt="Buy Me A Coffee" />
30
- </a>
31
- </p>
32
- </div>
33
-
34
- ---
35
-
36
- ## What is Xeno?
37
-
38
- **Xeno** is an enterprise-grade, runtime-agnostic architectural framework for
39
- Node.js built natively with TypeScript. It provides structural primitives for
40
- implementing robust **Domain-Driven Design (DDD)** and **Command Query
41
- Responsibility Segregation (CQRS)** patterns. By shifting operational logic away
42
- from delivery mechanisms and transport frameworks, Xeno ensures your core
43
- application architecture remains pristine, testable, and completely isolated
44
- from external infrastructural churn.
45
-
46
- ---
47
-
48
- ## 💡 Why Choose Xeno?
49
-
50
- Modern Node.js frameworks often tie business workflows tightly to HTTP server
51
- abstractions or rely heavily on experimental language features. Xeno fixes this
52
- with an emphasis on developer experience, type safety, and clean separation of
53
- concerns.
54
-
55
- - **Zero Decorators**: Xeno eliminates reliance on experimental or unstable TS
56
- decorator specifications (\`reflect-metadata\`). The IoC container
57
- (\`ServiceContainer\`) uses pure, explicit functional factories that optimize
58
- compilation speeds and eliminate runtime black-box behaviors.
59
- - **Complete Server Decoupling**: Xeno does not care if you use Fastify, Hono,
60
- Express, Koa, or AWS Lambda. The presentation layer handles incoming data
61
- using plain, primitive contracts, making migration or multi-runtime hosting
62
- completely seamless.
63
- - **Pay-For-What-You-Use (Opt-in Modularity)**: Core dependencies are
64
- strategically classified as optional peer dependencies. If your architecture
65
- doesn't use Redis, Sentry, or Supabase, you do not pull them into your node
66
- modules.
67
- - **Enterprise-Grade Resiliency & Cross-Cutting Pipelines**: Address complex
68
- distributed patterns natively without code duplication. Xeno provides
69
- out-of-the-box composite behaviors:
70
- - **Idempotency**: Implements multi-tenant logic keyspaces matching advanced
71
- SaaS factory patterns for logical partitioning.
72
- - **Concurrency Control**: Mitigates thundering herd impacts via advanced
73
- backoff retry strategies coupled with randomized jitter.
74
- - **Resilience Policies**: Deep integration with circuit breakers, bulkheads,
75
- and fallbacks.
76
- - **Deterministic Type Safety**: Strong infrastructure validation strategies
77
- using Zod schemas.
78
-
79
- ---
80
-
81
- ## 📖 Documentation & Getting Started
82
-
83
- To explore the architecture, programmatic configurations, and extension
84
- workflows of Xeno, read the full technical manuals located inside the main
85
- documentation hub:
86
-
87
- - **[Framework Documentation Repository](https://www.xeno-js.it/introduction)**
88
-
89
- Inside, you will find exhaustive, step-by-step assembly guides covering core
90
- host building (\`AppBuilder\`), isolated request middleware lifecycles, functional
91
- \`Result\` monads, and zero-trust authorization pipeline behavior tracks.
92
-
93
- ---
94
-
95
- ## 🚀 Live Executable Demos
96
-
97
- Want to see how Xeno works? Check out the functional example application
98
- showcasing end-to-end command/query segregation, multi-tenant databases, and
99
- resilient schema handling.
100
-
101
- You can dive straight into the explicit source code modules of specialized
102
- sandbox environments:
103
-
104
- - **[\`pipelines_middleware_demo/\`](https://www.xeno-js.it/demo)**: Traces
105
- an execution thread from the raw HTTP transport presentation layer, executing
106
- automated header extraction and anchoring metadata variables into
107
- \`AsyncLocalStorage\` thread boundaries.
108
-
109
- ---
110
-
111
- ## 📦 Installation
112
-
113
- Install the core package:
114
-
115
- \`\`\`bash
116
- npm install @xeno-js/core
117
-
118
- \`\`\`
119
-
120
- Xeno uses **Optional Peer Dependencies**. You only install the external
121
- libraries you actually need. Node.js will strictly lazy-load only the modules
122
- you enable in the configuration.
123
-
124
- \`\`\`bash
125
- # Example: Install tools only if you enable them in the builder
126
- npm install zod pino cockatiel drizzle-orm
127
-
128
- \`\`\`
129
-
130
- ---
131
-
132
- ## ⚡ Bootstrapping & Middleware Example
133
-
134
- Below is an architectural example of how to configure the Xeno
135
- \`ServiceContainer\`, load core modules, and process an incoming application
136
- payload natively inside a server middleware wrapper.
137
-
138
- ### 1. Initialize the Container and Configure Modules
139
-
140
- \`\`\`typescript
141
- import { AppBuilder, LOG_LEVEL, TOKENS, XenoRegistry } from '@xeno-js/core'
142
- import { FindUserQueryHandler } from './user/cqrs/handlers/index'
143
- import { FindUserController } from './user/controllers/index'
144
- import { UserMapper } from './user/mappers/user.mapper'
145
- import { UserWriteRepository } from './user/repositories/user-write.repository'
146
- import { UserDataSource } from './user/datasources/user.datasource'
147
-
148
- // Map your registry token with XenoRegistry<TSchemaDb, TExtension>
149
- type MyRegistry = XenoRegistry<{ /** Your Db Schema here **/}, {
150
- USER_MAPPER_TOKEN: UserMapper
151
- USER_DS_TOKEN: UserDataSource
152
- USER_REPOSITORY_TOKEN: UserWriteRepository
153
- FIND_USER_QUERY_HANDLER_TOKEN: FindUserQueryHandler
154
- FIND_USER_CONTROLLER_TOKEN: FindUserController
155
- }>
156
-
157
- // Create the root IoC container context
158
- export const bootstrap = new AppBuilder<MyRegistry>()
159
- // Configure middleware and only PUBLIC routes
160
- .addMiddlewares(opts => {
161
- opts.routeRegistry = {
162
- '/api/user/:id': ['GET', 'POST'],
163
- }
164
- })
165
- // Configure the CQRS pipeline
166
- // Can register Policies for your intent
167
- .addPipeline((config) => {
168
- config.authorization.policies = {
169
- 'FIND_USER_QUERY_HANDLER_TOKEN': {
170
- // Add authz by user id
171
- userId: true
172
- // Add authz by tenant id
173
- tenantId: true
174
- // Add authz by roles
175
- roles: ['admin']
176
- // Add authz by perissions
177
- permissions: ['read'],
178
- }
179
- }
180
- // Can add idempotency pipeline for command
181
- config.commandBus.idempotency = { lockTtlSeconds: 30, processedTtlSeconds: 60 }
182
- // Can add concurrency pipeline for command
183
- config.commandBus.concurrency = { delayConfig: { baseDelayMs: 100, maxJitterMs: 500 }, maxRetries: 3 }
184
- // Can add caching pipeline for query
185
- config.queryBus.isEnabled = true
186
- })
187
- // Configure Database with drizzle
188
- .addDb((opts, config) => {
189
- opts.connectionString = config.getOrThrow('DATABASE_URL')
190
- })
191
- // Configure Authentication with supabase
192
- .addAuth((opts, config) => {
193
- opts.key = 'demo-key'
194
- opts.url = config.getOrThrow('API_BASE_URL')
195
- })
196
- // Configure your logger (e.g. Console, Sentry, Pino or custom logger)
197
- .addLogger((config) => {
198
- config.level = LOG_LEVEL.INFO
199
- config.console = true
200
- })
201
- // Register your services
202
- .addServices((services) => {
203
- // REGISTER MAPPER
204
- services.addScoped('USER_MAPPER_TOKEN', () => new UserMapper())
205
-
206
- // REGISTER DATASOURCES
207
- services.addScoped('USER_DS_TOKEN', (c) => new UserDataSource(c.resolve(TOKENS.DB_CONTEXT)))
208
-
209
- // REGISTER REPOSITORIES
210
- services.addScoped('USER_REPOSITORY_TOKEN', (c) => new UserWriteRepository(c.resolve('USER_DS_TOKEN'), c.resolve('USER_MAPPER_TOKEN')))
211
-
212
- // REGISTER HANDLERS
213
- services.addScoped('FIND_USER_QUERY_HANDLER_TOKEN', (c) => {
214
- const requestcontext = c.resolve('USER_CONTEXT_FACTORY')
215
- const repository = c.resolve('USER_READ_REPOSITORY')
216
- return new FindUserQueryHandler(repository, requestcontext)
217
- })
218
-
219
- // REGISTER CONTROLLERS
220
- services.addTransient('FIND_USER_CONTROLLER_TOKEN', (c) => {
221
- return new FindUserController(c.resolve('CONTEXT_ACCESSOR'), c.resolve('MEDIATOR'))
222
- })
223
- })
224
-
225
- \`\`\`
226
-
227
- ### 2. Wrap and Run within Server Middleware (e.g., Fastify / Hono)
228
-
229
- \`\`\`typescript
230
- import 'dotenv/config'
231
- import { ContainerUtils } from '@xeno-js/core'
232
- import fastify from 'fastify'
233
- import { bootstrap } from './bootstrap'
234
-
235
- async function runDemo() {
236
- console.log('⚙️ Initialized Xeno Container...')
237
- try {
238
- // 1. Bootstrap the application and get the service container
239
- const xenoApp = await bootstrap.build()
240
-
241
- console.log('🚀 Starting Fastify server on http://localhost:3000...')
242
-
243
- // 2. Resolve the middleware from the container
244
- const middleware = xeno.resolve('MIDDLEWARE')
245
- // 3. Create a Fastify instance to handle HTTP requests
246
- const app = fastify()
247
-
248
- // ─── ENDPOINT 2: QUERY ────────────────────────────────────────────
249
- app.get('/api/user/:id', async (request, reply) => {
250
- // 4. Execute the middleware to handle the request context and authentication, then call the StatusController's handle method with the request payload.
251
- const responseDto = await middleware.execute(
252
- { path: '/api/user/:id', method: 'GET', transport: { res: reply, req: request } },
253
- { ...request.headers },
254
- async () => {
255
- const { id } = request.params as any
256
- const controller = ContainerUtils.resolveServiceScoped('FIND_USER_CONTROLLER_TOKEN', xenoApp)
257
- return await controller.handle({ id: id ?? '123' });
258
- }
259
- );
260
-
261
- return reply
262
- .status(responseDto.status)
263
- .type('application/json')
264
- .send(responseDto.data)
265
- })
266
-
267
- console.log('✅ Routes set up. Ready to accept requests.')
268
-
269
- // ─── START SERVER ─────────────────────────────────────────────────
270
- try {
271
- await app.listen({ port: 3000 })
272
- console.log('🚀 Application running on http://localhost:3000')
273
- console.log('👉 GET /api/user/:id (GET: api/user/1)')
274
- } catch (err) {
275
- console.error('Error starting Fastify server:', err)
276
- app.log.error(err)
277
- process.exit(1)
278
- }
279
- } catch (error) {
280
- console.error('Error during bootstrap or server setup:', error)
281
- process.exit(1)
282
- }
283
- }
284
-
285
- runDemo()
286
- \`\`\`
287
-
288
- ---
289
-
290
- ## 🛠 Scaffold your project with CLI
291
-
292
- Xeno includes an official CLI tool, \`@xeno-js/cli\`, designed to bootstrap your
293
- new application in seconds. It offers an interactive setup to select exactly the
294
- modules you need (Database, HTTP, Auth, Logging, etc.), ensuring you start with
295
- a clean, pre-configured architecture tailored to your specific requirements.
296
-
297
- If you want to learn how to use it, see the full options available, or
298
- understand how the scaffolding engine works, check the
299
- **[CLI Documentation](https://www.xeno-js.it/cli/overview)**.
300
-
301
- ---
302
-
303
- ## 🤝 For Contributors
304
-
305
- We welcome contributions to Xeno! To maintain the highest code quality and
306
- stability of the core framework, **direct pushes to the \`main\` and \`develop\`
307
- branches are strictly prohibited.** Please follow this Git Flow to contribute:
308
-
309
- 1. **Branch off from \`develop\`**: Create a new branch for your feature or
310
- bugfix.
311
-
312
- \`\`\`bash
313
- git checkout develop
314
- git pull origin develop
315
- git checkout -b feat/your-awesome-feature
316
- \`\`\`
317
-
318
- 2. **Make your changes**: Write your code and ensure it passes all local checks
319
- (linting, types, and tests).
320
-
321
- \`\`\`bash
322
- npm run check
323
- \`\`\`
324
-
325
- 3. **Commit your changes**: We enforce
326
- [Conventional Commits](https://www.conventionalcommits.org/). Husky will
327
- verify your commit message format.
328
-
329
- 4. **Commit Format:**
330
-
331
- \`\`\`bash
332
- feat(scope): add new feature
333
- fix(scope): resolve bug
334
- chore(scope): update dependencies
335
- \`\`\`
336
-
337
- 5. **Submit a Pull Request (PR)**: Push your branch to GitHub and open a Pull
338
- Request targeting the **\`develop\`** branch.
339
-
340
- 6. **Review**: The repository owner will review your code, run pipeline tests,
341
- and merge it into \`develop\`.
342
-
343
- _Note: The \`main\` branch is strictly reserved for production releases. Code
344
- flows from feature branches ➡️ \`develop\` ➡️ \`main\`._
345
-
346
- ### Scripts
347
-
348
- | Command | Description |
349
- | ----------------------- | ---------------------------------------------- |
350
- | \`npm run build\` | Builds the TypeScript source code into \`dist/\` |
351
- | \`npm run typecheck\` | Checks types without emitting files |
352
- | \`npm run lint\` | Runs ESLint |
353
- | \`npm run format\` | Formats code with Prettier |
354
- | \`npm run test\` | Runs the Vitest test suite |
355
- | \`npm run test:coverage\` | Runs tests and generates a coverage report |
356
-
357
- ### Code Quality (Husky & Git Hooks)
358
-
359
- This project strictly enforces code quality rules before pushing to the
360
- repository:
361
-
362
- - **\`pre-commit\`**: Runs \`lint-staged\` on staged files (ESLint + Prettier).
363
- - **\`commit-msg\`**: Checks commit messages with \`commitlint\` (we use
364
- Conventional Commits).
365
- - **\`pre-push\`**: Runs type checking, linting, and testing before code leaves
366
- your machine.
367
-
368
- ---
369
-
370
- ## 🌱 Support & Appreciation
371
-
372
- Building, benchmarking, and maintaining a progressive, enterprise-ready
373
- open-source framework requires a massive amount of continuous dedication and
374
- architectural engineering.
375
-
376
- If Xeno has brought value to your development workflows, helped decouple your
377
- core business logic, or simplified your system infrastructure layout, consider
378
- supporting its open-source lifecycle. Your backing directly accelerates our
379
- strategic roadmap for new out-of-the-box transport integrations (such as gRPC,
380
- RabbitMQ, and GraphQL) and keeps the documentation pristine.
381
-
382
- **Want to know how you can contribute or sponsor Xeno?** We rely on the
383
- commitment of our community to keep the project independent and thriving.
384
- Whether you are an individual developer or a business using Xeno, your support
385
- makes a real difference.
386
-
387
- 👉
388
- **[Read our support guidelines and find out how to help](https://www.xeno-js.it/support-us)**
389
-
390
- Thank you for being part of this decoupled open-source journey!
391
-
392
- <amp-bounce>
393
- </amp-bounce>
394
- <a href="https://www.buymeacoffee.com/xenojs" target="_blank">
395
- <img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="42" style="height: 42px !important;" />
396
- </a>
397
-
398
- ---
399
-
400
- ## 🛡️ Powered by Xeno
401
-
402
- If you are using Xeno in your project, let the world know! Add this badge to
403
- your README:
404
-
405
- \`\`\`html
406
- <a
407
- href="[https://github.com/xeno-js/xeno-js](https://github.com/xeno-js/xeno-js)"
408
- target="_blank"
409
- >
410
- <img
411
- src="[https://img.shields.io/badge/Powered%20by-Xeno-black?style=flat-square](https://img.shields.io/badge/Powered%20by-Xeno-black?style=flat-square)"
412
- alt="Powered by Xeno"
413
- height="20"
414
- />
415
- </a>
416
- \`\`\`
417
-
418
- ## 📄 License
419
-
420
- Copyright (c) 2026 Xeno. Licensed under the [ISC License](LICENSE).
421
-
422
- `
423
-
424
- const filePath = path.join(projectPath, 'readme')
425
- await this._fileService.writeFileRecursive(filePath, content)
426
- }
427
- }
@@ -1,40 +0,0 @@
1
- import path from 'node:path'
2
-
3
- import type { IFileService, IGenerator } from '../../../domain'
4
- import { CORE_CONSTANTS, type CoreOptions } from '../../../shared'
5
-
6
- export class RegistryGenerator implements IGenerator<CoreOptions> {
7
- constructor(private readonly _fileService: IFileService) {}
8
-
9
- public async generate(projectPath: string, options: CoreOptions): Promise<void> {
10
- let dbImport = ''
11
- let registryType = ''
12
- if (options.database !== CORE_CONSTANTS.NONE) {
13
- if (options.database === CORE_CONSTANTS.DRIZZLE) {
14
- dbImport = `import type { DbSchema } from './schema';`
15
- registryType = `XenoRegistry<DbSchema>`
16
- } else if (options.database === CORE_CONSTANTS.SQL_LITE) {
17
- dbImport = `import type { SqliteSchema } from './schema';`
18
- registryType = `XenoRegistry<SqliteSchema>`
19
- }
20
- } else {
21
- registryType = `XenoRegistry`
22
- }
23
-
24
- const content = `import type { XenoRegistry } from '@xeno-js/core';
25
- ${dbImport}
26
-
27
- /**
28
- * @file registry.ts
29
- * @description Centralized Type Contract for Dependency Injection.
30
- */
31
- export interface MyRegistry extends ${registryType} {
32
- // Add your application injection tokens here
33
- // e.g., USER_REPOSITORY: IUserRepository;
34
- }
35
- `
36
-
37
- const filePath = path.join(projectPath, 'src', 'registry.ts')
38
- await this._fileService.writeFileRecursive(filePath, content)
39
- }
40
- }
@@ -1,32 +0,0 @@
1
- import path from 'node:path'
2
-
3
- import type { IFileService, IGenerator } from '../../../domain'
4
- import type { CoreOptions } from '../../../shared'
5
-
6
- export class TsconfigGenerator implements IGenerator<CoreOptions> {
7
- constructor(private readonly _fileService: IFileService) {}
8
-
9
- public async generate(projectPath: string, _options: CoreOptions): Promise<void> {
10
- const tsconfig = {
11
- compilerOptions: {
12
- target: 'ES2022',
13
- module: 'ESNext',
14
- moduleResolution: 'bundler',
15
- strict: true,
16
- esModuleInterop: true,
17
- skipLibCheck: true,
18
- forceConsistentCasingInFileNames: true,
19
- outDir: './dist',
20
- rootDir: './src',
21
- types: ['node'],
22
- paths: {
23
- '@/*': ['./src/*'],
24
- },
25
- },
26
- include: ['src/**/*.ts'],
27
- }
28
-
29
- const filePath = path.join(projectPath, 'tsconfig.json')
30
- await this._fileService.writeFileRecursive(filePath, JSON.stringify(tsconfig, null, 2))
31
- }
32
- }
@@ -1,60 +0,0 @@
1
- import path from 'node:path'
2
-
3
- import type { IFileService, IGenerator } from '../../domain'
4
- import type { CoreOptions, ScaffoldingOptions } from '../../shared'
5
- import { CORE_CONSTANTS } from '../../shared'
6
-
7
- export class GitIgnoreGenerator implements IGenerator<ScaffoldingOptions> {
8
- constructor(private readonly _fileService: IFileService) {}
9
-
10
- public async generate(projectPath: string, options: ScaffoldingOptions): Promise<void> {
11
- let content = `# Dependencies
12
- node_modules/
13
-
14
- # Build artifacts
15
- dist/
16
- out/
17
- build/
18
-
19
- # Environment variables
20
- # We ignore actual .env files for security, but keep .env.example for documentation
21
- .env
22
- .env.local
23
- .env.*
24
- !.env.example
25
-
26
- # Logs
27
- *.log
28
- logs/
29
- npm-debug.log*
30
-
31
- # Test coverage
32
- coverage/
33
- .nyc_output/
34
-
35
- # OS and IDE
36
- .DS_Store
37
- Thumbs.db
38
- .vscode/
39
- .idea/
40
- `
41
-
42
- if ((options as CoreOptions).database === CORE_CONSTANTS.SQL_LITE) {
43
- content += `\n# SQLite Database
44
- *.sqlite
45
- *.sqlite3
46
- *.sqlite-journal
47
- `
48
- }
49
-
50
- // Ignora la cartella di compilazione locale di Vercel se l'ambiente lo richiede
51
- if ((options as CoreOptions).targetEnv === CORE_CONSTANTS.VERCEL) {
52
- content += `\n# Vercel
53
- .vercel/
54
- `
55
- }
56
-
57
- const filePath = path.join(projectPath, '.gitignore')
58
- await this._fileService.writeFileRecursive(filePath, content)
59
- }
60
- }
@@ -1,21 +0,0 @@
1
- import path from 'node:path'
2
-
3
- import { type IFileService, type IGenerator } from '../../../domain'
4
- import type { VueOptions } from '../../../shared'
5
-
6
- export class AppVueGenerator implements IGenerator<VueOptions> {
7
- constructor(private readonly _fileService: IFileService) {}
8
-
9
- public async generate(projectPath: string, options: VueOptions): Promise<void> {
10
- // 2. src/App.vue
11
- const appVue = `<script setup lang="ts">
12
- </script>
13
-
14
- <template>
15
- <div id="xeno-app">
16
- ${options.router ? '<router-view />' : '<h1>Welcome to Xeno Vue App</h1>'}
17
- </div>
18
- </template>`
19
- await this._fileService.writeFileRecursive(path.join(projectPath, 'src', 'App.vue'), appVue)
20
- }
21
- }
@@ -1,60 +0,0 @@
1
- import path from 'node:path'
2
-
3
- import { type IFileService, type IGenerator } from '../../../domain'
4
- import type { VueOptions } from '../../../shared'
5
-
6
- export class BootstrapGenerator implements IGenerator<VueOptions> {
7
- constructor(private readonly _fileService: IFileService) {}
8
-
9
- public async generate(projectPath: string, options: VueOptions): Promise<void> {
10
- // 4. src/bootstrap.ts
11
- let builderNodes = ` const builder = XenoAppBuilder.create<MyRegistry>()\n .addContext(() => {})`
12
-
13
- if (options.supabase) {
14
- builderNodes += `\n .addAuth((opts, config) => {
15
- opts.url = config.getOrThrow('VITE_SUPABASE_URL');
16
- opts.key = config.getOrThrow('VITE_SUPABASE_KEY');
17
- })`
18
- }
19
-
20
- if (options.sentry) {
21
- builderNodes += `\n .addLogger((opts, config) => {
22
- const env = config.get('APP_ENV') ?? 'development'
23
- const isDev = env.toLowerCase() === 'development'
24
- opts.console = isDev
25
- if (!isDev) {
26
- opts.sentry = {
27
- dsn: config.getOrThrow('VITE_SENTRY_DSN'),
28
- env,
29
- app,
30
- router,
31
- tracesSampleRate: 0.2,
32
- level: LOG_LEVEL.WARN,
33
- };
34
- }
35
- })`
36
- } else {
37
- builderNodes += `\n .addLogger((opts, config) => {
38
- opts.console = config.get('VITE_APP_ENV') === 'development';
39
- })`
40
- }
41
-
42
- builderNodes += `\n .addServices((config, register) => {
43
- // Register custom stores, API clients, and CQRS services here
44
- })`
45
-
46
- const bootstrapTs = `import { XenoAppBuilder, LOG_LEVEL } from '@xeno-js/vue';
47
- import type { MyRegistry } from './registry';
48
-
49
- export async function bootstrap(app: any, router: any) {
50
- ${builderNodes}
51
-
52
- return await builder.build();
53
- }
54
- `
55
- await this._fileService.writeFileRecursive(
56
- path.join(projectPath, 'src', 'bootstrap.ts'),
57
- bootstrapTs,
58
- )
59
- }
60
- }
@@ -1,36 +0,0 @@
1
- import path from 'node:path'
2
-
3
- import type { IFileService } from '../../../../domain'
4
- import { COMMAND_CONSTANTS, StringUtils } from '../../../../shared'
5
-
6
- export class CqrsVueGenerator {
7
- constructor(private readonly _fileService: IFileService) {}
8
-
9
- public async generate(
10
- targetDir: string,
11
- name: string,
12
- type: 'command' | 'query',
13
- outputPath?: string,
14
- ): Promise<void> {
15
- const pascalName = StringUtils.pascalCase(name)
16
- const tokenPrefix = StringUtils.splitCamelCaseWithUnderscore(pascalName).toUpperCase()
17
- const lowerName = name.toLowerCase()
18
- const destinationFolder = outputPath ?? lowerName
19
- const componentDir = path.join(targetDir, 'src', destinationFolder)
20
-
21
- switch (type) {
22
- case COMMAND_CONSTANTS.COMMAND: {
23
- const { GenerateCommandVueGenerator } = await import('./generate-command-vue.generator.js')
24
- const generator = new GenerateCommandVueGenerator(this._fileService)
25
- return generator.generate(pascalName, lowerName, tokenPrefix, componentDir)
26
- }
27
- case COMMAND_CONSTANTS.QUERY: {
28
- const { GenerateQueryVueGenerator } = await import('./generate-query-vue.generator.js')
29
- const generatorQuery = new GenerateQueryVueGenerator(this._fileService)
30
- return generatorQuery.generate(pascalName, lowerName, tokenPrefix, componentDir)
31
- }
32
- default:
33
- throw new Error(`Unsupported generator type: '${String(type)}'. Use 'command' or 'query'.`)
34
- }
35
- }
36
- }