@azure-net/cli 1.4.2 → 2.0.1

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 (32) hide show
  1. package/bin/azure-net.js +88 -37
  2. package/package.json +1 -1
  3. package/src/commands/generate/generateCrud.js +350 -0
  4. package/src/commands/generate/generateDatasource.js +41 -0
  5. package/src/commands/generate/generateModule.js +23 -0
  6. package/src/commands/generate/generatePresenter.js +113 -0
  7. package/src/commands/generate/generateRepository.js +102 -0
  8. package/src/commands/generate/generateResponse.js +42 -0
  9. package/src/commands/generate/generateSchema.js +95 -0
  10. package/src/commands/generate/generateService.js +93 -0
  11. package/src/commands/generate/index.js +8 -0
  12. package/src/commands/init/index.js +7 -0
  13. package/src/commands/init/initAliases.js +50 -0
  14. package/src/commands/init/initEdges.js +42 -0
  15. package/src/commands/init/initMiddleware.js +43 -0
  16. package/src/commands/init/initSchema.js +19 -0
  17. package/src/commands/init/initStructure.js +79 -0
  18. package/src/commands/init/initTranslations.js +102 -0
  19. package/src/utils/contextUtils.js +53 -0
  20. package/src/utils/fileUtils.js +79 -0
  21. package/src/utils/loadConfig.js +2 -2
  22. package/src/utils/providerUtils.js +107 -0
  23. package/.idea/azure-net-ecosystem-cli.iml +0 -9
  24. package/.idea/modules.xml +0 -8
  25. package/src/commands/generateCrud.js +0 -135
  26. package/src/commands/generateDatasource.js +0 -44
  27. package/src/commands/generateRepo.js +0 -69
  28. package/src/commands/generateRequest.js +0 -95
  29. package/src/commands/generateService.js +0 -77
  30. package/src/commands/generateStructure.js +0 -65
  31. package/src/commands/initAliases.js +0 -101
  32. /package/src/commands/{initLint.js → init/initLint.js} +0 -0
package/bin/azure-net.js CHANGED
@@ -1,36 +1,96 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { Command } from 'commander';
4
- import generateRequest from '../src/commands/generateRequest.js';
5
- import generateDatasource from '../src/commands/generateDatasource.js';
6
- import generateRepo from '../src/commands/generateRepo.js';
7
- import generateService from '../src/commands/generateService.js';
8
- import generateCrud from '../src/commands/generateCrud.js';
9
- import initLint from '../src/commands/initLint.js';
10
- import initStructure from '../src/commands/generateStructure.js';
11
- import initAliases from '../src/commands/initAliases.js';
4
+ import {
5
+ initStructure,
6
+ initAliases,
7
+ initMiddleware,
8
+ initEdges,
9
+ initTranslations,
10
+ initSchema,
11
+ initLint
12
+ } from '../src/commands/init/index.js';
13
+ import {
14
+ generateDatasource,
15
+ generateResponse,
16
+ generateRepository,
17
+ generateService,
18
+ generateSchema,
19
+ generatePresenter,
20
+ generateModule,
21
+ generateCrud
22
+ } from '../src/commands/generate/index.js';
12
23
 
13
24
  const program = new Command();
14
25
 
15
26
  program
16
27
  .name('azure-net')
17
- .description('Universal code generator')
18
- .version('1.0.0');
28
+ .description('Azure-Net CLI generator')
29
+ .version('2.0.0');
19
30
 
31
+ // Init commands
32
+ program
33
+ .command('init:lint')
34
+ .description('Setup linting and commit tools')
35
+ .action(initLint)
36
+
37
+ program
38
+ .command('init:structure')
39
+ .description('Generate base folder structure')
40
+ .action(initStructure);
41
+
42
+ program
43
+ .command('init:aliases')
44
+ .description('Generate alias mappings')
45
+ .action(initAliases);
46
+
47
+ program
48
+ .command('init:middleware')
49
+ .description('Initialize middleware')
50
+ .action(initMiddleware);
51
+
52
+ program
53
+ .command('init:edges')
54
+ .description('Initialize edges-svelte')
55
+ .action(initEdges);
56
+
57
+ program
58
+ .command('init:translations')
59
+ .description('Initialize translations')
60
+ .action(initTranslations);
61
+
62
+ program
63
+ .command('init:schema')
64
+ .description('Initialize schema factory')
65
+ .action(initSchema);
66
+
67
+ program
68
+ .command('init')
69
+ .description('Run all initialization steps')
70
+ .action(async () => {
71
+ await initStructure();
72
+ await initAliases();
73
+ await initEdges();
74
+ await initMiddleware();
75
+ await initTranslations();
76
+ await initSchema();
77
+ });
78
+
79
+ // Generate commands
20
80
  program
21
81
  .command('make:datasource')
22
82
  .description('Generate datasource')
23
83
  .action(generateDatasource);
24
84
 
25
85
  program
26
- .command('make:repo')
27
- .description('Generate repo')
28
- .action(generateRepo);
86
+ .command('make:response')
87
+ .description('Generate response builder')
88
+ .action(generateResponse);
29
89
 
30
90
  program
31
- .command('make:request')
32
- .description('Generate request')
33
- .action(generateRequest);
91
+ .command('make:repo')
92
+ .description('Generate repository')
93
+ .action(generateRepository);
34
94
 
35
95
  program
36
96
  .command('make:service')
@@ -38,32 +98,23 @@ program
38
98
  .action(generateService);
39
99
 
40
100
  program
41
- .command('make:crud')
42
- .description('Generate CRUD Domain/Repo/Service')
43
- .action(generateCrud);
44
-
45
- program
46
- .command('init:lint')
47
- .description('Setup linting and commit tools')
48
- .action(initLint)
101
+ .command('make:schema')
102
+ .description('Generate schema')
103
+ .action(generateSchema);
49
104
 
50
105
  program
51
- .command('init:structure')
52
- .description('Generate base folder structure based on config')
53
- .action(initStructure);
106
+ .command('make:presenter')
107
+ .description('Generate presenter')
108
+ .action(generatePresenter);
54
109
 
55
110
  program
56
- .command('init:aliases')
57
- .description('Generate alias mappings for modules or default architecture')
58
- .action(initAliases);
111
+ .command('make:module')
112
+ .description('Generate complete module')
113
+ .action(generateModule);
59
114
 
60
115
  program
61
- .command('init')
62
- .description('Run all initialization steps: structure, aliases, lint')
63
- .action(async () => {
64
- await initStructure();
65
- await initAliases();
66
- await initLint();
67
- });
116
+ .command('make:crud')
117
+ .description('Generate CRUD module')
118
+ .action(generateCrud);
68
119
 
69
120
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-net/cli",
3
- "version": "1.4.2",
3
+ "version": "2.0.1",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "azure-net": "bin/azure-net.js"
@@ -0,0 +1,350 @@
1
+ import prompts from 'prompts';
2
+ import fs from 'fs/promises';
3
+ import path from 'path';
4
+ import { selectContext, getContextPath, toPascalCase, toCamelCase, getAvailableFiles } from '../../utils/contextUtils.js';
5
+ import { writeIfNotExists, updateIndexTs, ensureIndexExports } from '../../utils/fileUtils.js';
6
+ import { ensureProvider, addToProvider } from '../../utils/providerUtils.js';
7
+
8
+ // Templates for CRUD generation
9
+ const entityTemplate = `export interface I{{name}} {
10
+ \tid: number;
11
+ \t// Add entity fields here
12
+ \tcreated_at: string;
13
+ \tupdated_at: string;
14
+ }`;
15
+
16
+ const portsIndexTemplate = `export interface I{{name}}Collection {
17
+ \tdata: I{{name}}[];
18
+ \ttotal: number;
19
+ }
20
+
21
+ export interface I{{name}}CollectionQuery {
22
+ \tpage?: number;
23
+ \tperPage?: number;
24
+ \t[key: string]: unknown;
25
+ }
26
+
27
+ export interface I{{name}}CreateRequest {
28
+ \t// Add request fields here
29
+ }
30
+
31
+ export interface I{{name}}UpdateRequest {
32
+ \t// Add request fields here
33
+ }`;
34
+
35
+ const repositoryTemplate = `import { {{datasource}} } from '{{datasourceImport}}';
36
+ import type { I{{name}} } from '${{context}}/Domain/Entities/{{name}}';
37
+ import type {
38
+ \tI{{name}}Collection,
39
+ \tI{{name}}CollectionQuery,
40
+ \tI{{name}}CreateRequest,
41
+ \tI{{name}}UpdateRequest
42
+ } from '${{context}}/Domain/Ports/{{name}}';
43
+
44
+ export class {{name}}Repository {
45
+ \tprivate endpoint = '{{endpoint}}';
46
+ \t
47
+ \tconstructor(private {{datasourceVar}}: {{datasource}}) {}
48
+ \t
49
+ \tpublic async collection(query?: I{{name}}CollectionQuery) {
50
+ \t\treturn this.{{datasourceVar}}.createRequest<I{{name}}Collection>(({ http, query: q }) =>
51
+ \t\t\thttp.get(\`\${this.endpoint}\${q.build(query || {})}\`)
52
+ \t\t).then(res => res.getData());
53
+ \t}
54
+ \t
55
+ \tpublic async resource(id: number) {
56
+ \t\treturn this.{{datasourceVar}}.createRequest<I{{name}}>(({ http }) =>
57
+ \t\t\thttp.get(\`\${this.endpoint}/\${id}\`)
58
+ \t\t).then(res => res.getData());
59
+ \t}
60
+ \t
61
+ \tpublic async create(data: I{{name}}CreateRequest) {
62
+ \t\treturn this.{{datasourceVar}}.createRequest<I{{name}}>(({ http }) =>
63
+ \t\t\thttp.post(this.endpoint, { json: data })
64
+ \t\t).then(res => res.getData());
65
+ \t}
66
+ \t
67
+ \tpublic async update(id: number, data: I{{name}}UpdateRequest) {
68
+ \t\treturn this.{{datasourceVar}}.createRequest<I{{name}}>(({ http }) =>
69
+ \t\t\thttp.put(\`\${this.endpoint}/\${id}\`, { json: data })
70
+ \t\t).then(res => res.getData());
71
+ \t}
72
+ \t
73
+ \tpublic async remove(id: number) {
74
+ \t\treturn this.{{datasourceVar}}.createRequest<void>(({ http }) =>
75
+ \t\t\thttp.delete(\`\${this.endpoint}/\${id}\`)
76
+ \t\t).then(() => undefined);
77
+ \t}
78
+ }`;
79
+
80
+ const serviceTemplate = `import { ClassMirror } from '@azure-net/kit';
81
+ import { {{name}}Repository } from '../../Infrastructure/Http/Repositories';
82
+
83
+ export class {{name}}Service extends ClassMirror<{{name}}Repository> {
84
+ \tconstructor(private {{camelName}}Repository: {{name}}Repository) {
85
+ \t\tsuper({{camelName}}Repository);
86
+ \t}
87
+ \t
88
+ \tdeclare collection: {{name}}Repository['collection'];
89
+ \tdeclare resource: {{name}}Repository['resource'];
90
+ \tdeclare create: {{name}}Repository['create'];
91
+ \tdeclare update: {{name}}Repository['update'];
92
+ \tdeclare remove: {{name}}Repository['remove'];
93
+ }`;
94
+
95
+ const createSchemaTemplate = `import { {{schemaFactory}} } from '{{schemaImport}}';
96
+ import type { I{{name}}CreateRequest } from '${{context}}/Domain/Ports/{{name}}';
97
+
98
+ export const Create{{name}}Schema = {{schemaFactory}}<I{{name}}CreateRequest>()
99
+ \t.rules((rules) => ({
100
+ \t\t// Add validation rules here
101
+ \t}))
102
+ \t.create();`;
103
+
104
+ const updateSchemaTemplate = `import { {{schemaFactory}} } from '{{schemaImport}}';
105
+ import type { I{{name}}UpdateRequest } from '${{context}}/Domain/Ports/{{name}}';
106
+
107
+ export const Update{{name}}Schema = {{schemaFactory}}<I{{name}}UpdateRequest>()
108
+ \t.rules((rules) => ({
109
+ \t\t// Add validation rules here
110
+ \t}))
111
+ \t.create();`;
112
+
113
+ const presenterTemplate = `import { {{presenterFactory}} } from '{{presenterImport}}';
114
+ import { ApplicationProvider } from '${{context}}/Application';
115
+ import { Create{{name}}Schema, Update{{name}}Schema } from './Schema';
116
+ import type {
117
+ \tI{{name}}CollectionQuery,
118
+ \tI{{name}}CreateRequest,
119
+ \tI{{name}}UpdateRequest
120
+ } from '${{context}}/Domain/Ports/{{name}}';
121
+
122
+ export const {{name}}Presenter = {{presenterFactory}}('{{name}}Presenter', ({ createAsyncResource, createAsyncAction }) => {
123
+ \tconst { {{name}}Service } = ApplicationProvider();
124
+ \t
125
+ \tconst collection = async (query?: I{{name}}CollectionQuery) =>
126
+ \t\tawait createAsyncResource({{name}}Service.collection(query));
127
+ \t
128
+ \tconst resource = async (id: number) =>
129
+ \t\tawait createAsyncResource({{name}}Service.resource(id));
130
+ \t
131
+ \tconst create = async (request: I{{name}}CreateRequest) =>
132
+ \t\tawait createAsyncAction({{name}}Service.create(Create{{name}}Schema.from(request).json()));
133
+ \t
134
+ \tconst update = async (id: number, request: I{{name}}UpdateRequest) =>
135
+ \t\tawait createAsyncAction({{name}}Service.update(id, Update{{name}}Schema.from(request).json()));
136
+ \t
137
+ \tconst remove = async (id: number) =>
138
+ \t\tawait createAsyncAction({{name}}Service.remove(id));
139
+ \t
140
+ \treturn { collection, resource, create, update, remove };
141
+ });`;
142
+
143
+ export default async function generateCrud() {
144
+ const context = await selectContext('Select context for CRUD module:');
145
+
146
+ if (context === 'core') {
147
+ console.error('❌ Cannot create CRUD in core. Choose a specific context.');
148
+ return;
149
+ }
150
+
151
+ const { name } = await prompts({
152
+ type: 'text',
153
+ name: 'name',
154
+ message: 'Entity name (PascalCase):'
155
+ });
156
+
157
+ const { endpoint } = await prompts({
158
+ type: 'text',
159
+ name: 'endpoint',
160
+ message: 'API endpoint (e.g. /api/users):'
161
+ });
162
+
163
+ // Get available datasources
164
+ const contextPath = getContextPath(context);
165
+ const coreDatasources = await getAvailableFiles(
166
+ path.join(process.cwd(), 'src/app/core/Datasource')
167
+ );
168
+ const contextDatasources = await getAvailableFiles(
169
+ path.join(contextPath, 'Infrastructure/Http/Datasource')
170
+ );
171
+
172
+ const allDatasources = [
173
+ ...coreDatasources.map(d => ({ title: `${d} (core)`, value: { name: d, from: 'core' } })),
174
+ ...contextDatasources.map(d => ({ title: `${d} (${context})`, value: { name: d, from: context } }))
175
+ ];
176
+
177
+ const { datasource } = await prompts({
178
+ type: 'select',
179
+ name: 'datasource',
180
+ message: 'Select datasource:',
181
+ choices: allDatasources
182
+ });
183
+
184
+ // Get schema and presenter factories
185
+ const coreSchemas = await getAvailableFiles(
186
+ path.join(process.cwd(), 'src/app/core/Schema')
187
+ );
188
+
189
+ const { schemaType } = await prompts({
190
+ type: 'select',
191
+ name: 'schemaType',
192
+ message: 'Select schema factory:',
193
+ choices: [
194
+ { title: 'Use createSchemaFactory from package', value: 'package' },
195
+ ...coreSchemas.map(s => ({ title: `Use ${s} from core`, value: s }))
196
+ ]
197
+ });
198
+
199
+ const corePresenters = await getAvailableFiles(
200
+ path.join(process.cwd(), 'src/app/core/Presenter')
201
+ );
202
+
203
+ const { presenterType } = await prompts({
204
+ type: 'select',
205
+ name: 'presenterType',
206
+ message: 'Select presenter factory:',
207
+ choices: [
208
+ { title: 'Use createPresenter from package', value: 'package' },
209
+ ...corePresenters.map(p => ({ title: `Use ${p} from core`, value: p }))
210
+ ]
211
+ });
212
+
213
+ const pascalName = toPascalCase(name);
214
+ const camelName = toCamelCase(name);
215
+ const contextName = toPascalCase(context);
216
+
217
+ console.log('\n🚀 Generating CRUD module...\n');
218
+
219
+ // 1. Create Entity
220
+ const entityPath = path.join(contextPath, 'Domain', 'Entities', pascalName);
221
+ await writeIfNotExists(
222
+ path.join(entityPath, 'index.ts'),
223
+ entityTemplate.replace(/{{name}}/g, pascalName)
224
+ );
225
+
226
+ // 2. Create Ports
227
+ const portsPath = path.join(contextPath, 'Domain', 'Ports', pascalName);
228
+ await writeIfNotExists(
229
+ path.join(portsPath, 'index.ts'),
230
+ portsIndexTemplate
231
+ .replace(/{{name}}/g, pascalName)
232
+ .replace(/{{context}}/g, context)
233
+ );
234
+
235
+ // 3. Create Repository
236
+ const repoPath = path.join(contextPath, 'Infrastructure', 'Http', 'Repositories');
237
+ const datasourceImport = datasource.from === 'core'
238
+ ? '$core/Datasource'
239
+ : `$${context}/Infrastructure/Http/Datasource`;
240
+
241
+ await writeIfNotExists(
242
+ path.join(repoPath, `${pascalName}Repository.ts`),
243
+ repositoryTemplate
244
+ .replace(/{{name}}/g, pascalName)
245
+ .replace(/{{context}}/g, context)
246
+ .replace(/{{endpoint}}/g, endpoint)
247
+ .replace(/{{datasource}}/g, datasource.name)
248
+ .replace(/{{datasourceImport}}/g, datasourceImport)
249
+ .replace(/{{datasourceVar}}/g, toCamelCase(datasource.name))
250
+ );
251
+ await updateIndexTs(repoPath);
252
+
253
+ // 4. Create Service
254
+ const servicePath = path.join(contextPath, 'Application', 'Services');
255
+ await writeIfNotExists(
256
+ path.join(servicePath, `${pascalName}Service.ts`),
257
+ serviceTemplate
258
+ .replace(/{{name}}/g, pascalName)
259
+ .replace(/{{camelName}}/g, camelName)
260
+ );
261
+ await updateIndexTs(servicePath);
262
+
263
+ // 5. Create Delivery module structure
264
+ const deliveryModulePath = path.join(contextPath, 'Delivery', pascalName);
265
+ const schemaPath = path.join(deliveryModulePath, 'Schema');
266
+
267
+ // Create schemas
268
+ const schemaFactory = schemaType === 'package' ? 'createSchemaFactory' : schemaType;
269
+ const schemaImport = schemaType === 'package'
270
+ ? '@azure-net/kit'
271
+ : '$core/Schema';
272
+
273
+ await writeIfNotExists(
274
+ path.join(schemaPath, `Create${pascalName}Schema.ts`),
275
+ createSchemaTemplate
276
+ .replace(/{{name}}/g, pascalName)
277
+ .replace(/{{context}}/g, context)
278
+ .replace(/{{schemaFactory}}/g, schemaFactory)
279
+ .replace(/{{schemaImport}}/g, schemaImport)
280
+ );
281
+
282
+ await writeIfNotExists(
283
+ path.join(schemaPath, `Update${pascalName}Schema.ts`),
284
+ updateSchemaTemplate
285
+ .replace(/{{name}}/g, pascalName)
286
+ .replace(/{{context}}/g, context)
287
+ .replace(/{{schemaFactory}}/g, schemaFactory)
288
+ .replace(/{{schemaImport}}/g, schemaImport)
289
+ );
290
+ await updateIndexTs(schemaPath);
291
+
292
+ // 6. Create Presenter
293
+ const presenterFactory = presenterType === 'package' ? 'createPresenter' : presenterType;
294
+ const presenterImport = presenterType === 'package'
295
+ ? '@azure-net/kit'
296
+ : '$core/Presenter';
297
+
298
+ await writeIfNotExists(
299
+ path.join(deliveryModulePath, `${pascalName}Presenter.ts`),
300
+ presenterTemplate
301
+ .replace(/{{name}}/g, pascalName)
302
+ .replace(/{{context}}/g, context)
303
+ .replace(/{{presenterFactory}}/g, presenterFactory)
304
+ .replace(/{{presenterImport}}/g, presenterImport)
305
+ );
306
+
307
+ // Create module index
308
+ await writeIfNotExists(
309
+ path.join(deliveryModulePath, 'index.ts'),
310
+ `export * from './${pascalName}Presenter';\nexport * from './Schema';`
311
+ );
312
+
313
+ // 7. Setup Providers
314
+ // Ensure DatasourceProvider
315
+ const datasourceProviderPath = path.join(contextPath, 'Infrastructure', 'Providers', 'DatasourceProvider.ts');
316
+ if (!(await fs.access(datasourceProviderPath).then(() => true).catch(() => false))) {
317
+ const datasourceProviderContent = `import { createBoundaryProvider } from '@azure-net/kit';
318
+ import { ${datasource.name} } from '${datasource.from === 'core' ? '$core/Datasource' : '../Http/Datasource'}';
319
+
320
+ export const DatasourceProvider = createBoundaryProvider('${contextName}DatasourceProvider', () => ({
321
+ \t${datasource.name}: () => new ${datasource.name}()
322
+ }));`;
323
+ await writeIfNotExists(datasourceProviderPath, datasourceProviderContent);
324
+ await updateIndexTs(path.dirname(datasourceProviderPath));
325
+ }
326
+
327
+ // Ensure InfrastructureProvider
328
+ const infraProvider = await ensureProvider(context, 'Infrastructure', {});
329
+ await addToProvider(
330
+ infraProvider.path,
331
+ `${pascalName}Repository`,
332
+ '../Http/Repositories',
333
+ `DatasourceProvider.${datasource.name}`
334
+ );
335
+
336
+ // Ensure ApplicationProvider
337
+ const appProvider = await ensureProvider(context, 'Application', { infrastructure: true });
338
+ await addToProvider(
339
+ appProvider.path,
340
+ `${pascalName}Service`,
341
+ '../Services',
342
+ `InfrastructureProvider.${pascalName}Repository`
343
+ );
344
+
345
+ // Update all layer indexes
346
+ await ensureIndexExports(path.join(contextPath, 'Infrastructure'));
347
+ await ensureIndexExports(path.join(contextPath, 'Application'));
348
+
349
+ console.log(`✅ CRUD module for ${pascalName} created successfully!`);
350
+ }
@@ -0,0 +1,41 @@
1
+ import prompts from 'prompts';
2
+ import { selectContext, getContextPath, toPascalCase } from '../../utils/contextUtils.js';
3
+ import { writeIfNotExists, updateIndexTs } from '../../utils/fileUtils.js';
4
+ import path from 'path';
5
+
6
+ const datasourceTemplate = `import { BaseHttpDatasource } from '@azure-net/kit/infra';
7
+ import { HttpService } from '@azure-net/kit/infra';
8
+
9
+ export class {{name}}Datasource extends BaseHttpDatasource {
10
+ \tconstructor() {
11
+ \t\tsuper({
12
+ \t\t\thttp: new HttpService({
13
+ \t\t\t\tbaseUrl: 'https://api.example.com'
14
+ \t\t\t})
15
+ \t\t});
16
+ \t}
17
+ }`;
18
+
19
+ export default async function generateDatasource() {
20
+ const context = await selectContext();
21
+
22
+ const { name } = await prompts({
23
+ type: 'text',
24
+ name: 'name',
25
+ message: 'Datasource name (without "Datasource" suffix):'
26
+ });
27
+
28
+ const pascalName = toPascalCase(name);
29
+ const contextPath = getContextPath(context);
30
+ const datasourcePath = context === 'core'
31
+ ? path.join(contextPath, 'Datasource')
32
+ : path.join(contextPath, 'Infrastructure', 'Http', 'Datasource');
33
+
34
+ const content = datasourceTemplate.replace(/{{name}}/g, pascalName);
35
+ const filePath = path.join(datasourcePath, `${pascalName}Datasource.ts`);
36
+
37
+ await writeIfNotExists(filePath, content);
38
+ await updateIndexTs(datasourcePath);
39
+
40
+ console.log(`✅ Datasource created at ${filePath}`);
41
+ }
@@ -0,0 +1,23 @@
1
+ import prompts from 'prompts';
2
+ import generateRepository from './generateRepository.js';
3
+ import generateService from './generateService.js';
4
+ import generatePresenter from './generatePresenter.js';
5
+ import generateSchema from './generateSchema.js';
6
+
7
+ export default async function generateModule() {
8
+ console.log('🚀 Generating complete module...\n');
9
+
10
+ const { confirm } = await prompts({
11
+ type: 'confirm',
12
+ name: 'confirm',
13
+ message: 'This will create repository, service, presenter and schemas. Continue?'
14
+ });
15
+
16
+ if (confirm) {
17
+ await generateRepository();
18
+ await generateService();
19
+ await generatePresenter();
20
+ await generateSchema(); // Create schema
21
+ await generateSchema(); // Update schema
22
+ }
23
+ }
@@ -0,0 +1,113 @@
1
+ import prompts from 'prompts';
2
+ import path from 'path';
3
+ import { selectContext, getContextPath, toPascalCase, getAvailableFiles } from '../../utils/contextUtils.js';
4
+ import { writeIfNotExists, updateIndexTs } from '../../utils/fileUtils.js';
5
+
6
+ const presenterWithCoreTemplate = `import { {{corePresenter}} } from '$core/Presenter';
7
+ {{serviceImport}}
8
+
9
+ export const {{name}}Presenter = {{corePresenter}}('{{name}}Presenter', ({ createAsyncResource, createAsyncAction }) => {
10
+ \t{{serviceInit}}
11
+ \t
12
+ \tconst example = async () => {
13
+ \t\t// Implement presenter logic
14
+ \t\treturn await createAsyncResource(Promise.resolve({}));
15
+ \t};
16
+ \t
17
+ \treturn { example };
18
+ });`;
19
+
20
+ const presenterWithPackageTemplate = `import { createPresenter } from '@azure-net/kit';
21
+ {{serviceImport}}
22
+
23
+ export const {{name}}Presenter = createPresenter('{{name}}Presenter', () => {
24
+ \t{{serviceInit}}
25
+ \t
26
+ \tconst example = async () => {
27
+ \t\t// Implement presenter logic
28
+ \t\treturn {};
29
+ \t};
30
+ \t
31
+ \treturn { example };
32
+ });`;
33
+
34
+ export default async function generatePresenter() {
35
+ const context = await selectContext('Select context for presenter:');
36
+
37
+ if (context === 'core') {
38
+ console.error('❌ Cannot create presenter in core. Choose a specific context.');
39
+ return;
40
+ }
41
+
42
+ const { name } = await prompts({
43
+ type: 'text',
44
+ name: 'name',
45
+ message: 'Module name (will create folder in Delivery):'
46
+ });
47
+
48
+ // Check for core presenters
49
+ const corePresenters = await getAvailableFiles(
50
+ path.join(process.cwd(), 'src/app/core/Presenter')
51
+ );
52
+
53
+ const presenterChoices = [
54
+ { title: 'Use createPresenter from package', value: 'package' },
55
+ ...corePresenters.map(p => ({ title: `Use ${p} from core`, value: p }))
56
+ ];
57
+
58
+ const { presenterType } = await prompts({
59
+ type: 'select',
60
+ name: 'presenterType',
61
+ message: 'Select presenter factory:',
62
+ choices: presenterChoices
63
+ });
64
+
65
+ // Get available services
66
+ const contextPath = getContextPath(context);
67
+ const services = await getAvailableFiles(
68
+ path.join(contextPath, 'Application', 'Services')
69
+ );
70
+
71
+ const serviceChoices = [
72
+ { title: 'Without service', value: null },
73
+ ...services.map(s => ({ title: `${s}`, value: s }))
74
+ ];
75
+
76
+ const { service } = await prompts({
77
+ type: 'select',
78
+ name: 'service',
79
+ message: 'Select service (optional):',
80
+ choices: serviceChoices
81
+ });
82
+
83
+ const pascalName = toPascalCase(name);
84
+ const modulePath = path.join(contextPath, 'Delivery', pascalName);
85
+ const filePath = path.join(modulePath, `${pascalName}Presenter.ts`);
86
+
87
+ const serviceImport = service
88
+ ? `import { ApplicationProvider } from '$${context}/Application';`
89
+ : '';
90
+
91
+ const serviceInit = service
92
+ ? `const { ${service} } = ApplicationProvider();`
93
+ : '';
94
+
95
+ const content = presenterType === 'package'
96
+ ? presenterWithPackageTemplate
97
+ .replace(/{{name}}/g, pascalName)
98
+ .replace(/{{serviceImport}}/g, serviceImport)
99
+ .replace(/{{serviceInit}}/g, serviceInit)
100
+ : presenterWithCoreTemplate
101
+ .replace(/{{name}}/g, pascalName)
102
+ .replace(/{{corePresenter}}/g, presenterType)
103
+ .replace(/{{serviceImport}}/g, serviceImport)
104
+ .replace(/{{serviceInit}}/g, serviceInit);
105
+
106
+ await writeIfNotExists(filePath, content);
107
+ await writeIfNotExists(
108
+ path.join(modulePath, 'index.ts'),
109
+ `export * from './${pascalName}Presenter';`
110
+ );
111
+
112
+ console.log(`✅ Presenter created at ${filePath}`);
113
+ }