@azure-net/cli 2.0.4 → 2.0.6

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.
@@ -4,7 +4,7 @@ import { loadUserConfig } from '../../utils/loadConfig.js';
4
4
 
5
5
  const APP_ROOT = path.join(process.cwd(), 'src', 'app');
6
6
  const CONTEXTS_PATH = path.join(APP_ROOT, 'contexts');
7
- const CORE_PATH = path.join(APP_ROOT, 'core');
7
+ const SHARED_PATH = path.join(APP_ROOT, 'shared');
8
8
 
9
9
  async function createDirIfNotExists(dirPath) {
10
10
  try {
@@ -23,7 +23,7 @@ async function createIndexFile(dirPath, exportPatterns = []) {
23
23
  }
24
24
  }
25
25
 
26
- async function createBaseStructure(root) {
26
+ async function createBaseStructure(root, contextName) {
27
27
  // Domain
28
28
  const domainPath = path.join(root, 'Domain');
29
29
  await createDirIfNotExists(path.join(domainPath, 'Entities'));
@@ -35,12 +35,72 @@ async function createBaseStructure(root) {
35
35
  await createDirIfNotExists(path.join(infraPath, 'Http', 'Datasource'));
36
36
  await createDirIfNotExists(path.join(infraPath, 'Providers'));
37
37
 
38
+ // Create empty InfrastructureProvider
39
+ const infraProviderContent = `import { createBoundaryProvider } from '@azure-net/kit';
40
+
41
+ export const InfrastructureProvider = createBoundaryProvider(
42
+ \t'${contextName}InfrastructureProvider',
43
+ \t() => ({
44
+ \t\t// Infrastructure services will be added here manually
45
+ \t})
46
+ );`;
47
+
48
+ await fs.writeFile(
49
+ path.join(infraPath, 'Providers', 'InfrastructureProvider.ts'),
50
+ infraProviderContent,
51
+ 'utf-8'
52
+ );
53
+
54
+ await fs.writeFile(
55
+ path.join(infraPath, 'Providers', 'index.ts'),
56
+ `export * from './InfrastructureProvider';`,
57
+ 'utf-8'
58
+ );
59
+
60
+ // Create Infrastructure index
61
+ await fs.writeFile(
62
+ path.join(infraPath, 'index.ts'),
63
+ `export * from './Providers';`,
64
+ 'utf-8'
65
+ );
66
+
38
67
  // Application
39
68
  const appPath = path.join(root, 'Application');
40
69
  await createDirIfNotExists(path.join(appPath, 'Services'));
41
70
  await createDirIfNotExists(path.join(appPath, 'Providers'));
42
71
 
43
- // Delivery - organized by modules, not by type
72
+ // Create empty ApplicationProvider
73
+ const appProviderContent = `import { createBoundaryProvider } from '@azure-net/kit';
74
+ import { InfrastructureProvider } from '../Infrastructure';
75
+
76
+ export const ApplicationProvider = createBoundaryProvider(
77
+ \t'${contextName}ApplicationProvider',
78
+ \t({ InfrastructureProvider }) => ({
79
+ \t\t// Application services will be added here manually
80
+ \t}),
81
+ \t{ dependsOn: { InfrastructureProvider } }
82
+ );`;
83
+
84
+ await fs.writeFile(
85
+ path.join(appPath, 'Providers', 'ApplicationProvider.ts'),
86
+ appProviderContent,
87
+ 'utf-8'
88
+ );
89
+
90
+ await fs.writeFile(
91
+ path.join(appPath, 'Providers', 'index.ts'),
92
+ `export * from './ApplicationProvider';`,
93
+ 'utf-8'
94
+ );
95
+
96
+ // Create Application index
97
+ await fs.writeFile(
98
+ path.join(appPath, 'index.ts'),
99
+ `export * from './Providers';`,
100
+ 'utf-8'
101
+ );
102
+
103
+ // Delivery - organized by modules
44
104
  const deliveryPath = path.join(root, 'Delivery');
45
105
  await createDirIfNotExists(deliveryPath);
46
106
  }
@@ -54,20 +114,21 @@ export default async function initStructure() {
54
114
  // Create contexts
55
115
  for (const context of contexts) {
56
116
  const contextPath = path.join(CONTEXTS_PATH, context);
57
- await createBaseStructure(contextPath);
117
+ const contextName = context.charAt(0).toUpperCase() + context.slice(1);
118
+ await createBaseStructure(contextPath, contextName);
58
119
  }
59
120
 
60
- // Create core structure
61
- await createDirIfNotExists(CORE_PATH);
62
- await createDirIfNotExists(path.join(CORE_PATH, 'Datasource'));
63
- await createDirIfNotExists(path.join(CORE_PATH, 'Response'));
64
- await createDirIfNotExists(path.join(CORE_PATH, 'Schema'));
65
- await createDirIfNotExists(path.join(CORE_PATH, 'Middleware'));
66
- await createDirIfNotExists(path.join(CORE_PATH, 'Presenter'));
67
- await createDirIfNotExists(path.join(CORE_PATH, 'Translation'));
68
-
69
- // Create core index.ts that exports all subdirectories
70
- await createIndexFile(CORE_PATH, [
121
+ // Create shared structure (former core)
122
+ await createDirIfNotExists(SHARED_PATH);
123
+ await createDirIfNotExists(path.join(SHARED_PATH, 'Datasource'));
124
+ await createDirIfNotExists(path.join(SHARED_PATH, 'Response'));
125
+ await createDirIfNotExists(path.join(SHARED_PATH, 'Schema'));
126
+ await createDirIfNotExists(path.join(SHARED_PATH, 'Middleware'));
127
+ await createDirIfNotExists(path.join(SHARED_PATH, 'Presenter'));
128
+ await createDirIfNotExists(path.join(SHARED_PATH, 'Translation'));
129
+
130
+ // Create shared index.ts that exports all subdirectories
131
+ await createIndexFile(SHARED_PATH, [
71
132
  './Schema',
72
133
  './Datasource',
73
134
  './Response',
@@ -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,413 +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 } 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 = `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
- // Presenter template with core factory (includes async helpers)
118
- const presenterWithCoreTemplate = `import { {{presenterFactory}} } from '\$core/Presenter';
119
- import { ApplicationProvider } from '\${{context}}/Application';
120
- import { Create{{name}}Schema, Update{{name}}Schema } from './Schema';
121
- import type {
122
- \tI{{name}}CollectionQuery,
123
- \tI{{name}}CreateRequest,
124
- \tI{{name}}UpdateRequest
125
- } from '\${{context}}/Domain/Ports/{{name}}';
126
-
127
- export const {{name}}Presenter = {{presenterFactory}}('{{name}}Presenter', ({ createAsyncResource, createAsyncAction }) => {
128
- \tconst { {{name}}Service } = ApplicationProvider();
129
- \t
130
- \tconst collection = async (query?: I{{name}}CollectionQuery) =>
131
- \t\tawait createAsyncResource({{name}}Service.collection(query));
132
- \t
133
- \tconst resource = async (id: number) =>
134
- \t\tawait createAsyncResource({{name}}Service.resource(id));
135
- \t
136
- \tconst create = async (request: I{{name}}CreateRequest) =>
137
- \t\tawait createAsyncAction({{name}}Service.create(Create{{name}}Schema.from(request).json()));
138
- \t
139
- \tconst update = async (id: number, request: I{{name}}UpdateRequest) =>
140
- \t\tawait createAsyncAction({{name}}Service.update(id, Update{{name}}Schema.from(request).json()));
141
- \t
142
- \tconst remove = async (id: number) =>
143
- \t\tawait createAsyncAction({{name}}Service.remove(id));
144
- \t
145
- \treturn { collection, resource, create, update, remove };
146
- });`;
147
-
148
- // Presenter template without async helpers
149
- const presenterWithoutCoreTemplate = `import { createPresenter } from '@azure-net/kit';
150
- import { ApplicationProvider } from '\${{context}}/Application';
151
- import { Create{{name}}Schema, Update{{name}}Schema } from './Schema';
152
- import type {
153
- \tI{{name}}CollectionQuery,
154
- \tI{{name}}CreateRequest,
155
- \tI{{name}}UpdateRequest
156
- } from '\${{context}}/Domain/Ports/{{name}}';
157
-
158
- export const {{name}}Presenter = createPresenter('{{name}}Presenter', () => {
159
- \tconst { {{name}}Service } = ApplicationProvider();
160
- \t
161
- \tconst collection = async (query?: I{{name}}CollectionQuery) =>
162
- \t\tawait {{name}}Service.collection(query);
163
- \t
164
- \tconst resource = async (id: number) =>
165
- \t\tawait {{name}}Service.resource(id);
166
- \t
167
- \tconst create = async (request: I{{name}}CreateRequest) =>
168
- \t\tawait {{name}}Service.create(Create{{name}}Schema.from(request).json());
169
- \t
170
- \tconst update = async (id: number, request: I{{name}}UpdateRequest) =>
171
- \t\tawait {{name}}Service.update(id, Update{{name}}Schema.from(request).json());
172
- \t
173
- \tconst remove = async (id: number) =>
174
- \t\tawait {{name}}Service.remove(id);
175
- \t
176
- \treturn { collection, resource, create, update, remove };
177
- });`;
178
-
179
- export default async function generateCrud() {
180
- const context = await selectContext('Select context for CRUD module:');
181
-
182
- if (context === 'core') {
183
- console.error('❌ Cannot create CRUD in core. Choose a specific context.');
184
- return;
185
- }
186
-
187
- const { name } = await prompts({
188
- type: 'text',
189
- name: 'name',
190
- message: 'Entity name (PascalCase):'
191
- });
192
-
193
- const { endpoint } = await prompts({
194
- type: 'text',
195
- name: 'endpoint',
196
- message: 'API endpoint (e.g. /api/users):'
197
- });
198
-
199
- // Get available datasources
200
- const contextPath = getContextPath(context);
201
- const coreDatasources = await getAvailableFiles(
202
- path.join(process.cwd(), 'src/app/core/Datasource')
203
- );
204
- const contextDatasources = await getAvailableFiles(
205
- path.join(contextPath, 'Infrastructure/Http/Datasource')
206
- );
207
-
208
- const allDatasources = [
209
- ...coreDatasources.map(d => ({ title: `${d} (core)`, value: { name: d, from: 'core' } })),
210
- ...contextDatasources.map(d => ({ title: `${d} (${context})`, value: { name: d, from: context } }))
211
- ];
212
-
213
- const { datasource } = await prompts({
214
- type: 'select',
215
- name: 'datasource',
216
- message: 'Select datasource:',
217
- choices: allDatasources
218
- });
219
-
220
- // Get schema and presenter factories
221
- const coreSchemas = await getAvailableFiles(
222
- path.join(process.cwd(), 'src/app/core/Schema')
223
- );
224
-
225
- const { schemaType } = await prompts({
226
- type: 'select',
227
- name: 'schemaType',
228
- message: 'Select schema factory:',
229
- choices: [
230
- { title: 'Use createSchemaFactory from package', value: 'package' },
231
- ...coreSchemas.map(s => ({ title: `Use ${s} from core`, value: s }))
232
- ]
233
- });
234
-
235
- const corePresenters = await getAvailableFiles(
236
- path.join(process.cwd(), 'src/app/core/Presenter')
237
- );
238
-
239
- const { presenterType } = await prompts({
240
- type: 'select',
241
- name: 'presenterType',
242
- message: 'Select presenter factory:',
243
- choices: [
244
- { title: 'Use createPresenter from package', value: 'package' },
245
- ...corePresenters.map(p => ({ title: `Use ${p} from core`, value: p }))
246
- ]
247
- });
248
-
249
- const pascalName = toPascalCase(name);
250
- const camelName = toCamelCase(name);
251
- const contextName = toPascalCase(context);
252
-
253
- console.log('\n🚀 Generating CRUD module...\n');
254
-
255
- // 1. Create Entity
256
- const entityPath = path.join(contextPath, 'Domain/Entities', pascalName);
257
- await writeIfNotExists(
258
- path.join(entityPath, 'index.ts'),
259
- entityTemplate.replace(/{{name}}/g, pascalName)
260
- );
261
-
262
- // 2. Create Ports
263
- const portsPath = path.join(contextPath, 'Domain/Ports', pascalName);
264
- await writeIfNotExists(
265
- path.join(portsPath, 'index.ts'),
266
- portsIndexTemplate
267
- .replace(/{{name}}/g, pascalName)
268
- .replace(/{{context}}/g, context)
269
- );
270
-
271
- // 3. Create Repository
272
- const repoPath = path.join(contextPath, 'Infrastructure/Http/Repositories');
273
- const datasourceImport = datasource.from === 'core'
274
- ? '$core/Datasource'
275
- : `\$${context}/Infrastructure/Http/Datasource`;
276
-
277
- await writeIfNotExists(
278
- path.join(repoPath, `${pascalName}Repository.ts`),
279
- repositoryTemplate
280
- .replace(/{{name}}/g, pascalName)
281
- .replace(/{{context}}/g, context)
282
- .replace(/{{endpoint}}/g, endpoint)
283
- .replace(/{{datasource}}/g, datasource.name)
284
- .replace(/{{datasourceImport}}/g, datasourceImport)
285
- .replace(/{{datasourceVar}}/g, toCamelCase(datasource.name))
286
- );
287
- await updateIndexTs(repoPath);
288
-
289
- // 4. Create Service
290
- const servicePath = path.join(contextPath, 'Application/Services');
291
- await writeIfNotExists(
292
- path.join(servicePath, `${pascalName}Service.ts`),
293
- serviceTemplate
294
- .replace(/{{name}}/g, pascalName)
295
- .replace(/{{camelName}}/g, camelName)
296
- .replace(/{{context}}/g, context)
297
- );
298
- await updateIndexTs(servicePath);
299
-
300
- // 5. Create Delivery module structure
301
- const deliveryModulePath = path.join(contextPath, 'Delivery', pascalName);
302
- const schemaPath = path.join(deliveryModulePath, 'Schema');
303
-
304
- // Create schemas
305
- const schemaFactory = schemaType === 'package' ? 'Schema' : schemaType;
306
- const schemaImport = schemaType === 'package'
307
- ? '@azure-net/kit'
308
- : '$core/Schema';
309
-
310
- if (schemaType === 'package') {
311
- // Add the import for createSchemaFactory and rules
312
- const schemaImportFull = `import { createSchemaFactory } from '@azure-net/kit';
313
- import { createRules, validationMessagesI18n } from '@azure-net/kit/schema';
314
-
315
- const Schema = createSchemaFactory(createRules(validationMessagesI18n));`;
316
-
317
- await writeIfNotExists(
318
- path.join(schemaPath, `Create${pascalName}Schema.ts`),
319
- schemaImportFull + '\n' + createSchemaTemplate
320
- .replace('import { {{schemaFactory}} } from \'{{schemaImport}}\';\n', '')
321
- .replace(/{{name}}/g, pascalName)
322
- .replace(/{{context}}/g, context)
323
- .replace(/{{schemaFactory}}/g, 'Schema')
324
- );
325
-
326
- await writeIfNotExists(
327
- path.join(schemaPath, `Update${pascalName}Schema.ts`),
328
- schemaImportFull + '\n' + updateSchemaTemplate
329
- .replace('import { {{schemaFactory}} } from \'{{schemaImport}}\';\n', '')
330
- .replace(/{{name}}/g, pascalName)
331
- .replace(/{{context}}/g, context)
332
- .replace(/{{schemaFactory}}/g, 'Schema')
333
- );
334
- } else {
335
- await writeIfNotExists(
336
- path.join(schemaPath, `Create${pascalName}Schema.ts`),
337
- createSchemaTemplate
338
- .replace(/{{name}}/g, pascalName)
339
- .replace(/{{context}}/g, context)
340
- .replace(/{{schemaFactory}}/g, schemaFactory)
341
- .replace(/{{schemaImport}}/g, schemaImport)
342
- );
343
-
344
- await writeIfNotExists(
345
- path.join(schemaPath, `Update${pascalName}Schema.ts`),
346
- updateSchemaTemplate
347
- .replace(/{{name}}/g, pascalName)
348
- .replace(/{{context}}/g, context)
349
- .replace(/{{schemaFactory}}/g, schemaFactory)
350
- .replace(/{{schemaImport}}/g, schemaImport)
351
- );
352
- }
353
- await updateIndexTs(schemaPath);
354
-
355
- // 6. Create Presenter - use correct template based on type
356
- const presenterTemplate = presenterType === 'package'
357
- ? presenterWithoutCoreTemplate
358
- : presenterWithCoreTemplate;
359
-
360
- const presenterFactory = presenterType === 'package' ? 'createPresenter' : presenterType;
361
-
362
- await writeIfNotExists(
363
- path.join(deliveryModulePath, `${pascalName}Presenter.ts`),
364
- presenterTemplate
365
- .replace(/{{name}}/g, pascalName)
366
- .replace(/{{context}}/g, context)
367
- .replace(/{{presenterFactory}}/g, presenterFactory)
368
- );
369
-
370
- // Create module index
371
- await writeIfNotExists(
372
- path.join(deliveryModulePath, 'index.ts'),
373
- `export * from './${pascalName}Presenter';\nexport * from './Schema';`
374
- );
375
-
376
- // 7. Setup Providers
377
- // Ensure DatasourceProvider
378
- const datasourceProviderPath = path.join(contextPath, 'Infrastructure/Providers/DatasourceProvider.ts');
379
- if (!(await fs.access(datasourceProviderPath).then(() => true).catch(() => false))) {
380
- const datasourceProviderContent = `import { createBoundaryProvider } from '@azure-net/kit';
381
- import { ${datasource.name} } from '${datasource.from === 'core' ? '$core/Datasource' : '../Http/Datasource'}';
382
-
383
- export const DatasourceProvider = createBoundaryProvider('${contextName}DatasourceProvider', () => ({
384
- \t${datasource.name}: () => DatasourceProvider.${datasource.name}
385
- }));`;
386
- await writeIfNotExists(datasourceProviderPath, datasourceProviderContent);
387
- await updateIndexTs(path.dirname(datasourceProviderPath));
388
- }
389
-
390
- // Ensure InfrastructureProvider
391
- const infraProvider = await ensureProvider(context, 'Infrastructure', {});
392
- await addToProvider(
393
- infraProvider.path,
394
- `${pascalName}Repository`,
395
- '$' + context + '/Infrastructure/Http/Repositories',
396
- `DatasourceProvider.${datasource.name}`
397
- );
398
-
399
- // Ensure ApplicationProvider
400
- const appProvider = await ensureProvider(context, 'Application', { infrastructure: true });
401
- await addToProvider(
402
- appProvider.path,
403
- `${pascalName}Service`,
404
- '$' + context + '/Application/Services',
405
- `InfrastructureProvider.${pascalName}Repository`
406
- );
407
-
408
- // Update all layer indexes
409
- await ensureIndexExports(path.join(contextPath, 'Infrastructure'));
410
- await ensureIndexExports(path.join(contextPath, 'Application'));
411
-
412
- console.log(`✅ CRUD module for ${pascalName} created successfully!`);
413
- }