@xeno-js/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. package/.github/.copilot-instruction.md +73 -0
  2. package/.github/agents/git-operator.agent.md +86 -0
  3. package/.github/agents/unit-tester.agent.md +68 -0
  4. package/.husky/commit-msg +1 -0
  5. package/.husky/pre-commit +1 -0
  6. package/.husky/pre-push +1 -0
  7. package/.prettierignore +7 -0
  8. package/.prettierrc.json +37 -0
  9. package/LICENSE +15 -0
  10. package/README.md +236 -0
  11. package/commitlint.config.cjs +39 -0
  12. package/dist/domain/contracts/icommand-cli.contracts.js +2 -0
  13. package/dist/domain/contracts/icommand-runner.contracts.js +2 -0
  14. package/dist/domain/contracts/idispatch.contracts.js +2 -0
  15. package/dist/domain/contracts/ifile-service.contracts.js +2 -0
  16. package/dist/domain/contracts/igenerator.contracts.js +2 -0
  17. package/dist/domain/contracts/index.js +2 -0
  18. package/dist/domain/contracts/iscaffold-strategy.contracts.js +2 -0
  19. package/dist/domain/index.js +2 -0
  20. package/dist/generator.contracts.js +13 -0
  21. package/dist/index.js +31 -0
  22. package/dist/infrastructure/bootstrap/bootstrapper.js +32 -0
  23. package/dist/infrastructure/bootstrap/index.js +17 -0
  24. package/dist/infrastructure/builder/builder.js +16 -0
  25. package/dist/infrastructure/builder/builder.test.js +30 -0
  26. package/dist/infrastructure/builder/index.js +17 -0
  27. package/dist/infrastructure/command_launcher/command.utils.js +30 -0
  28. package/dist/infrastructure/command_launcher/index.js +2 -0
  29. package/dist/infrastructure/commands/command-runner.service.js +36 -0
  30. package/dist/infrastructure/commands/generate.command.js +48 -0
  31. package/dist/infrastructure/commands/help.command.js +44 -0
  32. package/dist/infrastructure/commands/index.js +20 -0
  33. package/dist/infrastructure/commands/new-project.command.js +43 -0
  34. package/dist/infrastructure/dispatcher/dispatcher.js +39 -0
  35. package/dist/infrastructure/dispatcher/index.js +17 -0
  36. package/dist/infrastructure/file/file.service.js +13 -0
  37. package/dist/infrastructure/file/index.js +17 -0
  38. package/dist/infrastructure/generators/bootstrap.generator.js +118 -0
  39. package/dist/infrastructure/generators/core/bootstrap.generator.js +118 -0
  40. package/dist/infrastructure/generators/core/command/cqrs.generator.js +49 -0
  41. package/dist/infrastructure/generators/core/command/generate-command.generator.js +163 -0
  42. package/dist/infrastructure/generators/core/command/generate-query.generator.js +131 -0
  43. package/dist/infrastructure/generators/core/drizzle-sql-lite.generator.js +78 -0
  44. package/dist/infrastructure/generators/core/drizzle.generator.js +85 -0
  45. package/dist/infrastructure/generators/core/env.generator.js +69 -0
  46. package/dist/infrastructure/generators/core/index.js +25 -0
  47. package/dist/infrastructure/generators/core/main.generator.js +45 -0
  48. package/dist/infrastructure/generators/core/packagejson.generator.js +78 -0
  49. package/dist/infrastructure/generators/core/readme.generator.js +431 -0
  50. package/dist/infrastructure/generators/core/registry.generator.js +46 -0
  51. package/dist/infrastructure/generators/core/tsconfig.generator.js +41 -0
  52. package/dist/infrastructure/generators/core-packagejson.generator.js +78 -0
  53. package/dist/infrastructure/generators/drizzle-sql-lite.generator.js +78 -0
  54. package/dist/infrastructure/generators/drizzle.generator.js +85 -0
  55. package/dist/infrastructure/generators/env-vue.generator.js +40 -0
  56. package/dist/infrastructure/generators/env.generator.js +71 -0
  57. package/dist/infrastructure/generators/gitignore.generator.js +62 -0
  58. package/dist/infrastructure/generators/index.js +26 -0
  59. package/dist/infrastructure/generators/main.generator.js +45 -0
  60. package/dist/infrastructure/generators/readme.generator.js +431 -0
  61. package/dist/infrastructure/generators/registry.generator.js +46 -0
  62. package/dist/infrastructure/generators/tsconfig-vue.generator.js +39 -0
  63. package/dist/infrastructure/generators/tsconfig.generator.js +41 -0
  64. package/dist/infrastructure/generators/vite-config.generator.js +39 -0
  65. package/dist/infrastructure/generators/vue/app-vue.generator.js +26 -0
  66. package/dist/infrastructure/generators/vue/bootstrap-ts.generator.js +59 -0
  67. package/dist/infrastructure/generators/vue/command_query/cqrs.generator.js +36 -0
  68. package/dist/infrastructure/generators/vue/command_query/generate-command-vue.generator.js +139 -0
  69. package/dist/infrastructure/generators/vue/command_query/generate-query-vue.generator.js +147 -0
  70. package/dist/infrastructure/generators/vue/env.generator.js +40 -0
  71. package/dist/infrastructure/generators/vue/index-html.generator.js +29 -0
  72. package/dist/infrastructure/generators/vue/index.js +28 -0
  73. package/dist/infrastructure/generators/vue/main.generator.js +45 -0
  74. package/dist/infrastructure/generators/vue/packagejson.generator.js +59 -0
  75. package/dist/infrastructure/generators/vue/readme.generator.js +394 -0
  76. package/dist/infrastructure/generators/vue/registry-ts.generator.js +28 -0
  77. package/dist/infrastructure/generators/vue/router.generator.js +33 -0
  78. package/dist/infrastructure/generators/vue/tailwind.generator.js +19 -0
  79. package/dist/infrastructure/generators/vue/tsconfig.generator.js +39 -0
  80. package/dist/infrastructure/generators/vue/use-app.generator.js +43 -0
  81. package/dist/infrastructure/generators/vue/vite-config.generator.js +39 -0
  82. package/dist/infrastructure/generators/vue-packagejson.generator.js +59 -0
  83. package/dist/infrastructure/generators/vue-readme.generator.js +53 -0
  84. package/dist/infrastructure/generators/vue-source-files.generator.js +136 -0
  85. package/dist/infrastructure/index.js +21 -0
  86. package/dist/infrastructure/strategies/core-scaffold.strategy.js +99 -0
  87. package/dist/infrastructure/strategies/index.js +18 -0
  88. package/dist/infrastructure/strategies/vue-scaffold.strategy.js +79 -0
  89. package/dist/scaffolding.engine.js +60 -0
  90. package/dist/shared/constants/command.constants.js +19 -0
  91. package/dist/shared/constants/core.constants.js +10 -0
  92. package/dist/shared/constants/index.js +18 -0
  93. package/dist/shared/index.js +18 -0
  94. package/dist/shared/types/common.types.js +2 -0
  95. package/dist/shared/types/index.js +2 -0
  96. package/dist/shared/utils/guards.utils.js +310 -0
  97. package/dist/shared/utils/index.js +18 -0
  98. package/dist/shared/utils/string.utils.js +62 -0
  99. package/eslint.config.mjs +305 -0
  100. package/lint-staged.config.mjs +5 -0
  101. package/logo/logo.png +0 -0
  102. package/package.json +65 -0
  103. package/src/domain/contracts/icommand-cli.contracts.ts +13 -0
  104. package/src/domain/contracts/icommand-runner.contracts.ts +3 -0
  105. package/src/domain/contracts/idispatch.contracts.ts +3 -0
  106. package/src/domain/contracts/ifile-service.contracts.ts +3 -0
  107. package/src/domain/contracts/igenerator.contracts.ts +5 -0
  108. package/src/domain/contracts/index.ts +6 -0
  109. package/src/domain/contracts/iscaffold-strategy.contracts.ts +7 -0
  110. package/src/domain/index.ts +1 -0
  111. package/src/index.ts +30 -0
  112. package/src/infrastructure/bootstrap/bootstrapper.ts +30 -0
  113. package/src/infrastructure/bootstrap/index.ts +1 -0
  114. package/src/infrastructure/builder/builder.test.ts +36 -0
  115. package/src/infrastructure/builder/builder.ts +15 -0
  116. package/src/infrastructure/builder/index.ts +1 -0
  117. package/src/infrastructure/command_launcher/command.utils.ts +31 -0
  118. package/src/infrastructure/command_launcher/index.ts +0 -0
  119. package/src/infrastructure/commands/command-runner.service.ts +36 -0
  120. package/src/infrastructure/commands/generate.command.ts +55 -0
  121. package/src/infrastructure/commands/help.command.ts +63 -0
  122. package/src/infrastructure/commands/index.ts +4 -0
  123. package/src/infrastructure/commands/new-project.command.ts +47 -0
  124. package/src/infrastructure/dispatcher/dispatcher.ts +45 -0
  125. package/src/infrastructure/dispatcher/index.ts +1 -0
  126. package/src/infrastructure/file/file.service.ts +14 -0
  127. package/src/infrastructure/file/index.ts +1 -0
  128. package/src/infrastructure/generators/core/bootstrap.generator.ts +118 -0
  129. package/src/infrastructure/generators/core/command/cqrs.generator.ts +63 -0
  130. package/src/infrastructure/generators/core/command/generate-command.generator.ts +191 -0
  131. package/src/infrastructure/generators/core/command/generate-query.generator.ts +150 -0
  132. package/src/infrastructure/generators/core/drizzle-sql-lite.generator.ts +76 -0
  133. package/src/infrastructure/generators/core/drizzle.generator.ts +86 -0
  134. package/src/infrastructure/generators/core/env.generator.ts +69 -0
  135. package/src/infrastructure/generators/core/index.ts +9 -0
  136. package/src/infrastructure/generators/core/main.generator.ts +41 -0
  137. package/src/infrastructure/generators/core/packagejson.generator.ts +70 -0
  138. package/src/infrastructure/generators/core/readme.generator.ts +427 -0
  139. package/src/infrastructure/generators/core/registry.generator.ts +40 -0
  140. package/src/infrastructure/generators/core/tsconfig.generator.ts +39 -0
  141. package/src/infrastructure/generators/gitignore.generator.ts +60 -0
  142. package/src/infrastructure/generators/vue/app-vue.generator.ts +21 -0
  143. package/src/infrastructure/generators/vue/bootstrap-ts.generator.ts +60 -0
  144. package/src/infrastructure/generators/vue/command_query/cqrs.generator.ts +36 -0
  145. package/src/infrastructure/generators/vue/command_query/generate-command-vue.generator.ts +153 -0
  146. package/src/infrastructure/generators/vue/command_query/generate-query-vue.generator.ts +161 -0
  147. package/src/infrastructure/generators/vue/env.generator.ts +39 -0
  148. package/src/infrastructure/generators/vue/index-html.generator.ts +24 -0
  149. package/src/infrastructure/generators/vue/index.ts +12 -0
  150. package/src/infrastructure/generators/vue/main.generator.ts +41 -0
  151. package/src/infrastructure/generators/vue/packagejson.generator.ts +50 -0
  152. package/src/infrastructure/generators/vue/readme.generator.ts +389 -0
  153. package/src/infrastructure/generators/vue/registry-ts.generator.ts +26 -0
  154. package/src/infrastructure/generators/vue/router.generator.ts +35 -0
  155. package/src/infrastructure/generators/vue/tailwind.generator.ts +17 -0
  156. package/src/infrastructure/generators/vue/tsconfig.generator.ts +38 -0
  157. package/src/infrastructure/generators/vue/use-app.generator.ts +38 -0
  158. package/src/infrastructure/generators/vue/vite-config.generator.ts +35 -0
  159. package/src/infrastructure/index.ts +5 -0
  160. package/src/infrastructure/strategies/core-scaffold.strategy.ts +100 -0
  161. package/src/infrastructure/strategies/index.ts +2 -0
  162. package/src/infrastructure/strategies/vue-scaffold.strategy.ts +79 -0
  163. package/src/shared/constants/command.constants.ts +18 -0
  164. package/src/shared/constants/core.constants.ts +7 -0
  165. package/src/shared/constants/index.ts +2 -0
  166. package/src/shared/index.ts +3 -0
  167. package/src/shared/types/common.types.ts +68 -0
  168. package/src/shared/types/index.ts +1 -0
  169. package/src/shared/utils/guards.utils.ts +334 -0
  170. package/src/shared/utils/index.ts +2 -0
  171. package/src/shared/utils/string.utils.ts +60 -0
  172. package/tsconfig.json +15 -0
@@ -0,0 +1,36 @@
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.CqrsVueGenerator = void 0;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const shared_1 = require("../../../../shared");
9
+ class CqrsVueGenerator {
10
+ _fileService;
11
+ constructor(_fileService) {
12
+ this._fileService = _fileService;
13
+ }
14
+ async generate(targetDir, name, type, outputPath) {
15
+ const pascalName = shared_1.StringUtils.pascalCase(name);
16
+ const tokenPrefix = shared_1.StringUtils.splitCamelCaseWithUnderscore(pascalName).toUpperCase();
17
+ const lowerName = name.toLowerCase();
18
+ const destinationFolder = outputPath ?? lowerName;
19
+ const componentDir = node_path_1.default.join(targetDir, 'src', destinationFolder);
20
+ switch (type) {
21
+ case shared_1.COMMAND_CONSTANTS.COMMAND: {
22
+ const { GenerateCommandVueGenerator } = await import('./generate-command-vue.generator.js');
23
+ const generator = new GenerateCommandVueGenerator(this._fileService);
24
+ return generator.generate(pascalName, lowerName, tokenPrefix, componentDir);
25
+ }
26
+ case shared_1.COMMAND_CONSTANTS.QUERY: {
27
+ const { GenerateQueryVueGenerator } = await import('./generate-query-vue.generator.js');
28
+ const generatorQuery = new GenerateQueryVueGenerator(this._fileService);
29
+ return generatorQuery.generate(pascalName, lowerName, tokenPrefix, componentDir);
30
+ }
31
+ default:
32
+ throw new Error(`Unsupported generator type: '${String(type)}'. Use 'command' or 'query'.`);
33
+ }
34
+ }
35
+ }
36
+ exports.CqrsVueGenerator = CqrsVueGenerator;
@@ -0,0 +1,139 @@
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.GenerateCommandVueGenerator = void 0;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ class GenerateCommandVueGenerator {
9
+ _fileService;
10
+ constructor(_fileService) {
11
+ this._fileService = _fileService;
12
+ }
13
+ async generate(pascalName, lowerName, tokenPrefix, componentDir) {
14
+ // 1. Command (Application)
15
+ const commandContent = `import { Command } from '@xeno-js/vue';
16
+
17
+ export class ${pascalName}Command extends Command {
18
+ constructor() {
19
+ super('${tokenPrefix}_COMMAND');
20
+ }
21
+ }
22
+ `;
23
+ await this._fileService.writeFileRecursive(node_path_1.default.join(componentDir, `${lowerName}.command.ts`), commandContent);
24
+ const handlerContent = `import type { IHandler, ResultType } from '@xeno-js/vue';
25
+ import { AppError, Result } from '@xeno-js/vue';
26
+ import type { ${pascalName}Command } from './${lowerName}.command';
27
+ import type { ${pascalName}Response } from './${lowerName}.model';
28
+
29
+ /*
30
+ * ⚠️ WARNING: ACTION REQUIRED ⚠️
31
+ *
32
+ * Please register your handler in the IoC container (e.g. src/bootstrap.ts) and add its token to MyRegistry.
33
+ *
34
+ * 1. In src/registry.ts:
35
+ * ${tokenPrefix}_HANDLER: IHandler<${pascalName}Command, ${pascalName}Response>;
36
+ *
37
+ * 2. In src/bootstrap.ts:
38
+ * .addServices((config, register) => {
39
+ * register('${tokenPrefix}_HANDLER', new ${pascalName}Handler());
40
+ * });
41
+ */
42
+ export class ${pascalName}Handler implements IHandler<${pascalName}Command, ${pascalName}Response> {
43
+ constructor(
44
+ // TODO: Inject your remote DataSources or other services here
45
+ ) {}
46
+
47
+ public async handle(command: ${pascalName}Command, signal: AbortSignal): Promise<ResultType<${pascalName}Response>> {
48
+ AppError.throwIfAborted(signal, this.constructor.name);
49
+
50
+ // TODO: Implement your frontend business logic or API calls here
51
+ return Result.ok();
52
+ }
53
+ }
54
+ `;
55
+ await this._fileService.writeFileRecursive(node_path_1.default.join(componentDir, `${lowerName}.handler.ts`), handlerContent);
56
+ const composableContent = `import { ref } from 'vue';
57
+ import { AppError, Result, type ApiResponseDto, type ResultType } from '@xeno-js/vue';
58
+ import { ServicesUtils } from '@/use-app';
59
+ import { ${pascalName}Command } from './${lowerName}.command';
60
+ import type { ${pascalName}Request, ${pascalName}Response } from './${lowerName}.model';
61
+
62
+ /*
63
+ * ⚠️ WARNING: ACTION REQUIRED ⚠️
64
+ *
65
+ * Please register your handler in the IoC container (e.g. src/bootstrap.ts) and add its token to MyRegistry.
66
+ *
67
+ * 1. In src/registry.ts:
68
+ * ${tokenPrefix}_HANDLER: IHandler<${pascalName}Command, ${pascalName}Response>;
69
+ *
70
+ * 2. In src/bootstrap.ts:
71
+ * .addServices((config, register) => {
72
+ * register('${tokenPrefix}_HANDLER', new ${pascalName}Handler());
73
+ * });
74
+ */
75
+ export function use${pascalName}() {
76
+ const loading = ref(false);
77
+ const error = ref<string | null>(null);
78
+ let abortController: AbortController | null = null;
79
+
80
+ const execute = async (payload: ${pascalName}Request): Promise<ResultType<${pascalName}Response>> => {
81
+ abortController = new AbortController();
82
+
83
+ if (loading.value) return Result.fail(AppError.create({
84
+ name: '${pascalName}Command',
85
+ message: '${pascalName}Command is already in progress',
86
+ code: '${tokenPrefix}_COMMAND_ALREADY_IN_PROGRESS',
87
+ status: 500,
88
+ cause: new Error('${tokenPrefix}_COMMAND_ALREADY_IN_PROGRESS'),
89
+ }));
90
+ loading.value = true;
91
+ error.value = null;
92
+
93
+ try {
94
+ // Resolve mediator and handler from the container
95
+ const { mediator, ${tokenPrefix}_HANDLER: handler } = ServicesUtils.useApp();
96
+ const command = new ${pascalName}Command();
97
+
98
+ const result = await mediator.send(command, async () => {
99
+ return await handler.handle(command, abortController?.signal);
100
+ });
101
+
102
+ if (!result.isOk()) {
103
+ error.value = result.getErrorOrThrow().message;
104
+ }
105
+
106
+ return result;
107
+ } finally {
108
+ loading.value = false;
109
+ }
110
+ };
111
+
112
+ const abort = () => {
113
+ if (abortController) {
114
+ abortController.abort();
115
+ }
116
+ };
117
+
118
+ // Automatically cancel pending operations when the component unmounts
119
+ onUnmounted(() => {
120
+ abort();
121
+ });
122
+
123
+ return { loading, error, execute };
124
+ }
125
+ `;
126
+ await this._fileService.writeFileRecursive(node_path_1.default.join(componentDir, `use-${lowerName}.composable.ts`), composableContent);
127
+ // 3. Domain Model (Domain)
128
+ const modelContent = `export interface ${pascalName}Request {
129
+ // TODO: Define your request payload properties here
130
+ }
131
+
132
+ export interface ${pascalName}Response {
133
+ // TODO: Define your response properties here
134
+ }
135
+ `;
136
+ await this._fileService.writeFileRecursive(node_path_1.default.join(componentDir, `${lowerName}.model.ts`), modelContent);
137
+ }
138
+ }
139
+ exports.GenerateCommandVueGenerator = GenerateCommandVueGenerator;
@@ -0,0 +1,147 @@
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.GenerateQueryVueGenerator = void 0;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ class GenerateQueryVueGenerator {
9
+ _fileService;
10
+ constructor(_fileService) {
11
+ this._fileService = _fileService;
12
+ }
13
+ async generate(pascalName, lowerName, tokenPrefix, componentDir) {
14
+ // 1. Query (Application)
15
+ const queryContent = `import { Query } from '@xeno-js/vue';
16
+ import type { ${pascalName}Response } from './${lowerName}.model';
17
+
18
+ export class ${pascalName}Query extends Query<${pascalName}Response> {
19
+ constructor() {
20
+ super('${tokenPrefix}_QUERY', {
21
+ ttl: 60,
22
+ cacheKey: \`${lowerName}.query\`,
23
+ bypassCache: false,
24
+ consistentRead: false,
25
+ isUserScoped: true
26
+ });
27
+ }
28
+ }
29
+ `;
30
+ await this._fileService.writeFileRecursive(node_path_1.default.join(componentDir, `${lowerName}.query.ts`), queryContent);
31
+ const handlerContent = `import type { IHandler, ResultType } from '@xeno-js/vue';
32
+ import { AppError, Result } from '@xeno-js/vue';
33
+ import type { ${pascalName}Query } from './${lowerName}.query';
34
+ import type { ${pascalName}Response } from './${lowerName}.model';
35
+
36
+ /*
37
+ * ⚠️ WARNING: ACTION REQUIRED ⚠️
38
+ *
39
+ * Please register your handler in the IoC container (e.g. src/bootstrap.ts) and add its token to MyRegistry.
40
+ *
41
+ * 1. In src/registry.ts:
42
+ * ${tokenPrefix}_HANDLER: IHandler<${pascalName}Query, ${pascalName}Response>;
43
+ *
44
+ * 2. In src/bootstrap.ts:
45
+ * .addServices((config, register) => {
46
+ * register('${tokenPrefix}_HANDLER', new ${pascalName}Handler());
47
+ * });
48
+ */
49
+ export class ${pascalName}Handler implements IHandler<${pascalName}Query, ${pascalName}Response> {
50
+ constructor(
51
+ // TODO: Inject your remote DataSources or other services here
52
+ ) {}
53
+
54
+ public async handle(query: ${pascalName}Query, signal: AbortSignal): Promise<ResultType<${pascalName}Response>> {
55
+ AppError.throwIfAborted(signal, this.constructor.name);
56
+
57
+ // TODO: Implement your frontend business logic or API calls here
58
+ return Result.ok();
59
+ }
60
+ }
61
+ `;
62
+ await this._fileService.writeFileRecursive(node_path_1.default.join(componentDir, `${lowerName}.handler.ts`), handlerContent);
63
+ // 2. Composable (Presentation)
64
+ const composableContent = `import { ref } from 'vue';
65
+ import { AppError, Result, type ApiResponseDto, type ResultType } from '@xeno-js/vue';
66
+ import { ServicesUtils } from '@/use-app';
67
+ import { ${pascalName}Query } from './${lowerName}.query';
68
+ import type { ${pascalName}Response } from './${lowerName}.model';
69
+
70
+ export function use${pascalName}() {
71
+ const loading = ref(false);
72
+ const error = ref<string | null>(null);
73
+ const data = ref<${pascalName}Response | null>(null);
74
+ let abortController: AbortController | null = null;
75
+
76
+ /*
77
+ * ⚠️ WARNING: ACTION REQUIRED ⚠️
78
+ *
79
+ * Please register your handler in the IoC container (e.g. src/bootstrap.ts) and add its token to MyRegistry.
80
+ *
81
+ * 1. In src/registry.ts:
82
+ * ${tokenPrefix}_HANDLER: IHandler<${pascalName}Query, ${pascalName}Response>;
83
+ *
84
+ * 2. In src/bootstrap.ts:
85
+ * .addServices((config, register) => {
86
+ * register('${tokenPrefix}_HANDLER', new ${pascalName}Handler());
87
+ * });
88
+ */
89
+ const fetch = async (): Promise<ResultType<${pascalName}Response>> => {
90
+ abortController = new AbortController();
91
+
92
+ if (loading.value) return Result.fail(AppError.create({
93
+ name: '${pascalName}Query',
94
+ message: '${pascalName}Query is already in progress',
95
+ code: '${tokenPrefix}_QUERY_ALREADY_IN_PROGRESS',
96
+ status: 500,
97
+ cause: new Error('${tokenPrefix}_QUERY_ALREADY_IN_PROGRESS'),
98
+ }));
99
+ loading.value = true;
100
+ error.value = null;
101
+
102
+ try {
103
+ try {
104
+ // Resolve mediator and handler from the container
105
+ const { mediator, ${tokenPrefix}_HANDLER: handler } = ServicesUtils.useApp();
106
+ const query = new ${pascalName}Query();
107
+
108
+ const result = await mediator.query(query, async () => {
109
+ return await handler.handle(query, abortController?.signal);
110
+ });
111
+
112
+ if (result.isOk()) {
113
+ data.value = result.getValueOrThrow();
114
+ } else {
115
+ error.value = result.getErrorOrThrow().message;
116
+ }
117
+
118
+ return result;
119
+ } finally {
120
+ loading.value = false;
121
+ }
122
+ };
123
+
124
+ const abort = () => {
125
+ if (abortController) {
126
+ abortController.abort();
127
+ }
128
+ };
129
+
130
+ // Automatically cancel pending operations when the component unmounts
131
+ onUnmounted(() => {
132
+ abort();
133
+ });
134
+
135
+ return { loading, error, data, fetch };
136
+ }
137
+ `;
138
+ await this._fileService.writeFileRecursive(node_path_1.default.join(componentDir, `use-${lowerName}.composable.ts`), composableContent);
139
+ // 3. Domain Model (Domain)
140
+ const modelContent = `export interface ${pascalName}Response {
141
+ // TODO: Define your response properties here
142
+ }
143
+ `;
144
+ await this._fileService.writeFileRecursive(node_path_1.default.join(componentDir, `${lowerName}.model.ts`), modelContent);
145
+ }
146
+ }
147
+ exports.GenerateQueryVueGenerator = GenerateQueryVueGenerator;
@@ -0,0 +1,40 @@
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.EnvVueGenerator = void 0;
7
+ // src/infrastructure/generators/env-vue.generator.ts
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ class EnvVueGenerator {
10
+ _fileService;
11
+ constructor(_fileService) {
12
+ this._fileService = _fileService;
13
+ }
14
+ async generate(projectPath, options) {
15
+ let content = `# ─────────────────────────────────────────────────────────────────────────────
16
+ # Xeno VUE APPLICATION ENVIRONMENT VARIABLES
17
+ # ─────────────────────────────────────────────────────────────────────────────
18
+ VITE_APP_ENV=development
19
+ `;
20
+ if (options.axios) {
21
+ content += `\n# --- Axios ---
22
+ VITE_API_BASE_URL=http://localhost:3000
23
+ `;
24
+ }
25
+ if (options.supabase) {
26
+ content += `\n# --- Authentication (Supabase) ---
27
+ VITE_SUPABASE_URL=https://your-project.supabase.co
28
+ VITE_SUPABASE_KEY=your-anon-key
29
+ `;
30
+ }
31
+ if (options.sentry) {
32
+ content += `\n# --- Error Tracking (Sentry) ---
33
+ VITE_SENTRY_DSN=https://your-sentry-dsn@o0.ingest.sentry.io/0
34
+ `;
35
+ }
36
+ await this._fileService.writeFileRecursive(node_path_1.default.join(projectPath, '.env'), content);
37
+ await this._fileService.writeFileRecursive(node_path_1.default.join(projectPath, '.env.example'), content);
38
+ }
39
+ }
40
+ exports.EnvVueGenerator = EnvVueGenerator;
@@ -0,0 +1,29 @@
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.IndexVueGenerator = void 0;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ class IndexVueGenerator {
9
+ _fileService;
10
+ constructor(_fileService) {
11
+ this._fileService = _fileService;
12
+ }
13
+ async generate(projectPath, options) {
14
+ const indexHtml = `<!DOCTYPE html>
15
+ <html lang="en">
16
+ <head>
17
+ <meta charset="UTF-8" />
18
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
19
+ <title>${options.targetDir}</title>
20
+ </head>
21
+ <body>
22
+ <div id="app"></div>
23
+ <script type="module" src="/src/main.ts"></script>
24
+ </body>
25
+ </html>`;
26
+ await this._fileService.writeFileRecursive(node_path_1.default.join(projectPath, 'index.html'), indexHtml);
27
+ }
28
+ }
29
+ exports.IndexVueGenerator = IndexVueGenerator;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./app-vue.generator"), exports);
18
+ __exportStar(require("./bootstrap-ts.generator"), exports);
19
+ __exportStar(require("./env.generator"), exports);
20
+ __exportStar(require("./index-html.generator"), exports);
21
+ __exportStar(require("./main.generator"), exports);
22
+ __exportStar(require("./packagejson.generator"), exports);
23
+ __exportStar(require("./readme.generator"), exports);
24
+ __exportStar(require("./registry-ts.generator"), exports);
25
+ __exportStar(require("./router.generator"), exports);
26
+ __exportStar(require("./tailwind.generator"), exports);
27
+ __exportStar(require("./tsconfig.generator"), exports);
28
+ __exportStar(require("./vite-config.generator"), exports);
@@ -0,0 +1,45 @@
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.MainGenerator = void 0;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ class MainGenerator {
9
+ _fileService;
10
+ constructor(_fileService) {
11
+ this._fileService = _fileService;
12
+ }
13
+ async generate(projectPath, options) {
14
+ // 5. src/main.ts
15
+ const routerImport = options.router ? `\nimport router from './router';` : '';
16
+ const piniaImport = options.pinia ? `\nimport { createPinia } from 'pinia';` : '';
17
+ const tailwindImport = options.tailwind ? `\nimport './assets/style.css';` : '';
18
+ const mainTs = `import { createApp } from 'vue';
19
+ import App from './App.vue';
20
+ import { bootstrap } from './bootstrap';
21
+ import { XENO_SERVICES_KEY } from '@xeno-js/vue';${routerImport}${piniaImport}${tailwindImport}
22
+
23
+ async function mountApp() {
24
+ try {
25
+ const app = createApp(App);
26
+ ${options.pinia ? '\n app.use(createPinia());' : ''}
27
+ const container = await bootstrap(app, router);
28
+ ${options.router ? '\n app.use(router);' : ''}
29
+
30
+
31
+ // Provide the Xeno IoC container globally to all components
32
+ app.provide(XENO_SERVICES_KEY, container);
33
+
34
+ app.mount('#app');
35
+ } catch (error) {
36
+ console.error('Critical error during frontend bootstrap:', error);
37
+ }
38
+ }
39
+
40
+ mountApp();
41
+ `;
42
+ await this._fileService.writeFileRecursive(node_path_1.default.join(projectPath, 'src', 'main.ts'), mainTs);
43
+ }
44
+ }
45
+ exports.MainGenerator = MainGenerator;
@@ -0,0 +1,59 @@
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.PackageJsonVueGenerator = void 0;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ class PackageJsonVueGenerator {
9
+ _fileService;
10
+ constructor(_fileService) {
11
+ this._fileService = _fileService;
12
+ }
13
+ async generate(projectPath, options) {
14
+ const packageJson = {
15
+ name: options.targetDir,
16
+ version: '1.0.0',
17
+ private: true,
18
+ type: 'module',
19
+ scripts: {
20
+ dev: 'vite',
21
+ build: 'vue-tsc -b && vite build',
22
+ preview: 'vite preview',
23
+ g: 'xeno-js generate',
24
+ },
25
+ dependencies: {
26
+ '@xeno-js/vue': 'latest',
27
+ 'vue': '^3.5.0',
28
+ },
29
+ devDependencies: {
30
+ '@types/node': '^20.0.0',
31
+ '@vitejs/plugin-vue': '^5.1.0',
32
+ 'typescript': '^5.5.0',
33
+ 'vite': '^5.4.0',
34
+ 'vue-tsc': '^2.1.0',
35
+ },
36
+ };
37
+ if (options.axios)
38
+ packageJson.dependencies['axios'] = '^1.7.0';
39
+ if (options.cockatiel)
40
+ packageJson.dependencies['cockatiel'] = '^4.0.0';
41
+ if (options.supabase)
42
+ packageJson.dependencies['@supabase/supabase-js'] = '^2.45.0';
43
+ if (options.sentry)
44
+ packageJson.dependencies['@sentry/vue'] = '^8.28.0';
45
+ if (options.pinia)
46
+ packageJson.dependencies['pinia'] = '^2.2.0';
47
+ if (options.router)
48
+ packageJson.dependencies['vue-router'] = '^4.4.0';
49
+ if (options.zod)
50
+ packageJson.dependencies['zod'] = '^4.4.3';
51
+ if (options.tailwind) {
52
+ packageJson.devDependencies['tailwindcss'] = '^4.0.0';
53
+ packageJson.devDependencies['@tailwindcss/vite'] = '^4.0.0';
54
+ }
55
+ const filePath = node_path_1.default.join(projectPath, 'package.json');
56
+ await this._fileService.writeFileRecursive(filePath, JSON.stringify(packageJson, null, 2));
57
+ }
58
+ }
59
+ exports.PackageJsonVueGenerator = PackageJsonVueGenerator;