@azure-net/cli 2.0.5 → 2.0.7

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.
@@ -1,7 +1,7 @@
1
- import { writeIfNotExists, updateIndexTs, injectIntoFile } from '../../utils/fileUtils.js';
1
+ import { writeIfNotExists, injectIntoFile } from '../../utils/fileUtils.js';
2
2
  import path from 'path';
3
3
 
4
- const translationsPath = path.join(process.cwd(), 'src/app/core/Translation');
4
+ const translationsPath = path.join(process.cwd(), 'src/app/shared/Translation');
5
5
  const layoutServerPath = path.join(process.cwd(), 'src/routes/+layout.server.ts');
6
6
  const layoutTsPath = path.join(process.cwd(), 'src/routes/+layout.ts');
7
7
 
@@ -58,7 +58,7 @@ export default async function initTranslations() {
58
58
  await injectIntoFile(
59
59
  path.join(process.cwd(), 'src/hooks.server.ts'),
60
60
  'import',
61
- `import { Translation } from '$core';`,
61
+ `import { Translation } from '$shared';`,
62
62
  'before'
63
63
  );
64
64
 
@@ -87,7 +87,7 @@ export default async function initTranslations() {
87
87
  await injectIntoFile(
88
88
  layoutTsPath,
89
89
  'import',
90
- `import { Translation } from '$core';\nimport { browser } from '$app/environment';`,
90
+ `import { Translation } from '$shared';\nimport { browser } from '$app/environment';`,
91
91
  'before'
92
92
  );
93
93
 
@@ -4,7 +4,7 @@ import prompts from 'prompts';
4
4
  import { loadUserConfig } from './loadConfig.js';
5
5
 
6
6
  const CONTEXTS_PATH = path.join(process.cwd(), 'src/app/contexts');
7
- const CORE_PATH = path.join(process.cwd(), 'src/app/core');
7
+ const SHARED_PATH = path.join(process.cwd(), 'src/app/shared');
8
8
 
9
9
  export async function selectContext(message = 'Select context:') {
10
10
  const config = await loadUserConfig();
@@ -16,7 +16,7 @@ export async function selectContext(message = 'Select context:') {
16
16
  message,
17
17
  choices: [
18
18
  ...contexts.map(c => ({ title: c, value: c })),
19
- { title: 'core (shared)', value: 'core' }
19
+ { title: 'shared (former core)', value: 'shared' }
20
20
  ]
21
21
  });
22
22
 
@@ -24,8 +24,8 @@ export async function selectContext(message = 'Select context:') {
24
24
  }
25
25
 
26
26
  export function getContextPath(context) {
27
- return context === 'core'
28
- ? CORE_PATH
27
+ return context === 'shared'
28
+ ? SHARED_PATH
29
29
  : path.join(CONTEXTS_PATH, context);
30
30
  }
31
31
 
@@ -40,6 +40,27 @@ export async function getAvailableFiles(dir, pattern = '.ts') {
40
40
  }
41
41
  }
42
42
 
43
+ export async function getApplicationProviderServices(context) {
44
+ const contextPath = getContextPath(context);
45
+ const providerPath = path.join(contextPath, 'Application/Providers/ApplicationProvider.ts');
46
+
47
+ try {
48
+ const content = await fs.readFile(providerPath, 'utf-8');
49
+ // Extract service names from ApplicationProvider
50
+ const serviceRegex = /(\w+Service):\s*\(/g;
51
+ const services = [];
52
+ let match;
53
+
54
+ while ((match = serviceRegex.exec(content)) !== null) {
55
+ services.push(match[1]);
56
+ }
57
+
58
+ return services;
59
+ } catch {
60
+ return [];
61
+ }
62
+ }
63
+
43
64
  // Fixed to preserve PascalCase properly
44
65
  export function toPascalCase(str) {
45
66
  // If already in PascalCase with multiple words, preserve it
@@ -1,400 +0,0 @@
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, ensureDatasourceProvider } from '../../utils/providerUtils.js';
7
-
8
- // Templates remain the same as before...
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 = `import type { I{{name}} } from '\${{context}}/Domain/Entities/{{name}}';
17
-
18
- export interface I{{name}}Collection {
19
- \tdata: I{{name}}[];
20
- \ttotal: number;
21
- }
22
-
23
- export interface I{{name}}CollectionQuery {
24
- \tpage?: number;
25
- \tperPage?: number;
26
- \t[key: string]: unknown;
27
- }
28
-
29
- export interface I{{name}}CreateRequest {
30
- \t// Add request fields here
31
- \t[key: string]: unknown;
32
- }
33
-
34
- export interface I{{name}}UpdateRequest {
35
- \t// Add request fields here
36
- \t[key: string]: unknown;
37
- }`;
38
-
39
- const repositoryTemplate = `import { {{datasource}} } from '{{datasourceImport}}';
40
- import type { I{{name}} } from '\${{context}}/Domain/Entities/{{name}}';
41
- import type {
42
- \tI{{name}}Collection,
43
- \tI{{name}}CollectionQuery,
44
- \tI{{name}}CreateRequest,
45
- \tI{{name}}UpdateRequest
46
- } from '\${{context}}/Domain/Ports/{{name}}';
47
-
48
- export class {{name}}Repository {
49
- \tprivate endpoint = '{{endpoint}}';
50
- \t
51
- \tconstructor(private {{datasourceVar}}: {{datasource}}) {}
52
- \t
53
- \tpublic async collection(query?: I{{name}}CollectionQuery) {
54
- \t\treturn this.{{datasourceVar}}.createRequest<I{{name}}Collection>(({ http, query: q }) =>
55
- \t\t\thttp.get(\`\${this.endpoint}\${q.build(query || {})}\`)
56
- \t\t).then(res => res.getData());
57
- \t}
58
- \t
59
- \tpublic async resource(id: number) {
60
- \t\treturn this.{{datasourceVar}}.createRequest<I{{name}}>(({ http }) =>
61
- \t\t\thttp.get(\`\${this.endpoint}/\${id}\`)
62
- \t\t).then(res => res.getData());
63
- \t}
64
- \t
65
- \tpublic async create(data: I{{name}}CreateRequest) {
66
- \t\treturn this.{{datasourceVar}}.createRequest<I{{name}}>(({ http }) =>
67
- \t\t\thttp.post(this.endpoint, { json: data })
68
- \t\t).then(res => res.getData());
69
- \t}
70
- \t
71
- \tpublic async update(id: number, data: I{{name}}UpdateRequest) {
72
- \t\treturn this.{{datasourceVar}}.createRequest<I{{name}}>(({ http }) =>
73
- \t\t\thttp.put(\`\${this.endpoint}/\${id}\`, { json: data })
74
- \t\t).then(res => res.getData());
75
- \t}
76
- \t
77
- \tpublic async remove(id: number) {
78
- \t\treturn this.{{datasourceVar}}.createRequest<void>(({ http }) =>
79
- \t\t\thttp.delete(\`\${this.endpoint}/\${id}\`)
80
- \t\t).then(() => undefined);
81
- \t}
82
- }`;
83
-
84
- const serviceTemplate = `import { ClassMirror } from '@azure-net/kit';
85
- import { {{name}}Repository } from '\${{context}}/Infrastructure/Http/Repositories';
86
-
87
- export class {{name}}Service extends ClassMirror<{{name}}Repository> {
88
- \tconstructor(private {{camelName}}Repository: {{name}}Repository) {
89
- \t\tsuper({{camelName}}Repository);
90
- \t}
91
- \t
92
- \tdeclare collection: {{name}}Repository['collection'];
93
- \tdeclare resource: {{name}}Repository['resource'];
94
- \tdeclare create: {{name}}Repository['create'];
95
- \tdeclare update: {{name}}Repository['update'];
96
- \tdeclare remove: {{name}}Repository['remove'];
97
- }`;
98
-
99
- const createSchemaTemplate = `import { {{schemaFactory}} } from '{{schemaImport}}';
100
- import type { I{{name}}CreateRequest } from '\${{context}}/Domain/Ports/{{name}}';
101
-
102
- export const Create{{name}}Schema = {{schemaFactory}}<I{{name}}CreateRequest>()
103
- \t.rules((rules) => ({
104
- \t\t// Add validation rules here
105
- \t}))
106
- \t.create();`;
107
-
108
- const updateSchemaTemplate = `import { {{schemaFactory}} } from '{{schemaImport}}';
109
- import type { I{{name}}UpdateRequest } from '\${{context}}/Domain/Ports/{{name}}';
110
-
111
- export const Update{{name}}Schema = {{schemaFactory}}<I{{name}}UpdateRequest>()
112
- \t.rules((rules) => ({
113
- \t\t// Add validation rules here
114
- \t}))
115
- \t.create();`;
116
-
117
- const presenterWithCoreTemplate = `import { {{presenterFactory}} } from '\$core/Presenter';
118
- import { ApplicationProvider } from '\${{context}}/Application';
119
- import { Create{{name}}Schema, Update{{name}}Schema } from './Schema';
120
- import type {
121
- \tI{{name}}CollectionQuery,
122
- \tI{{name}}CreateRequest,
123
- \tI{{name}}UpdateRequest
124
- } from '\${{context}}/Domain/Ports/{{name}}';
125
-
126
- export const {{name}}Presenter = {{presenterFactory}}('{{name}}Presenter', ({ createAsyncResource, createAsyncAction }) => {
127
- \tconst { {{name}}Service } = ApplicationProvider();
128
- \t
129
- \tconst collection = async (query?: I{{name}}CollectionQuery) =>
130
- \t\tawait createAsyncResource({{name}}Service.collection(query));
131
- \t
132
- \tconst resource = async (id: number) =>
133
- \t\tawait createAsyncResource({{name}}Service.resource(id));
134
- \t
135
- \tconst create = async (request: I{{name}}CreateRequest) =>
136
- \t\tawait createAsyncAction({{name}}Service.create(Create{{name}}Schema.from(request).json()));
137
- \t
138
- \tconst update = async (id: number, request: I{{name}}UpdateRequest) =>
139
- \t\tawait createAsyncAction({{name}}Service.update(id, Update{{name}}Schema.from(request).json()));
140
- \t
141
- \tconst remove = async (id: number) =>
142
- \t\tawait createAsyncAction({{name}}Service.remove(id));
143
- \t
144
- \treturn { collection, resource, create, update, remove };
145
- });`;
146
-
147
- const presenterWithoutCoreTemplate = `import { createPresenter } from '@azure-net/kit';
148
- import { ApplicationProvider } from '\${{context}}/Application';
149
- import { Create{{name}}Schema, Update{{name}}Schema } from './Schema';
150
- import type {
151
- \tI{{name}}CollectionQuery,
152
- \tI{{name}}CreateRequest,
153
- \tI{{name}}UpdateRequest
154
- } from '\${{context}}/Domain/Ports/{{name}}';
155
-
156
- export const {{name}}Presenter = createPresenter('{{name}}Presenter', () => {
157
- \tconst { {{name}}Service } = ApplicationProvider();
158
- \t
159
- \tconst collection = async (query?: I{{name}}CollectionQuery) =>
160
- \t\tawait {{name}}Service.collection(query);
161
- \t
162
- \tconst resource = async (id: number) =>
163
- \t\tawait {{name}}Service.resource(id);
164
- \t
165
- \tconst create = async (request: I{{name}}CreateRequest) =>
166
- \t\tawait {{name}}Service.create(Create{{name}}Schema.from(request).json());
167
- \t
168
- \tconst update = async (id: number, request: I{{name}}UpdateRequest) =>
169
- \t\tawait {{name}}Service.update(id, Update{{name}}Schema.from(request).json());
170
- \t
171
- \tconst remove = async (id: number) =>
172
- \t\tawait {{name}}Service.remove(id);
173
- \t
174
- \treturn { collection, resource, create, update, remove };
175
- });`;
176
-
177
- export default async function generateCrud() {
178
- const context = await selectContext('Select context for CRUD module:');
179
-
180
- if (context === 'core') {
181
- console.error('āŒ Cannot create CRUD in core. Choose a specific context.');
182
- return;
183
- }
184
-
185
- const { name } = await prompts({
186
- type: 'text',
187
- name: 'name',
188
- message: 'Entity name (PascalCase):'
189
- });
190
-
191
- const { endpoint } = await prompts({
192
- type: 'text',
193
- name: 'endpoint',
194
- message: 'API endpoint (e.g. /api/users):'
195
- });
196
-
197
- // Get available datasources
198
- const contextPath = getContextPath(context);
199
- const coreDatasources = await getAvailableFiles(
200
- path.join(process.cwd(), 'src/app/core/Datasource')
201
- );
202
- const contextDatasources = await getAvailableFiles(
203
- path.join(contextPath, 'Infrastructure/Http/Datasource')
204
- );
205
-
206
- const allDatasources = [
207
- ...coreDatasources.map(d => ({ title: `${d} (core)`, value: { name: d, from: 'core' } })),
208
- ...contextDatasources.map(d => ({ title: `${d} (${context})`, value: { name: d, from: context } }))
209
- ];
210
-
211
- const { datasource } = await prompts({
212
- type: 'select',
213
- name: 'datasource',
214
- message: 'Select datasource:',
215
- choices: allDatasources
216
- });
217
-
218
- // Get schema and presenter factories
219
- const coreSchemas = await getAvailableFiles(
220
- path.join(process.cwd(), 'src/app/core/Schema')
221
- );
222
-
223
- const { schemaType } = await prompts({
224
- type: 'select',
225
- name: 'schemaType',
226
- message: 'Select schema factory:',
227
- choices: [
228
- { title: 'Use createSchemaFactory from package', value: 'package' },
229
- ...coreSchemas.map(s => ({ title: `Use ${s} from core`, value: s }))
230
- ]
231
- });
232
-
233
- const corePresenters = await getAvailableFiles(
234
- path.join(process.cwd(), 'src/app/core/Presenter')
235
- );
236
-
237
- const { presenterType } = await prompts({
238
- type: 'select',
239
- name: 'presenterType',
240
- message: 'Select presenter factory:',
241
- choices: [
242
- { title: 'Use createPresenter from package', value: 'package' },
243
- ...corePresenters.map(p => ({ title: `Use ${p} from core`, value: p }))
244
- ]
245
- });
246
-
247
- const pascalName = toPascalCase(name);
248
- const camelName = toCamelCase(name);
249
- const contextName = toPascalCase(context);
250
-
251
- console.log('\nšŸš€ Generating CRUD module...\n');
252
-
253
- // 1. Create Entity
254
- const entityPath = path.join(contextPath, 'Domain/Entities', pascalName);
255
- await writeIfNotExists(
256
- path.join(entityPath, 'index.ts'),
257
- entityTemplate.replace(/{{name}}/g, pascalName)
258
- );
259
-
260
- // 2. Create Ports
261
- const portsPath = path.join(contextPath, 'Domain/Ports', pascalName);
262
- await writeIfNotExists(
263
- path.join(portsPath, 'index.ts'),
264
- portsIndexTemplate
265
- .replace(/{{name}}/g, pascalName)
266
- .replace(/{{context}}/g, context)
267
- );
268
-
269
- // 3. Create Repository
270
- const repoPath = path.join(contextPath, 'Infrastructure/Http/Repositories');
271
- const datasourceImport = datasource.from === 'core'
272
- ? '$core/Datasource'
273
- : `\$${context}/Infrastructure/Http/Datasource`;
274
-
275
- await writeIfNotExists(
276
- path.join(repoPath, `${pascalName}Repository.ts`),
277
- repositoryTemplate
278
- .replace(/{{name}}/g, pascalName)
279
- .replace(/{{context}}/g, context)
280
- .replace(/{{endpoint}}/g, endpoint)
281
- .replace(/{{datasource}}/g, datasource.name)
282
- .replace(/{{datasourceImport}}/g, datasourceImport)
283
- .replace(/{{datasourceVar}}/g, toCamelCase(datasource.name))
284
- );
285
- await updateIndexTs(repoPath);
286
-
287
- // 4. Create Service
288
- const servicePath = path.join(contextPath, 'Application/Services');
289
- await writeIfNotExists(
290
- path.join(servicePath, `${pascalName}Service.ts`),
291
- serviceTemplate
292
- .replace(/{{name}}/g, pascalName)
293
- .replace(/{{camelName}}/g, camelName)
294
- .replace(/{{context}}/g, context)
295
- );
296
- await updateIndexTs(servicePath);
297
-
298
- // 5. Create Delivery module structure
299
- const deliveryModulePath = path.join(contextPath, 'Delivery', pascalName);
300
- const schemaPath = path.join(deliveryModulePath, 'Schema');
301
-
302
- // Create schemas
303
- const schemaFactory = schemaType === 'package' ? 'Schema' : schemaType;
304
- const schemaImport = schemaType === 'package'
305
- ? '@azure-net/kit'
306
- : '$core/Schema';
307
-
308
- if (schemaType === 'package') {
309
- const schemaImportFull = `import { createSchemaFactory } from '@azure-net/kit';
310
- import { createRules, validationMessagesI18n } from '@azure-net/kit/schema';
311
-
312
- const Schema = createSchemaFactory(createRules(validationMessagesI18n));`;
313
-
314
- await writeIfNotExists(
315
- path.join(schemaPath, `Create${pascalName}Schema.ts`),
316
- schemaImportFull + '\n' + createSchemaTemplate
317
- .replace('import { {{schemaFactory}} } from \'{{schemaImport}}\';\n', '')
318
- .replace(/{{name}}/g, pascalName)
319
- .replace(/{{context}}/g, context)
320
- .replace(/{{schemaFactory}}/g, 'Schema')
321
- );
322
-
323
- await writeIfNotExists(
324
- path.join(schemaPath, `Update${pascalName}Schema.ts`),
325
- schemaImportFull + '\n' + updateSchemaTemplate
326
- .replace('import { {{schemaFactory}} } from \'{{schemaImport}}\';\n', '')
327
- .replace(/{{name}}/g, pascalName)
328
- .replace(/{{context}}/g, context)
329
- .replace(/{{schemaFactory}}/g, 'Schema')
330
- );
331
- } else {
332
- await writeIfNotExists(
333
- path.join(schemaPath, `Create${pascalName}Schema.ts`),
334
- createSchemaTemplate
335
- .replace(/{{name}}/g, pascalName)
336
- .replace(/{{context}}/g, context)
337
- .replace(/{{schemaFactory}}/g, schemaFactory)
338
- .replace(/{{schemaImport}}/g, schemaImport)
339
- );
340
-
341
- await writeIfNotExists(
342
- path.join(schemaPath, `Update${pascalName}Schema.ts`),
343
- updateSchemaTemplate
344
- .replace(/{{name}}/g, pascalName)
345
- .replace(/{{context}}/g, context)
346
- .replace(/{{schemaFactory}}/g, schemaFactory)
347
- .replace(/{{schemaImport}}/g, schemaImport)
348
- );
349
- }
350
- await updateIndexTs(schemaPath);
351
-
352
- // 6. Create Presenter
353
- const presenterTemplate = presenterType === 'package'
354
- ? presenterWithoutCoreTemplate
355
- : presenterWithCoreTemplate;
356
-
357
- const presenterFactory = presenterType === 'package' ? 'createPresenter' : presenterType;
358
-
359
- await writeIfNotExists(
360
- path.join(deliveryModulePath, `${pascalName}Presenter.ts`),
361
- presenterTemplate
362
- .replace(/{{name}}/g, pascalName)
363
- .replace(/{{context}}/g, context)
364
- .replace(/{{presenterFactory}}/g, presenterFactory)
365
- );
366
-
367
- // Create module index
368
- await writeIfNotExists(
369
- path.join(deliveryModulePath, 'index.ts'),
370
- `export * from './${pascalName}Presenter';\nexport * from './Schema';`
371
- );
372
-
373
- // 7. Setup Providers
374
- // Ensure DatasourceProvider
375
- await ensureDatasourceProvider(context, datasource.name, datasource.from === 'core');
376
-
377
- // Ensure InfrastructureProvider
378
- const infraProvider = await ensureProvider(context, 'Infrastructure', { hasDatasource: true });
379
- await addToProvider(
380
- infraProvider.path,
381
- `${pascalName}Repository`,
382
- `\$${context}/Infrastructure/Http/Repositories`,
383
- `DatasourceProvider.${datasource.name}`
384
- );
385
-
386
- // Ensure ApplicationProvider
387
- const appProvider = await ensureProvider(context, 'Application', { infrastructure: true });
388
- await addToProvider(
389
- appProvider.path,
390
- `${pascalName}Service`,
391
- `\$${context}/Application/Services`,
392
- `InfrastructureProvider.${pascalName}Repository`
393
- );
394
-
395
- // Update all layer indexes
396
- await ensureIndexExports(path.join(contextPath, 'Infrastructure'));
397
- await ensureIndexExports(path.join(contextPath, 'Application'));
398
-
399
- console.log(`āœ… CRUD module for ${pascalName} created successfully!`);
400
- }