@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.
- package/LICENSE +18 -12
- package/README.md +461 -236
- package/dist/index.js +985 -653
- package/dist/index.js.map +1 -1
- package/package.json +91 -66
- package/.github/.copilot-instruction.md +0 -73
- package/.github/agents/git-operator.agent.md +0 -86
- package/.github/agents/unit-tester.agent.md +0 -68
- package/.husky/commit-msg +0 -1
- package/.husky/pre-commit +0 -1
- package/.husky/pre-push +0 -1
- package/.prettierignore +0 -7
- package/.prettierrc.json +0 -37
- package/commitlint.config.cjs +0 -39
- package/eslint.config.mjs +0 -306
- package/lint-staged.config.mjs +0 -5
- package/logo/logo.png +0 -0
- package/src/domain/contracts/icommand-cli.contracts.ts +0 -13
- package/src/domain/contracts/icommand-runner.contracts.ts +0 -3
- package/src/domain/contracts/idispatch.contracts.ts +0 -3
- package/src/domain/contracts/ifile-service.contracts.ts +0 -3
- package/src/domain/contracts/igenerator.contracts.ts +0 -5
- package/src/domain/contracts/index.ts +0 -6
- package/src/domain/contracts/iscaffold-strategy.contracts.ts +0 -7
- package/src/domain/index.ts +0 -1
- package/src/index.ts +0 -30
- package/src/infrastructure/bootstrap/bootstrapper.ts +0 -30
- package/src/infrastructure/bootstrap/index.ts +0 -1
- package/src/infrastructure/builder/builder.test.ts +0 -36
- package/src/infrastructure/builder/builder.ts +0 -15
- package/src/infrastructure/builder/index.ts +0 -1
- package/src/infrastructure/command_launcher/command.utils.ts +0 -31
- package/src/infrastructure/command_launcher/index.ts +0 -0
- package/src/infrastructure/commands/command-runner.service.ts +0 -36
- package/src/infrastructure/commands/generate.command.ts +0 -55
- package/src/infrastructure/commands/help.command.ts +0 -63
- package/src/infrastructure/commands/index.ts +0 -4
- package/src/infrastructure/commands/new-project.command.ts +0 -47
- package/src/infrastructure/dispatcher/dispatcher.ts +0 -45
- package/src/infrastructure/dispatcher/index.ts +0 -1
- package/src/infrastructure/file/file.service.ts +0 -14
- package/src/infrastructure/file/index.ts +0 -1
- package/src/infrastructure/generators/core/bootstrap.generator.ts +0 -118
- package/src/infrastructure/generators/core/command/cqrs.generator.ts +0 -63
- package/src/infrastructure/generators/core/command/generate-command.generator.ts +0 -191
- package/src/infrastructure/generators/core/command/generate-query.generator.ts +0 -150
- package/src/infrastructure/generators/core/drizzle-sql-lite.generator.ts +0 -77
- package/src/infrastructure/generators/core/drizzle.generator.ts +0 -87
- package/src/infrastructure/generators/core/env.generator.ts +0 -69
- package/src/infrastructure/generators/core/index.ts +0 -9
- package/src/infrastructure/generators/core/main.generator.ts +0 -41
- package/src/infrastructure/generators/core/packagejson.generator.ts +0 -70
- package/src/infrastructure/generators/core/readme.generator.ts +0 -427
- package/src/infrastructure/generators/core/registry.generator.ts +0 -40
- package/src/infrastructure/generators/core/tsconfig.generator.ts +0 -32
- package/src/infrastructure/generators/gitignore.generator.ts +0 -60
- package/src/infrastructure/generators/vue/app-vue.generator.ts +0 -21
- package/src/infrastructure/generators/vue/bootstrap-ts.generator.ts +0 -60
- package/src/infrastructure/generators/vue/command_query/cqrs.generator.ts +0 -36
- package/src/infrastructure/generators/vue/command_query/generate-command-vue.generator.ts +0 -153
- package/src/infrastructure/generators/vue/command_query/generate-query-vue.generator.ts +0 -161
- package/src/infrastructure/generators/vue/env.generator.ts +0 -39
- package/src/infrastructure/generators/vue/index-html.generator.ts +0 -24
- package/src/infrastructure/generators/vue/index.ts +0 -12
- package/src/infrastructure/generators/vue/main.generator.ts +0 -41
- package/src/infrastructure/generators/vue/packagejson.generator.ts +0 -50
- package/src/infrastructure/generators/vue/readme.generator.ts +0 -389
- package/src/infrastructure/generators/vue/registry-ts.generator.ts +0 -26
- package/src/infrastructure/generators/vue/router.generator.ts +0 -35
- package/src/infrastructure/generators/vue/tailwind.generator.ts +0 -17
- package/src/infrastructure/generators/vue/tsconfig.generator.ts +0 -38
- package/src/infrastructure/generators/vue/use-app.generator.ts +0 -38
- package/src/infrastructure/generators/vue/vite-config.generator.ts +0 -35
- package/src/infrastructure/index.ts +0 -5
- package/src/infrastructure/strategies/core-scaffold.strategy.ts +0 -100
- package/src/infrastructure/strategies/index.ts +0 -2
- package/src/infrastructure/strategies/vue-scaffold.strategy.ts +0 -79
- package/src/shared/constants/command.constants.ts +0 -18
- package/src/shared/constants/core.constants.ts +0 -7
- package/src/shared/constants/index.ts +0 -2
- package/src/shared/index.ts +0 -3
- package/src/shared/types/common.types.ts +0 -68
- package/src/shared/types/index.ts +0 -1
- package/src/shared/utils/guards.utils.ts +0 -334
- package/src/shared/utils/index.ts +0 -2
- package/src/shared/utils/string.utils.ts +0 -60
- package/tsconfig.json +0 -15
- package/tsup.config.ts +0 -13
|
@@ -1,389 +0,0 @@
|
|
|
1
|
-
// src/infrastructure/generators/vue-readme.generator.ts
|
|
2
|
-
import path from 'node:path'
|
|
3
|
-
|
|
4
|
-
import { type IFileService, type IGenerator } from '../../../domain'
|
|
5
|
-
import type { VueOptions } from '../../../shared'
|
|
6
|
-
|
|
7
|
-
export class ReadmeVueGenerator implements IGenerator<VueOptions> {
|
|
8
|
-
constructor(private readonly _fileService: IFileService) {}
|
|
9
|
-
|
|
10
|
-
public async generate(projectPath: string, options: VueOptions): Promise<void> {
|
|
11
|
-
const content = `# ${options.targetDir}
|
|
12
|
-
|
|
13
|
-
<div align="center">
|
|
14
|
-
<img src="logo/logo.png" alt="Xeno Logo" width="140" />
|
|
15
|
-
|
|
16
|
-
<h1>Xeno Vue</h1>
|
|
17
|
-
|
|
18
|
-
<p><em>Enterprise-grade DDD & CQRS framework for Vue.js</em></p>
|
|
19
|
-
|
|
20
|
-
<p>
|
|
21
|
-
<a href="https://github.com/xeno-js/xeno-js">
|
|
22
|
-
<img src="https://img.shields.io/badge/Powered%20by-Xeno-blueviolet?style=flat-square" alt="Powered by Xeno" />
|
|
23
|
-
</a>
|
|
24
|
-
<a href="https://github.com/xeno-js/xeno-fe/blob/main/LICENSE">
|
|
25
|
-
<img src="https://img.shields.io/npm/l/@xeno-js/vue?style=flat-square" alt="License: ISC" />
|
|
26
|
-
</a>
|
|
27
|
-
<a href="https://www.npmjs.com/package/@xeno-js/vue">
|
|
28
|
-
<img src="https://img.shields.io/npm/v/@xeno-js/vue?style=flat-square" alt="NPM Version" />
|
|
29
|
-
</a>
|
|
30
|
-
<a href="https://buymeacoffee.com/xenojs">
|
|
31
|
-
<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" />
|
|
32
|
-
</a>
|
|
33
|
-
</p>
|
|
34
|
-
</div>
|
|
35
|
-
|
|
36
|
-
---
|
|
37
|
-
|
|
38
|
-
## What is Xeno Vue?
|
|
39
|
-
|
|
40
|
-
**Xeno Vue** (\`@xeno-js/vue\`) is an enterprise-grade, deterministic
|
|
41
|
-
architectural framework that brings the strictness of **Domain-Driven Design
|
|
42
|
-
(DDD)** and **Command Query Responsibility Segregation (CQRS)** natively to the
|
|
43
|
-
browser.
|
|
44
|
-
|
|
45
|
-
By shifting operational logic, remote data fetching, and state mutations away
|
|
46
|
-
from Vue components and Pinia stores, Xeno ensures your frontend architecture
|
|
47
|
-
remains pristine, highly testable, and completely decoupled from the UI layer.
|
|
48
|
-
It treats the browser as a complex distributed client, not just a document
|
|
49
|
-
viewer.
|
|
50
|
-
|
|
51
|
-
---
|
|
52
|
-
|
|
53
|
-
## 💡 Why Choose Xeno Vue?
|
|
54
|
-
|
|
55
|
-
Modern frontend development often leads to "Spaghetti State" where API calls,
|
|
56
|
-
business rules, and DOM manipulations are tightly coupled inside components.
|
|
57
|
-
Xeno Vue fixes this with an emphasis on pure Dependency Injection (DI) and clean
|
|
58
|
-
boundaries.
|
|
59
|
-
|
|
60
|
-
- **Zero-Magic Dependency Injection**: Xeno provides an explicit
|
|
61
|
-
\`XenoAppBuilder\` to construct your IoC container at bootstrap. No hidden Vue
|
|
62
|
-
plugins doing implicit injections. You have total control over the dependency
|
|
63
|
-
graph.
|
|
64
|
-
- **Total UI Decoupling**: Vue components act strictly as the Presentation
|
|
65
|
-
Layer. Business logic, API calls, and CQRS handlers live in pure, isolated
|
|
66
|
-
TypeScript classes. You can swap Vue for React tomorrow without touching your
|
|
67
|
-
core domain.
|
|
68
|
-
- **Enterprise-Grade Client Resiliency**: The browser is a hostile, unreliable
|
|
69
|
-
environment. Xeno Vue natively integrates \`Cockatiel\` and \`Axios\` to provide
|
|
70
|
-
out-of-the-box circuit breakers, retries with jitter, and bulkheads directly
|
|
71
|
-
in the client.
|
|
72
|
-
- **Frontend Middleware Pipeline**: Handle Authentication, CSRF validation,
|
|
73
|
-
aggressive Query Caching, and Performance logging _before_ a command is
|
|
74
|
-
executed or an API call fires, using the native \`Mediator\` pipeline.
|
|
75
|
-
|
|
76
|
-
---
|
|
77
|
-
|
|
78
|
-
## 📖 Documentation & Getting Started
|
|
79
|
-
|
|
80
|
-
To explore the architecture, programmatic configurations, and extension
|
|
81
|
-
workflows of Xeno Vue, read the full technical manuals located inside the main
|
|
82
|
-
documentation hub:
|
|
83
|
-
|
|
84
|
-
- **[Framework Documentation Repository](https://www.xeno-js.it/vue/overview)**
|
|
85
|
-
|
|
86
|
-
Inside, you will find exhaustive, step-by-step assembly guides covering frontend
|
|
87
|
-
IoC building (\`XenoAppBuilder\`), Vue \`Provide/Inject\` boundaries, and CQRS
|
|
88
|
-
composables.
|
|
89
|
-
|
|
90
|
-
---
|
|
91
|
-
|
|
92
|
-
## 🚀 Live Executable Demos
|
|
93
|
-
|
|
94
|
-
Want to see how Xeno Vue works? Check out the functional example application
|
|
95
|
-
showcasing end-to-end command/query segregation, resilient HTTP fetching, and
|
|
96
|
-
pure Composition API integration.
|
|
97
|
-
|
|
98
|
-
- **[Xeno Vue Demo Architecture](https://www.xeno-js.it/demo)**
|
|
99
|
-
|
|
100
|
-
---
|
|
101
|
-
|
|
102
|
-
## 📦 Installation
|
|
103
|
-
|
|
104
|
-
Install the Vue package:
|
|
105
|
-
|
|
106
|
-
\`\`\`bash
|
|
107
|
-
npm install @xeno-js/vue
|
|
108
|
-
|
|
109
|
-
\`\`\`
|
|
110
|
-
|
|
111
|
-
Xeno uses **Optional Peer Dependencies**. You only install the external
|
|
112
|
-
libraries you actually need.
|
|
113
|
-
|
|
114
|
-
\`\`\`bash
|
|
115
|
-
# Example: Install tools only if you enable them in the builder
|
|
116
|
-
npm install axios cockatiel zod @supabase/supabase-js @sentry/vue
|
|
117
|
-
|
|
118
|
-
\`\`\`
|
|
119
|
-
|
|
120
|
-
---
|
|
121
|
-
|
|
122
|
-
## ⚡ Bootstrapping & Component Example
|
|
123
|
-
|
|
124
|
-
Below is an architectural example of how to configure the Xeno \`XenoAppBuilder\`,
|
|
125
|
-
inject it into the Vue application, and consume it using Composition API
|
|
126
|
-
Composables.
|
|
127
|
-
|
|
128
|
-
### 1. Initialize the Container (\`src/bootstrap.ts\`)
|
|
129
|
-
|
|
130
|
-
\`\`\`typescript
|
|
131
|
-
import { XenoAppBuilder, LOG_LEVEL, TOKENS } from '@xeno-js/vue'
|
|
132
|
-
import { BffRemoteDataSource } from './infrastructure'
|
|
133
|
-
|
|
134
|
-
import type { RemoteDataSource, XenoVueRegistry } from '@xeno-js/vue'
|
|
135
|
-
|
|
136
|
-
export type MyRegistry = XenoVueRegistry<{
|
|
137
|
-
BFF_REMOTE_DS: RemoteDataSource
|
|
138
|
-
}>
|
|
139
|
-
|
|
140
|
-
// Create the root IoC container context for the browser
|
|
141
|
-
const builder = XenoAppBuilder.create<MyRegistry>()
|
|
142
|
-
.addContext((opts) => {
|
|
143
|
-
opts.contextAccessor = useContextStore()
|
|
144
|
-
})
|
|
145
|
-
.addLogger((opts, config) => {
|
|
146
|
-
opts.console = config.get('VITE_APP_ENV') === 'development'
|
|
147
|
-
opts.level = LOG_LEVEL.DEBUG
|
|
148
|
-
})
|
|
149
|
-
.addAuth((opts, config) => {
|
|
150
|
-
opts.url = config.getOrThrow('VITE_SUPABASE_URL')
|
|
151
|
-
opts.key = config.getOrThrow('VITE_SUPABASE_KEY')
|
|
152
|
-
})
|
|
153
|
-
.addHttpCore('BFF_REMOTE_DS', (opts, config) => {
|
|
154
|
-
opts.client = {
|
|
155
|
-
baseURL: config.getOrThrow('VITE_API_BASE_URL'),
|
|
156
|
-
timeoutMs: 10000,
|
|
157
|
-
}
|
|
158
|
-
opts.resilience.retry.attempts = 3
|
|
159
|
-
opts.factory = (http, resilience) =>
|
|
160
|
-
new BffRemoteDataSource(http, resilience)
|
|
161
|
-
})
|
|
162
|
-
.addPipeline((config) => {
|
|
163
|
-
config.queryCaching = true // Enable in-memory caching for Queries
|
|
164
|
-
})
|
|
165
|
-
|
|
166
|
-
export async function bootstrap() {
|
|
167
|
-
return await builder.build()
|
|
168
|
-
}
|
|
169
|
-
\`\`\`
|
|
170
|
-
|
|
171
|
-
### 2. Inject into Vue (\`src/main.ts\`)
|
|
172
|
-
|
|
173
|
-
\`\`\`typescript
|
|
174
|
-
import { createApp } from 'vue'
|
|
175
|
-
import App from './App.vue'
|
|
176
|
-
import { bootstrap } from './bootstrap'
|
|
177
|
-
import { XENO_SERVICES_KEY, ServicesUtils } from '@xeno-js/vue'
|
|
178
|
-
|
|
179
|
-
async function mountApp() {
|
|
180
|
-
try {
|
|
181
|
-
const app = createApp(App)
|
|
182
|
-
const container = await bootstrap()
|
|
183
|
-
|
|
184
|
-
// Provide the Xeno IoC container globally to all components
|
|
185
|
-
app.provide(XENO_SERVICES_KEY, container)
|
|
186
|
-
|
|
187
|
-
// Register global services utility for composables
|
|
188
|
-
ServicesUtils.setGlobalServices(container)
|
|
189
|
-
|
|
190
|
-
app.mount('#app')
|
|
191
|
-
} catch (error) {
|
|
192
|
-
console.error('Critical error during frontend bootstrap:', error)
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
mountApp()
|
|
197
|
-
\`\`\`
|
|
198
|
-
|
|
199
|
-
### 3. CQRS Composable Usage (\`src/features/users/use-create-user.ts\`)
|
|
200
|
-
|
|
201
|
-
\`\`\`typescript
|
|
202
|
-
import { ref } from 'vue'
|
|
203
|
-
import { Result } from '@xeno-js/shared'
|
|
204
|
-
import { ServicesUtils } from '@/use-app'
|
|
205
|
-
import { CreateUserCommand } from './create-user.command'
|
|
206
|
-
|
|
207
|
-
export function useCreateUser() {
|
|
208
|
-
const loading = ref(false)
|
|
209
|
-
const error = ref<string | null>(null)
|
|
210
|
-
|
|
211
|
-
const execute = async (payload: { email: string; name: string }) => {
|
|
212
|
-
if (loading.value) return Result.fail(new Error('Already executing'))
|
|
213
|
-
loading.value = true
|
|
214
|
-
error.value = null
|
|
215
|
-
|
|
216
|
-
try {
|
|
217
|
-
// Safely resolve the Mediator from the Xeno Container
|
|
218
|
-
const { mediator, BFF_REMOTE_DS } = ServicesUtils.useApp()
|
|
219
|
-
const command = new CreateUserCommand()
|
|
220
|
-
|
|
221
|
-
const result = await mediator.send(command, async () => {
|
|
222
|
-
const apiResult = await bffRemoteDs.post('/v1/users', payload)
|
|
223
|
-
|
|
224
|
-
if (!apiResult.isOk()) return Result.fail(apiResult.getErrorOrThrow())
|
|
225
|
-
return Result.ok(apiResult.getValueOrThrow())
|
|
226
|
-
})
|
|
227
|
-
|
|
228
|
-
if (!result.isOk()) {
|
|
229
|
-
error.value = result.getErrorOrThrow().message
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return result
|
|
233
|
-
} finally {
|
|
234
|
-
loading.value = false
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
return { loading, error, execute }
|
|
239
|
-
}
|
|
240
|
-
\`\`\`
|
|
241
|
-
|
|
242
|
-
---
|
|
243
|
-
|
|
244
|
-
## 🛠 Scaffold your project with CLI
|
|
245
|
-
|
|
246
|
-
Xeno includes an official CLI tool, \`@xeno-js/cli\`, designed to bootstrap your
|
|
247
|
-
new application in seconds. It offers an interactive setup for Vue projects,
|
|
248
|
-
instantly scaffolding the CQRS files, composables, and dependency injection
|
|
249
|
-
boundaries.
|
|
250
|
-
|
|
251
|
-
\`\`\`bash
|
|
252
|
-
# Generate a new Vue project
|
|
253
|
-
npx @xeno-js/cli new my-frontend-app --vue
|
|
254
|
-
|
|
255
|
-
# Generate a Vue Command with its Composable
|
|
256
|
-
npx @xeno-js/cli g command CreateUser --vue
|
|
257
|
-
|
|
258
|
-
\`\`\`
|
|
259
|
-
|
|
260
|
-
Check the
|
|
261
|
-
**[CLI Documentation](https://www.google.com/search?q=https://www.xeno-js.it/cli/overview&utm_source=gemini)**
|
|
262
|
-
for full options.
|
|
263
|
-
|
|
264
|
-
---
|
|
265
|
-
|
|
266
|
-
## 🤝 For Contributors
|
|
267
|
-
|
|
268
|
-
We welcome contributions to Xeno! To maintain the highest code quality and
|
|
269
|
-
stability of the core framework, **direct pushes to the \`main\` and \`develop\`
|
|
270
|
-
branches are strictly prohibited.** Please follow this Git Flow to contribute:
|
|
271
|
-
|
|
272
|
-
1. **Branch off from \`develop**\`: Create a new branch for your feature or
|
|
273
|
-
bugfix.
|
|
274
|
-
|
|
275
|
-
\`\`\`bash
|
|
276
|
-
git checkout develop
|
|
277
|
-
git pull origin develop
|
|
278
|
-
git checkout -b feat/your-awesome-feature
|
|
279
|
-
|
|
280
|
-
\`\`\`
|
|
281
|
-
|
|
282
|
-
2. **Make your changes**: Write your code and ensure it passes all local checks
|
|
283
|
-
(linting, types, and tests).
|
|
284
|
-
|
|
285
|
-
\`\`\`bash
|
|
286
|
-
npm run check
|
|
287
|
-
|
|
288
|
-
\`\`\`
|
|
289
|
-
|
|
290
|
-
3. **Commit your changes**: We enforce
|
|
291
|
-
[Conventional Commits](https://www.conventionalcommits.org/?utm_source=gemini).
|
|
292
|
-
Husky will verify your commit message format.
|
|
293
|
-
4. **Commit Format:**
|
|
294
|
-
|
|
295
|
-
\`\`\`bash
|
|
296
|
-
feat(scope): add new feature
|
|
297
|
-
fix(scope): resolve bug
|
|
298
|
-
chore(scope): update dependencies
|
|
299
|
-
|
|
300
|
-
\`\`\`
|
|
301
|
-
|
|
302
|
-
5. **Submit a Pull Request (PR)**: Push your branch to GitHub and open a Pull
|
|
303
|
-
Request targeting the **\`develop\`** branch.
|
|
304
|
-
6. **Review**: The repository owner will review your code, run pipeline tests,
|
|
305
|
-
and merge it into \`develop\`.
|
|
306
|
-
|
|
307
|
-
_Note: The \`main\` branch is strictly reserved for production releases. Code
|
|
308
|
-
flows from feature branches ➡️ \`develop\` ➡️ \`main\`._
|
|
309
|
-
|
|
310
|
-
### Scripts
|
|
311
|
-
|
|
312
|
-
| Command | Description |
|
|
313
|
-
| ----------------------- | ---------------------------------------------- |
|
|
314
|
-
| \`npm run build\` | Builds the TypeScript source code into \`dist/\` |
|
|
315
|
-
| \`npm run typecheck\` | Checks types without emitting files |
|
|
316
|
-
| \`npm run lint\` | Runs ESLint |
|
|
317
|
-
| \`npm run format\` | Formats code with Prettier |
|
|
318
|
-
| \`npm run test\` | Runs the Vitest test suite |
|
|
319
|
-
| \`npm run test:coverage\` | Runs tests and generates a coverage report |
|
|
320
|
-
|
|
321
|
-
### Code Quality (Husky & Git Hooks)
|
|
322
|
-
|
|
323
|
-
This project strictly enforces code quality rules before pushing to the
|
|
324
|
-
repository:
|
|
325
|
-
|
|
326
|
-
- **\`pre-commit\`**: Runs \`lint-staged\` on staged files (ESLint + Prettier).
|
|
327
|
-
- **\`commit-msg\`**: Checks commit messages with \`commitlint\` (we use
|
|
328
|
-
Conventional Commits).
|
|
329
|
-
- **\`pre-push\`**: Runs type checking, linting, and testing before code leaves
|
|
330
|
-
your machine.
|
|
331
|
-
|
|
332
|
-
---
|
|
333
|
-
|
|
334
|
-
## 🌱 Support & Appreciation
|
|
335
|
-
|
|
336
|
-
Building, benchmarking, and maintaining a progressive, enterprise-ready
|
|
337
|
-
open-source framework requires a massive amount of continuous dedication and
|
|
338
|
-
architectural engineering.
|
|
339
|
-
|
|
340
|
-
If Xeno has brought value to your development workflows, helped decouple your
|
|
341
|
-
core business logic, or simplified your system infrastructure layout, consider
|
|
342
|
-
supporting its open-source lifecycle. Your backing directly accelerates our
|
|
343
|
-
strategic roadmap for new out-of-the-box transport integrations and keeps the
|
|
344
|
-
documentation pristine.
|
|
345
|
-
|
|
346
|
-
**Want to know how you can contribute or sponsor Xeno?** We rely on the
|
|
347
|
-
commitment of our community to keep the project independent and thriving.
|
|
348
|
-
Whether you are an individual developer or a business using Xeno, your support
|
|
349
|
-
makes a real difference.
|
|
350
|
-
|
|
351
|
-
👉
|
|
352
|
-
**[Read our support guidelines and find out how to help](https://www.xeno-js.it/support-us)**
|
|
353
|
-
|
|
354
|
-
Thank you for being part of this decoupled open-source journey!
|
|
355
|
-
|
|
356
|
-
<amp-bounce>
|
|
357
|
-
</amp-bounce>
|
|
358
|
-
<a href="https://www.buymeacoffee.com/xenojs" target="_blank">
|
|
359
|
-
<img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="42" style="height: 42px !important;" />
|
|
360
|
-
</a>
|
|
361
|
-
|
|
362
|
-
---
|
|
363
|
-
|
|
364
|
-
## 🛡️ Powered by Xeno
|
|
365
|
-
|
|
366
|
-
If you are using Xeno in your project, let the world know! Add this badge to
|
|
367
|
-
your README:
|
|
368
|
-
|
|
369
|
-
\`\`\`html
|
|
370
|
-
<a
|
|
371
|
-
href="[https://github.com/xeno-js/xeno-fe](https://github.com/xeno-js/xeno-fe)"
|
|
372
|
-
target="_blank"
|
|
373
|
-
>
|
|
374
|
-
<img
|
|
375
|
-
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)"
|
|
376
|
-
alt="Powered by Xeno"
|
|
377
|
-
height="20"
|
|
378
|
-
/>
|
|
379
|
-
</a>
|
|
380
|
-
\`\`\`
|
|
381
|
-
|
|
382
|
-
## 📄 License
|
|
383
|
-
|
|
384
|
-
Copyright (c) 2026 Xeno. Licensed under the
|
|
385
|
-
[ISC License](https://www.google.com/search?q=LICENSE&utm_source=gemini).
|
|
386
|
-
`
|
|
387
|
-
await this._fileService.writeFileRecursive(path.join(projectPath, 'README.md'), content)
|
|
388
|
-
}
|
|
389
|
-
}
|
|
@@ -1,26 +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 RegistryGenerator implements IGenerator<VueOptions> {
|
|
7
|
-
constructor(private readonly _fileService: IFileService) {}
|
|
8
|
-
|
|
9
|
-
public async generate(projectPath: string, _options: VueOptions): Promise<void> {
|
|
10
|
-
const registryTs = `import type { XenoVueRegistry } from '@xeno-js/vue';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* @file registry.ts
|
|
14
|
-
* @description Centralized Type Contract for Dependency Injection in Vue.
|
|
15
|
-
*/
|
|
16
|
-
export interface MyRegistry extends XenoVueRegistry {
|
|
17
|
-
// Add your frontend injection tokens here
|
|
18
|
-
// e.g., USER_DATA_SOURCE: IUserDataSource;
|
|
19
|
-
}
|
|
20
|
-
`
|
|
21
|
-
await this._fileService.writeFileRecursive(
|
|
22
|
-
path.join(projectPath, 'src', 'registry.ts'),
|
|
23
|
-
registryTs,
|
|
24
|
-
)
|
|
25
|
-
}
|
|
26
|
-
}
|
|
@@ -1,35 +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 RouterGenerator implements IGenerator<VueOptions> {
|
|
7
|
-
constructor(private readonly _fileService: IFileService) {}
|
|
8
|
-
|
|
9
|
-
public async generate(projectPath: string, options: VueOptions): Promise<void> {
|
|
10
|
-
// 6. Optional router and assets
|
|
11
|
-
if (options.router) {
|
|
12
|
-
const routerTs = `import { createRouter, createWebHistory } from 'vue-router';
|
|
13
|
-
|
|
14
|
-
export default createRouter({
|
|
15
|
-
history: createWebHistory(),
|
|
16
|
-
routes: [
|
|
17
|
-
{
|
|
18
|
-
path: '/',
|
|
19
|
-
name: 'Home',
|
|
20
|
-
component: () => import('../views/HomeView.vue')
|
|
21
|
-
}
|
|
22
|
-
]
|
|
23
|
-
});`
|
|
24
|
-
await this._fileService.writeFileRecursive(
|
|
25
|
-
path.join(projectPath, 'src', 'router', 'index.ts'),
|
|
26
|
-
routerTs,
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
await this._fileService.writeFileRecursive(
|
|
30
|
-
path.join(projectPath, 'src', 'views', 'HomeView.vue'),
|
|
31
|
-
`<template>\n <h1>Home View</h1>\n</template>`,
|
|
32
|
-
)
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
@@ -1,17 +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 TailwindGenerator implements IGenerator<VueOptions> {
|
|
7
|
-
constructor(private readonly _fileService: IFileService) {}
|
|
8
|
-
|
|
9
|
-
public async generate(projectPath: string, options: VueOptions): Promise<void> {
|
|
10
|
-
if (options.tailwind) {
|
|
11
|
-
await this._fileService.writeFileRecursive(
|
|
12
|
-
path.join(projectPath, 'src', 'assets', 'style.css'),
|
|
13
|
-
`@import "tailwindcss";\n`,
|
|
14
|
-
)
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
// src/infrastructure/generators/tsconfig-vue.generator.ts
|
|
2
|
-
import path from 'node:path'
|
|
3
|
-
|
|
4
|
-
import { type IFileService, type IGenerator } from '../../../domain'
|
|
5
|
-
import type { VueOptions } from '../../../shared'
|
|
6
|
-
|
|
7
|
-
export class TsconfigVueGenerator implements IGenerator<VueOptions> {
|
|
8
|
-
constructor(private readonly _fileService: IFileService) {}
|
|
9
|
-
|
|
10
|
-
public async generate(projectPath: string, _options: VueOptions): Promise<void> {
|
|
11
|
-
const tsconfig = {
|
|
12
|
-
compilerOptions: {
|
|
13
|
-
target: 'ES2022',
|
|
14
|
-
useDefineForClassFields: true,
|
|
15
|
-
module: 'ESNext',
|
|
16
|
-
moduleResolution: 'bundler',
|
|
17
|
-
strict: true,
|
|
18
|
-
jsx: 'preserve',
|
|
19
|
-
resolveJsonModule: true,
|
|
20
|
-
isolatedModules: true,
|
|
21
|
-
esModuleInterop: true,
|
|
22
|
-
lib: ['ES2022', 'DOM', 'DOM.Iterable'],
|
|
23
|
-
skipLibCheck: true,
|
|
24
|
-
noEmit: true,
|
|
25
|
-
types: ['vite/client'],
|
|
26
|
-
paths: {
|
|
27
|
-
'@/*': ['./src/*'],
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
include: ['src/**/*.ts', 'src/**/*.d.ts', 'src/**/*.tsx', 'src/**/*.vue'],
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
await this._fileService.writeFileRecursive(
|
|
34
|
-
path.join(projectPath, 'tsconfig.json'),
|
|
35
|
-
JSON.stringify(tsconfig, null, 2),
|
|
36
|
-
)
|
|
37
|
-
}
|
|
38
|
-
}
|
|
@@ -1,38 +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 UseAppVueGenerator implements IGenerator<VueOptions> {
|
|
7
|
-
constructor(private readonly _fileService: IFileService) {}
|
|
8
|
-
|
|
9
|
-
public async generate(projectPath: string, _options: VueOptions): Promise<void> {
|
|
10
|
-
const content = `import type { Nullable } from "@xeno-js/vue";
|
|
11
|
-
import { Guards, XENO_SERVICES_KEY } from "@xeno-js/vue";
|
|
12
|
-
import { inject } from "vue";
|
|
13
|
-
import type { MyRegistry } from "./registry";
|
|
14
|
-
|
|
15
|
-
let globalServices: Nullable<MyRegistry> = null;
|
|
16
|
-
|
|
17
|
-
export const ServicesUtils = Object.freeze({
|
|
18
|
-
// Metodo per registrare i servizi al bootstrap
|
|
19
|
-
setGlobalServices(services: MyRegistry) {
|
|
20
|
-
globalServices = services;
|
|
21
|
-
},
|
|
22
|
-
useApp(): MyRegistry {
|
|
23
|
-
if (Guards.isDefined(globalServices))
|
|
24
|
-
return globalServices;
|
|
25
|
-
|
|
26
|
-
const services = inject<MyRegistry>(XENO_SERVICES_KEY);
|
|
27
|
-
if (!services)
|
|
28
|
-
throw new Error(
|
|
29
|
-
'[Xeno Error]: XenoServices not found. Did you provide them using app.provide(XENO_SERVICES_KEY, services)?',
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
return services;
|
|
33
|
-
}
|
|
34
|
-
} as const);
|
|
35
|
-
`
|
|
36
|
-
await this._fileService.writeFileRecursive(path.join(projectPath, 'src', 'use-app.ts'), content)
|
|
37
|
-
}
|
|
38
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
// src/infrastructure/generators/viteconfig.generator.ts
|
|
2
|
-
import path from 'node:path'
|
|
3
|
-
|
|
4
|
-
import { type IFileService, type IGenerator } from '../../../domain'
|
|
5
|
-
import type { VueOptions } from '../../../shared'
|
|
6
|
-
|
|
7
|
-
export class ViteconfigGenerator implements IGenerator<VueOptions> {
|
|
8
|
-
constructor(private readonly _fileService: IFileService) {}
|
|
9
|
-
|
|
10
|
-
public async generate(projectPath: string, options: VueOptions): Promise<void> {
|
|
11
|
-
const tailwindImport = options.tailwind ? `\nimport tailwindcss from '@tailwindcss/vite';` : ''
|
|
12
|
-
const tailwindPlugin = options.tailwind ? `\n tailwindcss(),` : ''
|
|
13
|
-
|
|
14
|
-
const content = `import { defineConfig } from 'vite';
|
|
15
|
-
import vue from '@vitejs/plugin-vue';${tailwindImport}
|
|
16
|
-
import path from 'node:path';
|
|
17
|
-
|
|
18
|
-
export default defineConfig({
|
|
19
|
-
plugins: [
|
|
20
|
-
vue(),${tailwindPlugin}
|
|
21
|
-
],
|
|
22
|
-
resolve: {
|
|
23
|
-
alias: {
|
|
24
|
-
'@': path.resolve(__dirname, './src'),
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
server: {
|
|
28
|
-
port: 5173,
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
`
|
|
32
|
-
const filePath = path.join(projectPath, 'vite.config.ts')
|
|
33
|
-
await this._fileService.writeFileRecursive(filePath, content)
|
|
34
|
-
}
|
|
35
|
-
}
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
// src/strategies/core.strategy.ts
|
|
2
|
-
import prompts from 'prompts'
|
|
3
|
-
|
|
4
|
-
import type { IFileService, IGenerator, IScaffoldStrategy } from '../../domain'
|
|
5
|
-
import type { CoreOptions } from '../../shared'
|
|
6
|
-
import { CORE_CONSTANTS, TARGET_ENV_CONSTANTS } from '../../shared'
|
|
7
|
-
|
|
8
|
-
export class CoreScaffoldStrategy implements IScaffoldStrategy<CoreOptions> {
|
|
9
|
-
constructor(private readonly _fileService: IFileService) {}
|
|
10
|
-
public async promptOptions(targetDir: string): Promise<CoreOptions> {
|
|
11
|
-
const response = await prompts([
|
|
12
|
-
{ type: 'confirm', name: 'axios', message: 'Install Axios?', initial: true },
|
|
13
|
-
{ type: 'confirm', name: 'cockatiel', message: 'Install Cockatiel?', initial: true },
|
|
14
|
-
{ type: 'confirm', name: 'supabase', message: 'Install Supabase Auth?', initial: true },
|
|
15
|
-
{
|
|
16
|
-
type: 'select',
|
|
17
|
-
name: 'database',
|
|
18
|
-
message: 'Select database type',
|
|
19
|
-
choices: [
|
|
20
|
-
{ title: 'Drizzle PostgreSQL', value: 'drizzle' },
|
|
21
|
-
{ title: 'SQL Lite', value: 'sqlLite' },
|
|
22
|
-
{ title: 'None', value: 'none' },
|
|
23
|
-
],
|
|
24
|
-
},
|
|
25
|
-
{ type: 'confirm', name: 'pino', message: 'Install Pino Logger?', initial: true },
|
|
26
|
-
{ type: 'confirm', name: 'sentry', message: 'Install Sentry Logger?', initial: true },
|
|
27
|
-
{ type: 'confirm', name: 'redis', message: 'Install Redis?', initial: true },
|
|
28
|
-
{ type: 'confirm', name: 'zod', message: 'Install Zod?', initial: true },
|
|
29
|
-
// {
|
|
30
|
-
// type: 'select',
|
|
31
|
-
// name: 'targetEnv',
|
|
32
|
-
// message: 'Select target environment',
|
|
33
|
-
// choices: [
|
|
34
|
-
// { title: 'Console', value: 'console' },
|
|
35
|
-
// { title: 'Vercel (Serverless)', value: 'vercel' },
|
|
36
|
-
// { title: 'Fastify (Standalone)', value: 'fastify' },
|
|
37
|
-
// ],
|
|
38
|
-
// },
|
|
39
|
-
{
|
|
40
|
-
type: 'confirm',
|
|
41
|
-
name: 'gitInit',
|
|
42
|
-
message: 'Initialize a new Git repository?',
|
|
43
|
-
initial: true,
|
|
44
|
-
},
|
|
45
|
-
])
|
|
46
|
-
|
|
47
|
-
return {
|
|
48
|
-
targetDir,
|
|
49
|
-
projectType: 'core',
|
|
50
|
-
targetEnv: 'console',
|
|
51
|
-
...response,
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
public async getGenerators(options: CoreOptions): Promise<IGenerator<CoreOptions>[]> {
|
|
56
|
-
// Lazy Loading: Importiamo i moduli solo se servono!
|
|
57
|
-
const generators: IGenerator<CoreOptions>[] = []
|
|
58
|
-
|
|
59
|
-
const { PackageJsonCoreGenerator } = await import('../generators/core/packagejson.generator.js')
|
|
60
|
-
const { BootstrapGenerator } = await import('../generators/core/bootstrap.generator.js')
|
|
61
|
-
const { EnvGenerator } = await import('../generators/core/env.generator.js')
|
|
62
|
-
const { GitIgnoreGenerator } = await import('../generators/gitignore.generator.js')
|
|
63
|
-
const { ReadmeGenerator } = await import('../generators/core/readme.generator.js')
|
|
64
|
-
const { RegistryGenerator } = await import('../generators/core/registry.generator.js')
|
|
65
|
-
const { TsconfigGenerator } = await import('../generators/core/tsconfig.generator.js')
|
|
66
|
-
|
|
67
|
-
generators.push(new PackageJsonCoreGenerator(this._fileService))
|
|
68
|
-
generators.push(new BootstrapGenerator(this._fileService))
|
|
69
|
-
generators.push(new EnvGenerator(this._fileService))
|
|
70
|
-
generators.push(new GitIgnoreGenerator(this._fileService))
|
|
71
|
-
generators.push(new ReadmeGenerator(this._fileService))
|
|
72
|
-
generators.push(new RegistryGenerator(this._fileService))
|
|
73
|
-
generators.push(new TsconfigGenerator(this._fileService))
|
|
74
|
-
|
|
75
|
-
if (options.database !== CORE_CONSTANTS.NONE) {
|
|
76
|
-
if (options.database === CORE_CONSTANTS.DRIZZLE) {
|
|
77
|
-
const { DrizzleGenerator } = await import('../generators/core/drizzle.generator.js')
|
|
78
|
-
generators.push(new DrizzleGenerator(this._fileService))
|
|
79
|
-
} else if (options.database === CORE_CONSTANTS.SQL_LITE) {
|
|
80
|
-
const { DrizzleSqlLiteGenerator } =
|
|
81
|
-
await import('../generators/core/drizzle-sql-lite.generator.js')
|
|
82
|
-
generators.push(new DrizzleSqlLiteGenerator(this._fileService))
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (options.targetEnv === TARGET_ENV_CONSTANTS.CONSOLE) {
|
|
87
|
-
const { MainGenerator } = await import('../generators/core/main.generator.js')
|
|
88
|
-
generators.push(new MainGenerator(this._fileService))
|
|
89
|
-
}
|
|
90
|
-
// else if (options.targetEnv === CORE_CONSTANTS.VERCEL) {
|
|
91
|
-
// const { VercelJsonGenerator } = await import('../generators');
|
|
92
|
-
// generators.push(new VercelJsonGenerator());
|
|
93
|
-
// } else if (options.targetEnv === CORE_CONSTANTS.FASTIFY) {
|
|
94
|
-
// const { FastifysonGenerator } = await import('../generators');
|
|
95
|
-
// generators.push(new FastifysonGenerator());
|
|
96
|
-
// }
|
|
97
|
-
|
|
98
|
-
return generators
|
|
99
|
-
}
|
|
100
|
-
}
|