@azure-net/cli 2.0.2 ā 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/commands/generate/generateCrud.js +52 -17
- package/src/commands/generate/generateDatasource.js +126 -12
- package/src/commands/generate/generatePresenter.js +5 -5
- package/src/commands/generate/generateResponse.js +5 -5
- package/src/commands/init/initSchema.js +2 -2
- package/src/utils/contextUtils.js +18 -3
- package/src/utils/providerUtils.js +6 -1
package/package.json
CHANGED
|
@@ -13,7 +13,7 @@ const entityTemplate = `export interface I{{name}} {
|
|
|
13
13
|
\tupdated_at: string;
|
|
14
14
|
}`;
|
|
15
15
|
|
|
16
|
-
const portsIndexTemplate = `import type { I{{name}} } from '
|
|
16
|
+
const portsIndexTemplate = `import type { I{{name}} } from '\${{context}}/Domain/Entities/{{name}}';
|
|
17
17
|
|
|
18
18
|
export interface I{{name}}Collection {
|
|
19
19
|
\tdata: I{{name}}[];
|
|
@@ -28,10 +28,12 @@ export interface I{{name}}CollectionQuery {
|
|
|
28
28
|
|
|
29
29
|
export interface I{{name}}CreateRequest {
|
|
30
30
|
\t// Add request fields here
|
|
31
|
+
\t[key: string]: unknown;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
export interface I{{name}}UpdateRequest {
|
|
34
|
-
\t// Add request fields here
|
|
35
|
+
\t// Add request fields here
|
|
36
|
+
\t[key: string]: unknown;
|
|
35
37
|
}`;
|
|
36
38
|
|
|
37
39
|
const repositoryTemplate = `import { {{datasource}} } from '{{datasourceImport}}';
|
|
@@ -80,7 +82,7 @@ export class {{name}}Repository {
|
|
|
80
82
|
}`;
|
|
81
83
|
|
|
82
84
|
const serviceTemplate = `import { ClassMirror } from '@azure-net/kit';
|
|
83
|
-
import { {{name}}Repository } from '
|
|
85
|
+
import { {{name}}Repository } from '\${{context}}/Infrastructure/Http/Repositories';
|
|
84
86
|
|
|
85
87
|
export class {{name}}Service extends ClassMirror<{{name}}Repository> {
|
|
86
88
|
\tconstructor(private {{camelName}}Repository: {{name}}Repository) {
|
|
@@ -112,7 +114,8 @@ export const Update{{name}}Schema = {{schemaFactory}}<I{{name}}UpdateRequest>()
|
|
|
112
114
|
\t}))
|
|
113
115
|
\t.create();`;
|
|
114
116
|
|
|
115
|
-
|
|
117
|
+
// Presenter template with core factory (includes async helpers)
|
|
118
|
+
const presenterWithCoreTemplate = `import { {{presenterFactory}} } from '\$core/Presenter';
|
|
116
119
|
import { ApplicationProvider } from '\${{context}}/Application';
|
|
117
120
|
import { Create{{name}}Schema, Update{{name}}Schema } from './Schema';
|
|
118
121
|
import type {
|
|
@@ -142,6 +145,37 @@ export const {{name}}Presenter = {{presenterFactory}}('{{name}}Presenter', ({ cr
|
|
|
142
145
|
\treturn { collection, resource, create, update, remove };
|
|
143
146
|
});`;
|
|
144
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
|
+
|
|
145
179
|
export default async function generateCrud() {
|
|
146
180
|
const context = await selectContext('Select context for CRUD module:');
|
|
147
181
|
|
|
@@ -219,14 +253,14 @@ export default async function generateCrud() {
|
|
|
219
253
|
console.log('\nš Generating CRUD module...\n');
|
|
220
254
|
|
|
221
255
|
// 1. Create Entity
|
|
222
|
-
const entityPath = path.join(contextPath, 'Domain
|
|
256
|
+
const entityPath = path.join(contextPath, 'Domain/Entities', pascalName);
|
|
223
257
|
await writeIfNotExists(
|
|
224
258
|
path.join(entityPath, 'index.ts'),
|
|
225
259
|
entityTemplate.replace(/{{name}}/g, pascalName)
|
|
226
260
|
);
|
|
227
261
|
|
|
228
262
|
// 2. Create Ports
|
|
229
|
-
const portsPath = path.join(contextPath, 'Domain
|
|
263
|
+
const portsPath = path.join(contextPath, 'Domain/Ports', pascalName);
|
|
230
264
|
await writeIfNotExists(
|
|
231
265
|
path.join(portsPath, 'index.ts'),
|
|
232
266
|
portsIndexTemplate
|
|
@@ -235,7 +269,7 @@ export default async function generateCrud() {
|
|
|
235
269
|
);
|
|
236
270
|
|
|
237
271
|
// 3. Create Repository
|
|
238
|
-
const repoPath = path.join(contextPath, 'Infrastructure
|
|
272
|
+
const repoPath = path.join(contextPath, 'Infrastructure/Http/Repositories');
|
|
239
273
|
const datasourceImport = datasource.from === 'core'
|
|
240
274
|
? '$core/Datasource'
|
|
241
275
|
: `\$${context}/Infrastructure/Http/Datasource`;
|
|
@@ -253,12 +287,13 @@ export default async function generateCrud() {
|
|
|
253
287
|
await updateIndexTs(repoPath);
|
|
254
288
|
|
|
255
289
|
// 4. Create Service
|
|
256
|
-
const servicePath = path.join(contextPath, 'Application
|
|
290
|
+
const servicePath = path.join(contextPath, 'Application/Services');
|
|
257
291
|
await writeIfNotExists(
|
|
258
292
|
path.join(servicePath, `${pascalName}Service.ts`),
|
|
259
293
|
serviceTemplate
|
|
260
294
|
.replace(/{{name}}/g, pascalName)
|
|
261
295
|
.replace(/{{camelName}}/g, camelName)
|
|
296
|
+
.replace(/{{context}}/g, context)
|
|
262
297
|
);
|
|
263
298
|
await updateIndexTs(servicePath);
|
|
264
299
|
|
|
@@ -317,11 +352,12 @@ const Schema = createSchemaFactory(createRules(validationMessagesI18n));`;
|
|
|
317
352
|
}
|
|
318
353
|
await updateIndexTs(schemaPath);
|
|
319
354
|
|
|
320
|
-
// 6. Create Presenter
|
|
355
|
+
// 6. Create Presenter - use correct template based on type
|
|
356
|
+
const presenterTemplate = presenterType === 'package'
|
|
357
|
+
? presenterWithoutCoreTemplate
|
|
358
|
+
: presenterWithCoreTemplate;
|
|
359
|
+
|
|
321
360
|
const presenterFactory = presenterType === 'package' ? 'createPresenter' : presenterType;
|
|
322
|
-
const presenterImport = presenterType === 'package'
|
|
323
|
-
? '@azure-net/kit'
|
|
324
|
-
: '$core/Presenter';
|
|
325
361
|
|
|
326
362
|
await writeIfNotExists(
|
|
327
363
|
path.join(deliveryModulePath, `${pascalName}Presenter.ts`),
|
|
@@ -329,7 +365,6 @@ const Schema = createSchemaFactory(createRules(validationMessagesI18n));`;
|
|
|
329
365
|
.replace(/{{name}}/g, pascalName)
|
|
330
366
|
.replace(/{{context}}/g, context)
|
|
331
367
|
.replace(/{{presenterFactory}}/g, presenterFactory)
|
|
332
|
-
.replace(/{{presenterImport}}/g, presenterImport)
|
|
333
368
|
);
|
|
334
369
|
|
|
335
370
|
// Create module index
|
|
@@ -340,13 +375,13 @@ const Schema = createSchemaFactory(createRules(validationMessagesI18n));`;
|
|
|
340
375
|
|
|
341
376
|
// 7. Setup Providers
|
|
342
377
|
// Ensure DatasourceProvider
|
|
343
|
-
const datasourceProviderPath = path.join(contextPath, 'Infrastructure
|
|
378
|
+
const datasourceProviderPath = path.join(contextPath, 'Infrastructure/Providers/DatasourceProvider.ts');
|
|
344
379
|
if (!(await fs.access(datasourceProviderPath).then(() => true).catch(() => false))) {
|
|
345
380
|
const datasourceProviderContent = `import { createBoundaryProvider } from '@azure-net/kit';
|
|
346
381
|
import { ${datasource.name} } from '${datasource.from === 'core' ? '$core/Datasource' : '../Http/Datasource'}';
|
|
347
382
|
|
|
348
383
|
export const DatasourceProvider = createBoundaryProvider('${contextName}DatasourceProvider', () => ({
|
|
349
|
-
\t${datasource.name}: () =>
|
|
384
|
+
\t${datasource.name}: () => DatasourceProvider.${datasource.name}
|
|
350
385
|
}));`;
|
|
351
386
|
await writeIfNotExists(datasourceProviderPath, datasourceProviderContent);
|
|
352
387
|
await updateIndexTs(path.dirname(datasourceProviderPath));
|
|
@@ -357,7 +392,7 @@ export const DatasourceProvider = createBoundaryProvider('${contextName}Datasour
|
|
|
357
392
|
await addToProvider(
|
|
358
393
|
infraProvider.path,
|
|
359
394
|
`${pascalName}Repository`,
|
|
360
|
-
'
|
|
395
|
+
'$' + context + '/Infrastructure/Http/Repositories',
|
|
361
396
|
`DatasourceProvider.${datasource.name}`
|
|
362
397
|
);
|
|
363
398
|
|
|
@@ -366,7 +401,7 @@ export const DatasourceProvider = createBoundaryProvider('${contextName}Datasour
|
|
|
366
401
|
await addToProvider(
|
|
367
402
|
appProvider.path,
|
|
368
403
|
`${pascalName}Service`,
|
|
369
|
-
'
|
|
404
|
+
'$' + context + '/Application/Services',
|
|
370
405
|
`InfrastructureProvider.${pascalName}Repository`
|
|
371
406
|
);
|
|
372
407
|
|
|
@@ -1,18 +1,27 @@
|
|
|
1
1
|
import prompts from 'prompts';
|
|
2
|
-
import { selectContext, getContextPath, toPascalCase } from '../../utils/contextUtils.js';
|
|
3
|
-
import { writeIfNotExists, updateIndexTs } from '../../utils/fileUtils.js';
|
|
4
2
|
import path from 'path';
|
|
3
|
+
import { selectContext, getContextPath, toPascalCase, getAvailableFiles, toCamelCase } from '../../utils/contextUtils.js';
|
|
4
|
+
import { writeIfNotExists, updateIndexTs } from '../../utils/fileUtils.js';
|
|
5
|
+
import { ensureProvider, addToProvider } from '../../utils/providerUtils.js';
|
|
5
6
|
|
|
6
|
-
const
|
|
7
|
-
import {
|
|
7
|
+
const datasourceWithResponseTemplate = `import { BaseHttpDatasource, type CreateRequestCallbackType } from '@azure-net/kit/infra';
|
|
8
|
+
import { {{responseClass}}, type {{responseInterface}} } from '{{responseImport}}';
|
|
9
|
+
|
|
10
|
+
export class {{name}}Datasource extends BaseHttpDatasource {
|
|
11
|
+
\tconstructor(private http: HttpService) {
|
|
12
|
+
\t\tsuper({ http });
|
|
13
|
+
\t}
|
|
14
|
+
|
|
15
|
+
\tasync createRequest<T>(callback: CreateRequestCallbackType<{{responseInterface}}<T>>) {
|
|
16
|
+
\t\treturn new {{responseClass}}<T>(await this.createRawRequest<{{responseInterface}}<T>>(callback));
|
|
17
|
+
\t}
|
|
18
|
+
}`;
|
|
19
|
+
|
|
20
|
+
const datasourceWithoutResponseTemplate = `import { BaseHttpDatasource } from '@azure-net/kit/infra';
|
|
8
21
|
|
|
9
22
|
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});
|
|
23
|
+
\tconstructor(private http: HttpService) {
|
|
24
|
+
\t\tsuper({ http });
|
|
16
25
|
\t}
|
|
17
26
|
}`;
|
|
18
27
|
|
|
@@ -26,16 +35,121 @@ export default async function generateDatasource() {
|
|
|
26
35
|
});
|
|
27
36
|
|
|
28
37
|
const pascalName = toPascalCase(name);
|
|
38
|
+
const camelName = toCamelCase(name);
|
|
29
39
|
const contextPath = getContextPath(context);
|
|
40
|
+
|
|
41
|
+
// Get available responses
|
|
42
|
+
const coreResponses = await getAvailableFiles(
|
|
43
|
+
path.join(process.cwd(), 'src/app/core/Response')
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const contextResponses = context !== 'core'
|
|
47
|
+
? await getAvailableFiles(path.join(contextPath, 'Infrastructure/Response'))
|
|
48
|
+
: [];
|
|
49
|
+
|
|
50
|
+
const allResponses = [
|
|
51
|
+
...coreResponses.map(r => ({
|
|
52
|
+
title: `${r} (core)`,
|
|
53
|
+
value: { name: r, from: 'core' }
|
|
54
|
+
})),
|
|
55
|
+
...contextResponses.map(r => ({
|
|
56
|
+
title: `${r} (${context})`,
|
|
57
|
+
value: { name: r, from: context }
|
|
58
|
+
}))
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
if (allResponses.length === 0) {
|
|
62
|
+
console.error('ā No responses available. Create a response first with make:response');
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const { response } = await prompts({
|
|
67
|
+
type: 'select',
|
|
68
|
+
name: 'response',
|
|
69
|
+
message: 'Select response for datasource:',
|
|
70
|
+
choices: allResponses
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Determine interface name - typically IBackendApiDataSourceResponse or similar
|
|
74
|
+
const responseInterface = `I${response.name.replace('Response', '')}Response`;
|
|
75
|
+
|
|
30
76
|
const datasourcePath = context === 'core'
|
|
31
77
|
? path.join(contextPath, 'Datasource')
|
|
32
78
|
: path.join(contextPath, 'Infrastructure', 'Http', 'Datasource');
|
|
33
79
|
|
|
34
|
-
const
|
|
35
|
-
|
|
80
|
+
const responseImport = response.from === 'core'
|
|
81
|
+
? '$core/Response'
|
|
82
|
+
: context === 'core'
|
|
83
|
+
? '../Response'
|
|
84
|
+
: '../../Response';
|
|
85
|
+
|
|
86
|
+
const content = datasourceWithResponseTemplate
|
|
87
|
+
.replace(/{{name}}/g, pascalName)
|
|
88
|
+
.replace(/{{responseClass}}/g, response.name)
|
|
89
|
+
.replace(/{{responseInterface}}/g, responseInterface)
|
|
90
|
+
.replace(/{{responseImport}}/g, responseImport);
|
|
36
91
|
|
|
92
|
+
const filePath = path.join(datasourcePath, `${pascalName}Datasource.ts`);
|
|
37
93
|
await writeIfNotExists(filePath, content);
|
|
38
94
|
await updateIndexTs(datasourcePath);
|
|
39
95
|
|
|
96
|
+
// If not in core, ensure DatasourceProvider exists
|
|
97
|
+
if (context !== 'core') {
|
|
98
|
+
const contextName = toPascalCase(context);
|
|
99
|
+
const providerPath = path.join(contextPath, 'Infrastructure/Providers/DatasourceProvider.ts');
|
|
100
|
+
|
|
101
|
+
if (!(await fs.access(providerPath).then(() => true).catch(() => false))) {
|
|
102
|
+
const providerContent = `import { createBoundaryProvider } from '@azure-net/kit';
|
|
103
|
+
import { HttpService } from '@azure-net/kit/infra';
|
|
104
|
+
import { ${pascalName}Datasource } from '../Http/Datasource';
|
|
105
|
+
|
|
106
|
+
export const DatasourceProvider = createBoundaryProvider('${contextName}DatasourceProvider', () => ({
|
|
107
|
+
\t${pascalName}Datasource: () => new ${pascalName}Datasource(
|
|
108
|
+
\t\tnew HttpService({ baseUrl: 'https://api.example.com' })
|
|
109
|
+
\t)
|
|
110
|
+
}));`;
|
|
111
|
+
await writeIfNotExists(providerPath, providerContent);
|
|
112
|
+
await updateIndexTs(path.dirname(providerPath));
|
|
113
|
+
} else {
|
|
114
|
+
// Add datasource to existing provider
|
|
115
|
+
await addDatasourceToProvider(providerPath, pascalName);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
40
119
|
console.log(`ā
Datasource created at ${filePath}`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function addDatasourceToProvider(providerPath, datasourceName) {
|
|
123
|
+
let content = await fs.readFile(providerPath, 'utf-8');
|
|
124
|
+
|
|
125
|
+
// Add import if not exists
|
|
126
|
+
if (!content.includes(`${datasourceName}Datasource`)) {
|
|
127
|
+
const importStatement = `import { ${datasourceName}Datasource } from '../Http/Datasource';`;
|
|
128
|
+
const lastImportIndex = content.lastIndexOf('import ');
|
|
129
|
+
const endOfImportLine = content.indexOf('\n', lastImportIndex);
|
|
130
|
+
content = content.slice(0, endOfImportLine + 1) + importStatement + '\n' + content.slice(endOfImportLine + 1);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Add factory method
|
|
134
|
+
const factoryLine = `\t${datasourceName}Datasource: () => new ${datasourceName}Datasource(
|
|
135
|
+
\t\tnew HttpService({ baseUrl: 'https://api.example.com' })
|
|
136
|
+
\t)`;
|
|
137
|
+
|
|
138
|
+
if (!content.includes(`${datasourceName}Datasource:`)) {
|
|
139
|
+
const returnIndex = content.indexOf('=> ({');
|
|
140
|
+
const endOfReturn = content.indexOf('})', returnIndex);
|
|
141
|
+
const beforeEnd = content.lastIndexOf('\n', endOfReturn);
|
|
142
|
+
|
|
143
|
+
// Check if there are existing entries
|
|
144
|
+
const servicesSection = content.substring(returnIndex, endOfReturn);
|
|
145
|
+
const hasServices = servicesSection.includes(':');
|
|
146
|
+
|
|
147
|
+
if (hasServices) {
|
|
148
|
+
content = content.slice(0, beforeEnd) + ',\n' + factoryLine + content.slice(beforeEnd);
|
|
149
|
+
} else {
|
|
150
|
+
content = content.slice(0, beforeEnd + 1) + factoryLine + content.slice(beforeEnd);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
await fs.writeFile(providerPath, content, 'utf-8');
|
|
41
155
|
}
|
|
@@ -10,7 +10,7 @@ export const {{name}}Presenter = {{corePresenter}}('{{name}}Presenter', ({ creat
|
|
|
10
10
|
\t{{serviceInit}}
|
|
11
11
|
\t
|
|
12
12
|
\tconst example = async () => {
|
|
13
|
-
\t\t//
|
|
13
|
+
\t\t// Using async helpers from core presenter factory
|
|
14
14
|
\t\treturn await createAsyncResource(Promise.resolve({}));
|
|
15
15
|
\t};
|
|
16
16
|
\t
|
|
@@ -24,8 +24,8 @@ export const {{name}}Presenter = createPresenter('{{name}}Presenter', () => {
|
|
|
24
24
|
\t{{serviceInit}}
|
|
25
25
|
\t
|
|
26
26
|
\tconst example = async () => {
|
|
27
|
-
\t\t//
|
|
28
|
-
\t\treturn {};
|
|
27
|
+
\t\t// Direct method without async helpers
|
|
28
|
+
\t\treturn await Promise.resolve({});
|
|
29
29
|
\t};
|
|
30
30
|
\t
|
|
31
31
|
\treturn { example };
|
|
@@ -65,12 +65,12 @@ export default async function generatePresenter() {
|
|
|
65
65
|
// Get available services
|
|
66
66
|
const contextPath = getContextPath(context);
|
|
67
67
|
const services = await getAvailableFiles(
|
|
68
|
-
path.join(contextPath, 'Application
|
|
68
|
+
path.join(contextPath, 'Application/Services')
|
|
69
69
|
);
|
|
70
70
|
|
|
71
71
|
const serviceChoices = [
|
|
72
72
|
{ title: 'Without service', value: null },
|
|
73
|
-
...services.map(s => ({ title:
|
|
73
|
+
...services.map(s => ({ title: s, value: s }))
|
|
74
74
|
];
|
|
75
75
|
|
|
76
76
|
const { service } = await prompts({
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import prompts from 'prompts';
|
|
2
|
+
import path from 'path';
|
|
2
3
|
import { selectContext, getContextPath, toPascalCase } from '../../utils/contextUtils.js';
|
|
3
4
|
import { writeIfNotExists, updateIndexTs } from '../../utils/fileUtils.js';
|
|
4
|
-
import path from 'path';
|
|
5
5
|
|
|
6
|
-
const responseTemplate = `import { ResponseBuilder } from '@azure-net/kit';
|
|
6
|
+
const responseTemplate = `import { ResponseBuilder } from '@azure-net/kit/infra';
|
|
7
7
|
|
|
8
8
|
export interface I{{name}}Response<T = unknown> {
|
|
9
9
|
\tdata: T;
|
|
@@ -23,14 +23,14 @@ export default async function generateResponse() {
|
|
|
23
23
|
const { name } = await prompts({
|
|
24
24
|
type: 'text',
|
|
25
25
|
name: 'name',
|
|
26
|
-
message: 'Response name (
|
|
26
|
+
message: 'Response name (without "Response" suffix):'
|
|
27
27
|
});
|
|
28
28
|
|
|
29
29
|
const pascalName = toPascalCase(name);
|
|
30
30
|
const contextPath = getContextPath(context);
|
|
31
31
|
const responsePath = context === 'core'
|
|
32
|
-
? path.join(contextPath, '
|
|
33
|
-
: path.join(contextPath, 'Infrastructure'
|
|
32
|
+
? path.join(contextPath, 'Response')
|
|
33
|
+
: path.join(contextPath, 'Infrastructure/Response');
|
|
34
34
|
|
|
35
35
|
const content = responseTemplate.replace(/{{name}}/g, pascalName);
|
|
36
36
|
const filePath = path.join(responsePath, `${pascalName}Response.ts`);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { writeIfNotExists } from '../../utils/fileUtils.js';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
|
|
4
|
-
const schemaPath = path.join(process.cwd(), 'src/app/core/
|
|
4
|
+
const schemaPath = path.join(process.cwd(), 'src/app/core/Schema/Schema.ts');
|
|
5
5
|
|
|
6
6
|
const schemaTemplate = `import { createSchemaFactory } from '@azure-net/kit';
|
|
7
7
|
import { createRules, validationMessagesI18n } from '@azure-net/kit/schema';
|
|
@@ -11,7 +11,7 @@ export const Schema = createSchemaFactory(createRules(validationMessagesI18n));`
|
|
|
11
11
|
export default async function initSchema() {
|
|
12
12
|
await writeIfNotExists(schemaPath, schemaTemplate);
|
|
13
13
|
await writeIfNotExists(
|
|
14
|
-
path.join(process.cwd(), 'src/app/core/
|
|
14
|
+
path.join(process.cwd(), 'src/app/core/Schema/index.ts'),
|
|
15
15
|
`export * from './Schema';`
|
|
16
16
|
);
|
|
17
17
|
|
|
@@ -40,13 +40,28 @@ export async function getAvailableFiles(dir, pattern = '.ts') {
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
// Fixed to preserve PascalCase properly
|
|
43
44
|
export function toPascalCase(str) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
// If already in PascalCase with multiple words, preserve it
|
|
46
|
+
if (/^[A-Z][a-z]+(?:[A-Z][a-z]+)*$/.test(str)) {
|
|
47
|
+
return str;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Split by common delimiters but preserve existing camelCase/PascalCase
|
|
51
|
+
const words = str.split(/[-_\s]+/);
|
|
52
|
+
return words
|
|
53
|
+
.map((word, index) => {
|
|
54
|
+
// If word is already in camelCase or PascalCase, preserve it
|
|
55
|
+
if (/[a-z][A-Z]/.test(word)) {
|
|
56
|
+
return word.charAt(0).toUpperCase() + word.slice(1);
|
|
57
|
+
}
|
|
58
|
+
// Otherwise capitalize first letter
|
|
59
|
+
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
60
|
+
})
|
|
47
61
|
.join('');
|
|
48
62
|
}
|
|
49
63
|
|
|
64
|
+
// Fixed to preserve camelCase properly
|
|
50
65
|
export function toCamelCase(str) {
|
|
51
66
|
const pascal = toPascalCase(str);
|
|
52
67
|
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
@@ -68,8 +68,13 @@ export const ${varName} = createBoundaryProvider(
|
|
|
68
68
|
export async function addToProvider(providerPath, serviceName, importPath, dependency = null) {
|
|
69
69
|
let content = await fs.readFile(providerPath, 'utf-8');
|
|
70
70
|
|
|
71
|
+
// Use alias import path instead of relative
|
|
72
|
+
const aliasImportPath = importPath.startsWith('$') ? importPath : importPath.startsWith('../')
|
|
73
|
+
? importPath // Keep relative if it's internal to the same layer
|
|
74
|
+
: importPath;
|
|
75
|
+
|
|
71
76
|
// Add import if not exists
|
|
72
|
-
const importStatement = `import { ${serviceName} } from '${
|
|
77
|
+
const importStatement = `import { ${serviceName} } from '${aliasImportPath}';`;
|
|
73
78
|
if (!content.includes(serviceName)) {
|
|
74
79
|
const lastImportIndex = content.lastIndexOf('import ');
|
|
75
80
|
const endOfImportLine = content.indexOf('\n', lastImportIndex);
|