@azure-net/cli 2.0.9 ā 2.1.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.
- package/bin/azure-net.js +7 -1
- package/package.json +1 -1
- package/src/commands/generate/generateCrudBase.js +28 -16
- package/src/commands/generate/generateCrudPresenter.js +20 -18
- package/src/commands/generate/generateDatasource.js +21 -20
- package/src/commands/generate/generatePresenter.js +13 -11
- package/src/commands/generate/generateRepository.js +9 -6
- package/src/commands/generate/generateResponse.js +10 -5
- package/src/commands/init/index.js +2 -1
- package/src/commands/init/initAliases.js +1 -0
- package/src/commands/init/initMiddleware.js +6 -3
- package/src/commands/init/initPresenter.js +22 -0
- package/src/commands/init/initSchema.js +6 -3
- package/src/commands/init/initStructure.js +17 -20
- package/src/commands/init/initTranslations.js +5 -2
- package/src/utils/contextUtils.js +7 -22
- package/src/utils/fileUtils.js +28 -0
package/bin/azure-net.js
CHANGED
|
@@ -8,7 +8,8 @@ import {
|
|
|
8
8
|
initEdges,
|
|
9
9
|
initTranslations,
|
|
10
10
|
initSchema,
|
|
11
|
-
initLint
|
|
11
|
+
initLint,
|
|
12
|
+
initPresenter
|
|
12
13
|
} from '../src/commands/init/index.js';
|
|
13
14
|
import {
|
|
14
15
|
generateDatasource,
|
|
@@ -67,6 +68,11 @@ program
|
|
|
67
68
|
.description('Initialize schema factory')
|
|
68
69
|
.action(initSchema);
|
|
69
70
|
|
|
71
|
+
program
|
|
72
|
+
.command('init:presenter')
|
|
73
|
+
.description('Initialize presenter factory')
|
|
74
|
+
.action(initPresenter);
|
|
75
|
+
|
|
70
76
|
program
|
|
71
77
|
.command('init')
|
|
72
78
|
.description('Run all initialization steps')
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import prompts from 'prompts';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { selectContext, getContextPath, toPascalCase, toCamelCase, getAvailableFiles } from '../../utils/contextUtils.js';
|
|
4
|
-
import { writeIfNotExists, updateIndexTs } from '../../utils/fileUtils.js';
|
|
4
|
+
import { writeIfNotExists, updateIndexTs, updateCoreIndex } from '../../utils/fileUtils.js';
|
|
5
5
|
|
|
6
6
|
// Templates for CRUD base generation
|
|
7
7
|
const entityTemplate = `export interface I{{name}} {
|
|
@@ -11,7 +11,7 @@ const entityTemplate = `export interface I{{name}} {
|
|
|
11
11
|
\tupdated_at: string;
|
|
12
12
|
}`;
|
|
13
13
|
|
|
14
|
-
const portsIndexTemplate = `import type { I{{name}} } from '\${{context}}/Domain/
|
|
14
|
+
const portsIndexTemplate = `import type { I{{name}} } from '\${{context}}/Domain/{{name}}/Model';
|
|
15
15
|
|
|
16
16
|
export interface I{{name}}Collection {
|
|
17
17
|
\tdata: I{{name}}[];
|
|
@@ -35,13 +35,13 @@ export interface I{{name}}UpdateRequest {
|
|
|
35
35
|
}`;
|
|
36
36
|
|
|
37
37
|
const repositoryTemplate = `import { {{datasource}} } from '{{datasourceImport}}';
|
|
38
|
-
import type { I{{name}} } from '\${{context}}/Domain/
|
|
38
|
+
import type { I{{name}} } from '\${{context}}/Domain/{{name}}/Model';
|
|
39
39
|
import type {
|
|
40
40
|
\tI{{name}}Collection,
|
|
41
41
|
\tI{{name}}CollectionQuery,
|
|
42
42
|
\tI{{name}}CreateRequest,
|
|
43
43
|
\tI{{name}}UpdateRequest
|
|
44
|
-
} from '\${{context}}/Domain/
|
|
44
|
+
} from '\${{context}}/Domain/{{name}}/Ports';
|
|
45
45
|
|
|
46
46
|
export class {{name}}Repository {
|
|
47
47
|
\tprivate endpoint = '{{endpoint}}';
|
|
@@ -111,15 +111,15 @@ export default async function generateCrudBase() {
|
|
|
111
111
|
|
|
112
112
|
// Get available datasources
|
|
113
113
|
const contextPath = getContextPath(context);
|
|
114
|
-
const
|
|
115
|
-
path.join(process.cwd(), 'src/app/
|
|
114
|
+
const coreDatasources = await getAvailableFiles(
|
|
115
|
+
path.join(process.cwd(), 'src/app/core/Datasource')
|
|
116
116
|
);
|
|
117
117
|
const contextDatasources = await getAvailableFiles(
|
|
118
118
|
path.join(contextPath, 'Infrastructure/Http/Datasource')
|
|
119
119
|
);
|
|
120
120
|
|
|
121
121
|
const allDatasources = [
|
|
122
|
-
...
|
|
122
|
+
...coreDatasources.map(d => ({ title: `${d} (core)`, value: { name: d, from: 'core' } })),
|
|
123
123
|
...contextDatasources.map(d => ({ title: `${d} (${context})`, value: { name: d, from: context } }))
|
|
124
124
|
];
|
|
125
125
|
|
|
@@ -135,15 +135,18 @@ export default async function generateCrudBase() {
|
|
|
135
135
|
|
|
136
136
|
console.log('\nš Generating CRUD base (repository & service)...\n');
|
|
137
137
|
|
|
138
|
-
// 1. Create
|
|
139
|
-
const
|
|
138
|
+
// 1. Create Domain structure
|
|
139
|
+
const domainPath = path.join(contextPath, 'Domain', pascalName);
|
|
140
|
+
const modelPath = path.join(domainPath, 'Model');
|
|
141
|
+
const portsPath = path.join(domainPath, 'Ports');
|
|
142
|
+
|
|
143
|
+
// Create Model
|
|
140
144
|
await writeIfNotExists(
|
|
141
|
-
path.join(
|
|
145
|
+
path.join(modelPath, 'index.ts'),
|
|
142
146
|
entityTemplate.replace(/{{name}}/g, pascalName)
|
|
143
147
|
);
|
|
144
148
|
|
|
145
|
-
//
|
|
146
|
-
const portsPath = path.join(contextPath, 'Domain/Ports', pascalName);
|
|
149
|
+
// Create Ports
|
|
147
150
|
await writeIfNotExists(
|
|
148
151
|
path.join(portsPath, 'index.ts'),
|
|
149
152
|
portsIndexTemplate
|
|
@@ -151,10 +154,16 @@ export default async function generateCrudBase() {
|
|
|
151
154
|
.replace(/{{context}}/g, context)
|
|
152
155
|
);
|
|
153
156
|
|
|
154
|
-
//
|
|
157
|
+
// Create Domain module index
|
|
158
|
+
await writeIfNotExists(
|
|
159
|
+
path.join(domainPath, 'index.ts'),
|
|
160
|
+
`export * from './Model';\nexport * from './Ports';`
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
// 2. Create Repository
|
|
155
164
|
const repoPath = path.join(contextPath, 'Infrastructure/Http/Repositories');
|
|
156
|
-
const datasourceImport = datasource.from === '
|
|
157
|
-
? '$
|
|
165
|
+
const datasourceImport = datasource.from === 'core'
|
|
166
|
+
? '$core/Datasource'
|
|
158
167
|
: `\$${context}/Infrastructure/Http/Datasource`;
|
|
159
168
|
|
|
160
169
|
await writeIfNotExists(
|
|
@@ -169,7 +178,7 @@ export default async function generateCrudBase() {
|
|
|
169
178
|
);
|
|
170
179
|
await updateIndexTs(repoPath);
|
|
171
180
|
|
|
172
|
-
//
|
|
181
|
+
// 3. Create Service
|
|
173
182
|
const servicePath = path.join(contextPath, 'Application/Services');
|
|
174
183
|
await writeIfNotExists(
|
|
175
184
|
path.join(servicePath, `${pascalName}Service.ts`),
|
|
@@ -180,6 +189,9 @@ export default async function generateCrudBase() {
|
|
|
180
189
|
);
|
|
181
190
|
await updateIndexTs(servicePath);
|
|
182
191
|
|
|
192
|
+
// Update core index
|
|
193
|
+
await updateCoreIndex();
|
|
194
|
+
|
|
183
195
|
console.log(`ā
CRUD base for ${pascalName} created successfully!`);
|
|
184
196
|
console.log(`\nš” Remember to:`);
|
|
185
197
|
console.log(` 1. Add ${pascalName}Repository to InfrastructureProvider`);
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import prompts from 'prompts';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import fs from 'fs/promises';
|
|
4
3
|
import { selectContext, getContextPath, toPascalCase, getAvailableFiles, getApplicationProviderServices } from '../../utils/contextUtils.js';
|
|
5
|
-
import {updateIndexTs, writeIfNotExists} from '../../utils/fileUtils.js';
|
|
4
|
+
import { updateIndexTs, writeIfNotExists, updateCoreIndex } from '../../utils/fileUtils.js';
|
|
6
5
|
|
|
7
6
|
const createSchemaTemplate = `import { {{schemaFactory}} } from '{{schemaImport}}';
|
|
8
|
-
import type { I{{name}}CreateRequest } from '\${{context}}/Domain/
|
|
7
|
+
import type { I{{name}}CreateRequest } from '\${{context}}/Domain/{{entity}}/Ports';
|
|
9
8
|
|
|
10
9
|
export const Create{{name}}Schema = {{schemaFactory}}<I{{name}}CreateRequest>()
|
|
11
10
|
\t.rules((rules) => ({
|
|
@@ -14,7 +13,7 @@ export const Create{{name}}Schema = {{schemaFactory}}<I{{name}}CreateRequest>()
|
|
|
14
13
|
\t.create();`;
|
|
15
14
|
|
|
16
15
|
const updateSchemaTemplate = `import { {{schemaFactory}} } from '{{schemaImport}}';
|
|
17
|
-
import type { I{{name}}UpdateRequest } from '\${{context}}/Domain/
|
|
16
|
+
import type { I{{name}}UpdateRequest } from '\${{context}}/Domain/{{entity}}/Ports';
|
|
18
17
|
|
|
19
18
|
export const Update{{name}}Schema = {{schemaFactory}}<I{{name}}UpdateRequest>()
|
|
20
19
|
\t.rules((rules) => ({
|
|
@@ -22,14 +21,14 @@ export const Update{{name}}Schema = {{schemaFactory}}<I{{name}}UpdateRequest>()
|
|
|
22
21
|
\t}))
|
|
23
22
|
\t.create();`;
|
|
24
23
|
|
|
25
|
-
const
|
|
24
|
+
const presenterWithCoreTemplate = `import { {{presenterFactory}} } from '$core/Presenter';
|
|
26
25
|
import { ApplicationProvider } from '\${{context}}/Application';
|
|
27
26
|
import { Create{{name}}Schema, Update{{name}}Schema } from './Schema';
|
|
28
27
|
import type {
|
|
29
28
|
\tI{{name}}CollectionQuery,
|
|
30
29
|
\tI{{name}}CreateRequest,
|
|
31
30
|
\tI{{name}}UpdateRequest
|
|
32
|
-
} from '\${{context}}/Domain/
|
|
31
|
+
} from '\${{context}}/Domain/{{name}}/Ports';
|
|
33
32
|
|
|
34
33
|
export const {{name}}Presenter = {{presenterFactory}}('{{name}}Presenter', ({ createAsyncResource, createAsyncAction }) => {
|
|
35
34
|
\tconst { {{serviceName}} } = ApplicationProvider();
|
|
@@ -52,14 +51,14 @@ export const {{name}}Presenter = {{presenterFactory}}('{{name}}Presenter', ({ cr
|
|
|
52
51
|
\treturn { collection, resource, create, update, remove };
|
|
53
52
|
});`;
|
|
54
53
|
|
|
55
|
-
const
|
|
54
|
+
const presenterWithoutCoreTemplate = `import { createPresenter } from '@azure-net/kit';
|
|
56
55
|
import { ApplicationProvider } from '\${{context}}/Application';
|
|
57
56
|
import { Create{{name}}Schema, Update{{name}}Schema } from './Schema';
|
|
58
57
|
import type {
|
|
59
58
|
\tI{{name}}CollectionQuery,
|
|
60
59
|
\tI{{name}}CreateRequest,
|
|
61
60
|
\tI{{name}}UpdateRequest
|
|
62
|
-
} from '\${{context}}/Domain/
|
|
61
|
+
} from '\${{context}}/Domain/{{name}}/Ports';
|
|
63
62
|
|
|
64
63
|
export const {{name}}Presenter = createPresenter('{{name}}Presenter', () => {
|
|
65
64
|
\tconst { {{serviceName}} } = ApplicationProvider();
|
|
@@ -74,7 +73,7 @@ export const {{name}}Presenter = createPresenter('{{name}}Presenter', () => {
|
|
|
74
73
|
\t\tawait {{serviceName}}.create(Create{{name}}Schema.from(request).json());
|
|
75
74
|
\t
|
|
76
75
|
\tconst update = async (id: number, request: I{{name}}UpdateRequest) =>
|
|
77
|
-
\t\tawait {{serviceName}}.update(id, Update{{name}}Schema.from(request).json());
|
|
76
|
+
\t\tawait {{serviceName}}.update(id, Update{{name}}Schema.from(request).json()));
|
|
78
77
|
\t
|
|
79
78
|
\tconst remove = async (id: number) =>
|
|
80
79
|
\t\tawait {{serviceName}}.remove(id);
|
|
@@ -105,8 +104,8 @@ export default async function generateCrudPresenter() {
|
|
|
105
104
|
const pascalName = toPascalCase(entityName);
|
|
106
105
|
|
|
107
106
|
// Get schema factory
|
|
108
|
-
const
|
|
109
|
-
path.join(process.cwd(), 'src/app/
|
|
107
|
+
const coreSchemas = await getAvailableFiles(
|
|
108
|
+
path.join(process.cwd(), 'src/app/core/Schema')
|
|
110
109
|
);
|
|
111
110
|
|
|
112
111
|
const { schemaType } = await prompts({
|
|
@@ -115,13 +114,13 @@ export default async function generateCrudPresenter() {
|
|
|
115
114
|
message: 'Select schema factory:',
|
|
116
115
|
choices: [
|
|
117
116
|
{ title: 'Use createSchemaFactory from package', value: 'package' },
|
|
118
|
-
...
|
|
117
|
+
...coreSchemas.map(s => ({ title: `Use ${s} from core`, value: s }))
|
|
119
118
|
]
|
|
120
119
|
});
|
|
121
120
|
|
|
122
121
|
// Get presenter factory
|
|
123
|
-
const
|
|
124
|
-
path.join(process.cwd(), 'src/app/
|
|
122
|
+
const corePresenters = await getAvailableFiles(
|
|
123
|
+
path.join(process.cwd(), 'src/app/core/Presenter')
|
|
125
124
|
);
|
|
126
125
|
|
|
127
126
|
const { presenterType } = await prompts({
|
|
@@ -130,7 +129,7 @@ export default async function generateCrudPresenter() {
|
|
|
130
129
|
message: 'Select presenter factory:',
|
|
131
130
|
choices: [
|
|
132
131
|
{ title: 'Use createPresenter from package', value: 'package' },
|
|
133
|
-
...
|
|
132
|
+
...corePresenters.map(p => ({ title: `Use ${p} from core`, value: p }))
|
|
134
133
|
]
|
|
135
134
|
});
|
|
136
135
|
|
|
@@ -144,7 +143,7 @@ export default async function generateCrudPresenter() {
|
|
|
144
143
|
const schemaFactory = schemaType === 'package' ? 'Schema' : schemaType;
|
|
145
144
|
const schemaImport = schemaType === 'package'
|
|
146
145
|
? '@azure-net/kit'
|
|
147
|
-
: '$
|
|
146
|
+
: '$core/Schema';
|
|
148
147
|
|
|
149
148
|
if (schemaType === 'package') {
|
|
150
149
|
const schemaImportFull = `import { createSchemaFactory } from '@azure-net/kit';
|
|
@@ -196,8 +195,8 @@ const Schema = createSchemaFactory(createRules(validationMessagesI18n));`;
|
|
|
196
195
|
|
|
197
196
|
// Create Presenter
|
|
198
197
|
const presenterTemplate = presenterType === 'package'
|
|
199
|
-
?
|
|
200
|
-
:
|
|
198
|
+
? presenterWithoutCoreTemplate
|
|
199
|
+
: presenterWithCoreTemplate;
|
|
201
200
|
|
|
202
201
|
const presenterFactory = presenterType === 'package' ? 'createPresenter' : presenterType;
|
|
203
202
|
|
|
@@ -216,5 +215,8 @@ const Schema = createSchemaFactory(createRules(validationMessagesI18n));`;
|
|
|
216
215
|
`export * from './${pascalName}Presenter';\nexport * from './Schema';`
|
|
217
216
|
);
|
|
218
217
|
|
|
218
|
+
// Update core index
|
|
219
|
+
await updateCoreIndex();
|
|
220
|
+
|
|
219
221
|
console.log(`ā
CRUD presenter for ${pascalName} created successfully!`);
|
|
220
222
|
}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import prompts from 'prompts';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { selectContext, getContextPath, toPascalCase, getAvailableFiles } from '../../utils/contextUtils.js';
|
|
4
|
-
import { writeIfNotExists, updateIndexTs } from '../../utils/fileUtils.js';
|
|
4
|
+
import { writeIfNotExists, updateIndexTs, updateCoreIndex } from '../../utils/fileUtils.js';
|
|
5
5
|
|
|
6
6
|
const datasourceWithResponseTemplate = `import { BaseHttpDatasource, type CreateRequestCallbackType } from '@azure-net/kit/infra';
|
|
7
|
-
import { {{responseClass}}
|
|
7
|
+
import { {{responseClass}} } from '{{responseImport}}';
|
|
8
8
|
|
|
9
9
|
export class {{name}}Datasource extends BaseHttpDatasource {
|
|
10
|
-
\tasync createRequest<T>(callback: CreateRequestCallbackType<
|
|
11
|
-
\t\treturn new {{responseClass}}<T>(await this.createRawRequest<
|
|
10
|
+
\tasync createRequest<T>(callback: CreateRequestCallbackType<T>) {
|
|
11
|
+
\t\treturn new {{responseClass}}<T>(await this.createRawRequest<T>(callback));
|
|
12
12
|
\t}
|
|
13
13
|
}`;
|
|
14
14
|
|
|
15
15
|
export default async function generateDatasource() {
|
|
16
|
-
const context = await selectContext('Select context for datasource (or
|
|
16
|
+
const context = await selectContext('Select context for datasource (or core):');
|
|
17
17
|
|
|
18
18
|
const { name } = await prompts({
|
|
19
19
|
type: 'text',
|
|
@@ -22,23 +22,23 @@ export default async function generateDatasource() {
|
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
const pascalName = toPascalCase(name);
|
|
25
|
-
const contextPath = context === '
|
|
26
|
-
? path.join(process.cwd(), 'src/app/
|
|
25
|
+
const contextPath = context === 'core'
|
|
26
|
+
? path.join(process.cwd(), 'src/app/core')
|
|
27
27
|
: getContextPath(context);
|
|
28
28
|
|
|
29
29
|
// Get available responses
|
|
30
|
-
const
|
|
31
|
-
path.join(process.cwd(), 'src/app/
|
|
30
|
+
const coreResponses = await getAvailableFiles(
|
|
31
|
+
path.join(process.cwd(), 'src/app/core/Response')
|
|
32
32
|
);
|
|
33
33
|
|
|
34
|
-
const contextResponses = context !== '
|
|
34
|
+
const contextResponses = context !== 'core'
|
|
35
35
|
? await getAvailableFiles(path.join(contextPath, 'Infrastructure/Response'))
|
|
36
36
|
: [];
|
|
37
37
|
|
|
38
38
|
const allResponses = [
|
|
39
|
-
...
|
|
40
|
-
title: `${r} (
|
|
41
|
-
value: { name: r, from: '
|
|
39
|
+
...coreResponses.map(r => ({
|
|
40
|
+
title: `${r} (core)`,
|
|
41
|
+
value: { name: r, from: 'core' }
|
|
42
42
|
})),
|
|
43
43
|
...contextResponses.map(r => ({
|
|
44
44
|
title: `${r} (${context})`,
|
|
@@ -58,26 +58,27 @@ export default async function generateDatasource() {
|
|
|
58
58
|
choices: allResponses
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
const responseInterface = `I${response.name.replace('Response', '')}Response`;
|
|
63
|
-
|
|
64
|
-
const datasourcePath = context === 'shared'
|
|
61
|
+
const datasourcePath = context === 'core'
|
|
65
62
|
? path.join(contextPath, 'Datasource')
|
|
66
63
|
: path.join(contextPath, 'Infrastructure/Http/Datasource');
|
|
67
64
|
|
|
68
|
-
const responseImport = response.from === '
|
|
69
|
-
? context === '
|
|
65
|
+
const responseImport = response.from === 'core'
|
|
66
|
+
? context === 'core' ? '../Response' : '$core/Response'
|
|
70
67
|
: `\$${context}/Infrastructure/Response`;
|
|
71
68
|
|
|
72
69
|
const content = datasourceWithResponseTemplate
|
|
73
70
|
.replace(/{{name}}/g, pascalName)
|
|
74
71
|
.replace(/{{responseClass}}/g, response.name)
|
|
75
|
-
.replace(/{{responseInterface}}/g, responseInterface)
|
|
76
72
|
.replace(/{{responseImport}}/g, responseImport);
|
|
77
73
|
|
|
78
74
|
const filePath = path.join(datasourcePath, `${pascalName}Datasource.ts`);
|
|
79
75
|
await writeIfNotExists(filePath, content);
|
|
80
76
|
await updateIndexTs(datasourcePath);
|
|
81
77
|
|
|
78
|
+
// Update core index if needed
|
|
79
|
+
if (context === 'core') {
|
|
80
|
+
await updateCoreIndex();
|
|
81
|
+
}
|
|
82
|
+
|
|
82
83
|
console.log(`ā
Datasource created at ${filePath}`);
|
|
83
84
|
}
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import prompts from 'prompts';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import fs from 'fs/promises';
|
|
4
3
|
import { selectContext, getContextPath, toPascalCase, getAvailableFiles } from '../../utils/contextUtils.js';
|
|
5
|
-
import { writeIfNotExists } from '../../utils/fileUtils.js';
|
|
4
|
+
import { writeIfNotExists, updateCoreIndex } from '../../utils/fileUtils.js';
|
|
6
5
|
|
|
7
|
-
const
|
|
6
|
+
const presenterWithCoreTemplate = `import { {{corePresenter}} } from '$core/Presenter';
|
|
8
7
|
import { ApplicationProvider } from '\${{context}}/Application';
|
|
9
8
|
|
|
10
|
-
export const {{name}}Presenter = {{
|
|
9
|
+
export const {{name}}Presenter = {{corePresenter}}('{{name}}Presenter', ({ createAsyncResource, createAsyncAction }) => {
|
|
11
10
|
\tconst { /* extract services from ApplicationProvider */ } = ApplicationProvider();
|
|
12
11
|
\t
|
|
13
12
|
\tconst example = async () => {
|
|
14
|
-
\t\t// Using async helpers from
|
|
13
|
+
\t\t// Using async helpers from core presenter factory
|
|
15
14
|
\t\treturn await createAsyncResource(Promise.resolve({}));
|
|
16
15
|
\t};
|
|
17
16
|
\t
|
|
@@ -41,14 +40,14 @@ export default async function generatePresenter() {
|
|
|
41
40
|
message: 'Module name (will create folder in Delivery):'
|
|
42
41
|
});
|
|
43
42
|
|
|
44
|
-
// Check for
|
|
45
|
-
const
|
|
46
|
-
path.join(process.cwd(), 'src/app/
|
|
43
|
+
// Check for core presenters
|
|
44
|
+
const corePresenters = await getAvailableFiles(
|
|
45
|
+
path.join(process.cwd(), 'src/app/core/Presenter')
|
|
47
46
|
);
|
|
48
47
|
|
|
49
48
|
const presenterChoices = [
|
|
50
49
|
{ title: 'Use createPresenter from package', value: 'package' },
|
|
51
|
-
...
|
|
50
|
+
...corePresenters.map(p => ({ title: `Use ${p} from core`, value: p }))
|
|
52
51
|
];
|
|
53
52
|
|
|
54
53
|
const { presenterType } = await prompts({
|
|
@@ -67,9 +66,9 @@ export default async function generatePresenter() {
|
|
|
67
66
|
? presenterWithPackageTemplate
|
|
68
67
|
.replace(/{{name}}/g, pascalName)
|
|
69
68
|
.replace(/{{context}}/g, context)
|
|
70
|
-
:
|
|
69
|
+
: presenterWithCoreTemplate
|
|
71
70
|
.replace(/{{name}}/g, pascalName)
|
|
72
|
-
.replace(/{{
|
|
71
|
+
.replace(/{{corePresenter}}/g, presenterType)
|
|
73
72
|
.replace(/{{context}}/g, context);
|
|
74
73
|
|
|
75
74
|
await writeIfNotExists(filePath, content);
|
|
@@ -78,6 +77,9 @@ export default async function generatePresenter() {
|
|
|
78
77
|
`export * from './${pascalName}Presenter';`
|
|
79
78
|
);
|
|
80
79
|
|
|
80
|
+
// Update core index
|
|
81
|
+
await updateCoreIndex();
|
|
82
|
+
|
|
81
83
|
console.log(`ā
Presenter created at ${filePath}`);
|
|
82
84
|
console.log(`\nš” Remember to extract needed services from ApplicationProvider in the presenter.`);
|
|
83
85
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import prompts from 'prompts';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { selectContext, getContextPath, toPascalCase, getAvailableFiles, toCamelCase } from '../../utils/contextUtils.js';
|
|
4
|
-
import { writeIfNotExists, updateIndexTs } from '../../utils/fileUtils.js';
|
|
4
|
+
import { writeIfNotExists, updateIndexTs, updateCoreIndex } from '../../utils/fileUtils.js';
|
|
5
5
|
|
|
6
6
|
const repositoryTemplate = `import { {{datasource}} } from '{{datasourceImport}}';
|
|
7
7
|
|
|
@@ -26,15 +26,15 @@ export default async function generateRepository() {
|
|
|
26
26
|
|
|
27
27
|
// Get available datasources
|
|
28
28
|
const contextPath = getContextPath(context);
|
|
29
|
-
const
|
|
30
|
-
path.join(process.cwd(), 'src/app/
|
|
29
|
+
const coreDatasources = await getAvailableFiles(
|
|
30
|
+
path.join(process.cwd(), 'src/app/core/Datasource')
|
|
31
31
|
);
|
|
32
32
|
const contextDatasources = await getAvailableFiles(
|
|
33
33
|
path.join(contextPath, 'Infrastructure/Http/Datasource')
|
|
34
34
|
);
|
|
35
35
|
|
|
36
36
|
const allDatasources = [
|
|
37
|
-
...
|
|
37
|
+
...coreDatasources.map(d => ({ title: `${d} (core)`, value: { name: d, from: 'core' } })),
|
|
38
38
|
...contextDatasources.map(d => ({ title: `${d} (${context})`, value: { name: d, from: context } }))
|
|
39
39
|
];
|
|
40
40
|
|
|
@@ -55,8 +55,8 @@ export default async function generateRepository() {
|
|
|
55
55
|
const filePath = path.join(repoPath, `${pascalName}Repository.ts`);
|
|
56
56
|
|
|
57
57
|
// Generate repository
|
|
58
|
-
const datasourceImport = datasource.from === '
|
|
59
|
-
? '$
|
|
58
|
+
const datasourceImport = datasource.from === 'core'
|
|
59
|
+
? '$core/Datasource'
|
|
60
60
|
: `\$${context}/Infrastructure/Http/Datasource`;
|
|
61
61
|
|
|
62
62
|
const content = repositoryTemplate
|
|
@@ -68,6 +68,9 @@ export default async function generateRepository() {
|
|
|
68
68
|
await writeIfNotExists(filePath, content);
|
|
69
69
|
await updateIndexTs(repoPath);
|
|
70
70
|
|
|
71
|
+
// Update core index
|
|
72
|
+
await updateCoreIndex();
|
|
73
|
+
|
|
71
74
|
console.log(`ā
Repository created at ${filePath}`);
|
|
72
75
|
console.log(`\nš” Remember to manually add this repository to InfrastructureProvider when needed.`);
|
|
73
76
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import prompts from 'prompts';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { selectContext, getContextPath, toPascalCase } from '../../utils/contextUtils.js';
|
|
4
|
-
import { writeIfNotExists, updateIndexTs } from '../../utils/fileUtils.js';
|
|
4
|
+
import { writeIfNotExists, updateIndexTs, updateCoreIndex } from '../../utils/fileUtils.js';
|
|
5
5
|
|
|
6
6
|
const responseTemplate = `import { ResponseBuilder } from '@azure-net/kit/infra';
|
|
7
7
|
|
|
@@ -9,7 +9,7 @@ export class {{name}}Response<TData = unknown, TMeta = unknown> extends Response
|
|
|
9
9
|
}`;
|
|
10
10
|
|
|
11
11
|
export default async function generateResponse() {
|
|
12
|
-
const context = await selectContext('Select context for response (or
|
|
12
|
+
const context = await selectContext('Select context for response (or core):');
|
|
13
13
|
|
|
14
14
|
const { name } = await prompts({
|
|
15
15
|
type: 'text',
|
|
@@ -18,11 +18,11 @@ export default async function generateResponse() {
|
|
|
18
18
|
});
|
|
19
19
|
|
|
20
20
|
const pascalName = toPascalCase(name);
|
|
21
|
-
const contextPath = context === '
|
|
22
|
-
? path.join(process.cwd(), 'src/app/
|
|
21
|
+
const contextPath = context === 'core'
|
|
22
|
+
? path.join(process.cwd(), 'src/app/core')
|
|
23
23
|
: getContextPath(context);
|
|
24
24
|
|
|
25
|
-
const responsePath = context === '
|
|
25
|
+
const responsePath = context === 'core'
|
|
26
26
|
? path.join(contextPath, 'Response')
|
|
27
27
|
: path.join(contextPath, 'Infrastructure/Response');
|
|
28
28
|
|
|
@@ -32,5 +32,10 @@ export default async function generateResponse() {
|
|
|
32
32
|
await writeIfNotExists(filePath, content);
|
|
33
33
|
await updateIndexTs(responsePath);
|
|
34
34
|
|
|
35
|
+
// Update core index if needed
|
|
36
|
+
if (context === 'core') {
|
|
37
|
+
await updateCoreIndex();
|
|
38
|
+
}
|
|
39
|
+
|
|
35
40
|
console.log(`ā
Response created at ${filePath}`);
|
|
36
41
|
}
|
|
@@ -4,4 +4,5 @@ export { default as initMiddleware } from './initMiddleware.js';
|
|
|
4
4
|
export { default as initEdges } from './initEdges.js';
|
|
5
5
|
export { default as initTranslations } from './initTranslations.js';
|
|
6
6
|
export { default as initSchema } from './initSchema.js';
|
|
7
|
-
export { default as initLint } from './initLint.js';
|
|
7
|
+
export { default as initLint } from './initLint.js';
|
|
8
|
+
export { default as initPresenter } from './initPresenter.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { writeIfNotExists,
|
|
1
|
+
import { writeIfNotExists, updateCoreIndex } from '../../utils/fileUtils.js';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
|
|
4
|
-
const middlewarePath = path.join(process.cwd(), 'src/app/
|
|
4
|
+
const middlewarePath = path.join(process.cwd(), 'src/app/core/Middleware/MiddlewareManager.ts');
|
|
5
5
|
|
|
6
6
|
const middlewareTemplate = `import { createMiddlewareManager } from '@azure-net/kit';
|
|
7
7
|
|
|
@@ -10,9 +10,12 @@ export const { clientMiddleware, serverMiddleware } = createMiddlewareManager([]
|
|
|
10
10
|
export default async function initMiddleware() {
|
|
11
11
|
await writeIfNotExists(middlewarePath, middlewareTemplate);
|
|
12
12
|
await writeIfNotExists(
|
|
13
|
-
path.join(process.cwd(), 'src/app/
|
|
13
|
+
path.join(process.cwd(), 'src/app/core/Middleware/index.ts'),
|
|
14
14
|
`export * from './MiddlewareManager';`
|
|
15
15
|
);
|
|
16
16
|
|
|
17
|
+
// Update core index
|
|
18
|
+
await updateCoreIndex();
|
|
19
|
+
|
|
17
20
|
console.log('ā
Middleware initialized');
|
|
18
21
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { writeIfNotExists } from '../../utils/fileUtils.js';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
const presenterPath = path.join(process.cwd(), 'src/app/core/Presenter/AppPresenter.ts');
|
|
5
|
+
|
|
6
|
+
const presenterTemplate = `import { createPresenterFactory } from '@azure-net/kit/edges';
|
|
7
|
+
import { createAsyncHelpers, createErrorParser } from '@azure-net/kit';
|
|
8
|
+
|
|
9
|
+
const ErrorHandler = createErrorParser();
|
|
10
|
+
const AsyncHelpers = createAsyncHelpers({ parseError: ErrorHandler });
|
|
11
|
+
|
|
12
|
+
export const AppPresenter = createPresenterFactory({ ...AsyncHelpers, handleError: ErrorHandler });`;
|
|
13
|
+
|
|
14
|
+
export default async function initPresenter() {
|
|
15
|
+
await writeIfNotExists(presenterPath, presenterTemplate);
|
|
16
|
+
await writeIfNotExists(
|
|
17
|
+
path.join(process.cwd(), 'src/app/core/Presenter/index.ts'),
|
|
18
|
+
`export * from './AppPresenter';`
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
console.log('ā
Presenter factory initialized');
|
|
22
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { writeIfNotExists } from '../../utils/fileUtils.js';
|
|
1
|
+
import { writeIfNotExists, updateCoreIndex } from '../../utils/fileUtils.js';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
|
|
4
|
-
const schemaPath = path.join(process.cwd(), 'src/app/
|
|
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,9 +11,12 @@ 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/
|
|
14
|
+
path.join(process.cwd(), 'src/app/core/Schema/index.ts'),
|
|
15
15
|
`export * from './Schema';`
|
|
16
16
|
);
|
|
17
17
|
|
|
18
|
+
// Update core index
|
|
19
|
+
await updateCoreIndex();
|
|
20
|
+
|
|
18
21
|
console.log('ā
Schema factory initialized');
|
|
19
22
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import fs from 'fs/promises';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { loadUserConfig } from '../../utils/loadConfig.js';
|
|
4
|
+
import { updateCoreIndex } from '../../utils/fileUtils.js';
|
|
4
5
|
|
|
5
6
|
const APP_ROOT = path.join(process.cwd(), 'src', 'app');
|
|
6
7
|
const CONTEXTS_PATH = path.join(APP_ROOT, 'contexts');
|
|
7
8
|
const SHARED_PATH = path.join(APP_ROOT, 'shared');
|
|
8
|
-
const CORE_PATH = path.join(APP_ROOT, '
|
|
9
|
+
const CORE_PATH = path.join(APP_ROOT, 'core');
|
|
9
10
|
|
|
10
11
|
async function createDirIfNotExists(dirPath) {
|
|
11
12
|
try {
|
|
@@ -25,10 +26,9 @@ async function createIndexFile(dirPath, exportPatterns = []) {
|
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
async function createBaseStructure(root, contextName, contextAlias) {
|
|
28
|
-
// Domain
|
|
29
|
+
// Domain - Š½Š¾Š²Š°Ń ŃŃŃŃŠŗŃŃŃŠ°
|
|
29
30
|
const domainPath = path.join(root, 'Domain');
|
|
30
|
-
await createDirIfNotExists(
|
|
31
|
-
await createDirIfNotExists(path.join(domainPath, 'Ports'));
|
|
31
|
+
await createDirIfNotExists(domainPath);
|
|
32
32
|
|
|
33
33
|
// Infrastructure
|
|
34
34
|
const infraPath = path.join(root, 'Infrastructure');
|
|
@@ -119,23 +119,20 @@ export default async function initStructure() {
|
|
|
119
119
|
await createBaseStructure(contextPath, contextName, context);
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
// Create shared
|
|
122
|
+
// Create empty shared folder
|
|
123
123
|
await createDirIfNotExists(SHARED_PATH);
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
await createDirIfNotExists(
|
|
127
|
-
await createDirIfNotExists(path.join(
|
|
128
|
-
await createDirIfNotExists(path.join(
|
|
129
|
-
await createDirIfNotExists(path.join(
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
await
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
'./Middleware',
|
|
137
|
-
'./Translation'
|
|
138
|
-
]);
|
|
124
|
+
|
|
125
|
+
// Create core structure with all functionality
|
|
126
|
+
await createDirIfNotExists(CORE_PATH);
|
|
127
|
+
await createDirIfNotExists(path.join(CORE_PATH, 'Datasource'));
|
|
128
|
+
await createDirIfNotExists(path.join(CORE_PATH, 'Response'));
|
|
129
|
+
await createDirIfNotExists(path.join(CORE_PATH, 'Schema'));
|
|
130
|
+
await createDirIfNotExists(path.join(CORE_PATH, 'Middleware'));
|
|
131
|
+
await createDirIfNotExists(path.join(CORE_PATH, 'Presenter'));
|
|
132
|
+
await createDirIfNotExists(path.join(CORE_PATH, 'Translation'));
|
|
133
|
+
|
|
134
|
+
// Update core index
|
|
135
|
+
await updateCoreIndex();
|
|
139
136
|
|
|
140
137
|
console.log('ā
Structure initialization complete!');
|
|
141
138
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { writeIfNotExists } from '../../utils/fileUtils.js';
|
|
1
|
+
import { writeIfNotExists, updateCoreIndex } from '../../utils/fileUtils.js';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
|
|
4
|
-
const translationsPath = path.join(process.cwd(), 'src/app/
|
|
4
|
+
const translationsPath = path.join(process.cwd(), 'src/app/core/Translation');
|
|
5
5
|
|
|
6
6
|
const translationProviderTemplate = `import { messages } from './Locales';
|
|
7
7
|
import { createTranslations } from '@azure-net/kit/i18n';
|
|
@@ -52,5 +52,8 @@ export default async function initTranslations() {
|
|
|
52
52
|
localesIndexTemplate
|
|
53
53
|
);
|
|
54
54
|
|
|
55
|
+
// Update core index
|
|
56
|
+
await updateCoreIndex();
|
|
57
|
+
|
|
55
58
|
console.log('ā
Translations initialized');
|
|
56
59
|
}
|
|
@@ -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
|
|
7
|
+
const CORE_PATH = path.join(process.cwd(), 'src/app/core');
|
|
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: '
|
|
19
|
+
{ title: 'core', value: 'core' }
|
|
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 === '
|
|
28
|
-
?
|
|
27
|
+
return context === 'core'
|
|
28
|
+
? CORE_PATH
|
|
29
29
|
: path.join(CONTEXTS_PATH, context);
|
|
30
30
|
}
|
|
31
31
|
|
|
@@ -61,28 +61,13 @@ export async function getApplicationProviderServices(context) {
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
// Fixed to preserve PascalCase properly
|
|
65
64
|
export function toPascalCase(str) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Split by common delimiters but preserve existing camelCase/PascalCase
|
|
72
|
-
const words = str.split(/[-_\s]+/);
|
|
73
|
-
return words
|
|
74
|
-
.map((word, index) => {
|
|
75
|
-
// If word is already in camelCase or PascalCase, preserve it
|
|
76
|
-
if (/[a-z][A-Z]/.test(word)) {
|
|
77
|
-
return word.charAt(0).toUpperCase() + word.slice(1);
|
|
78
|
-
}
|
|
79
|
-
// Otherwise capitalize first letter
|
|
80
|
-
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
81
|
-
})
|
|
65
|
+
return str
|
|
66
|
+
.split(/[-_\s]+/)
|
|
67
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
82
68
|
.join('');
|
|
83
69
|
}
|
|
84
70
|
|
|
85
|
-
// Fixed to preserve camelCase properly
|
|
86
71
|
export function toCamelCase(str) {
|
|
87
72
|
const pascal = toPascalCase(str);
|
|
88
73
|
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
package/src/utils/fileUtils.js
CHANGED
|
@@ -28,6 +28,34 @@ export async function updateIndexTs(dir, filePattern = '.ts', ignore = ['index.t
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
export async function updateCoreIndex() {
|
|
32
|
+
const corePath = path.join(process.cwd(), 'src/app/core');
|
|
33
|
+
try {
|
|
34
|
+
const dirs = await fs.readdir(corePath, { withFileTypes: true });
|
|
35
|
+
const validDirs = [];
|
|
36
|
+
|
|
37
|
+
for (const dir of dirs) {
|
|
38
|
+
if (dir.isDirectory()) {
|
|
39
|
+
// Check if directory has any files
|
|
40
|
+
const dirPath = path.join(corePath, dir.name);
|
|
41
|
+
const files = await fs.readdir(dirPath);
|
|
42
|
+
if (files.length > 0) {
|
|
43
|
+
validDirs.push(dir.name);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (validDirs.length > 0) {
|
|
49
|
+
const content = validDirs
|
|
50
|
+
.map(d => `export * from './${d}';`)
|
|
51
|
+
.join('\n') + '\n';
|
|
52
|
+
await fs.writeFile(path.join(corePath, 'index.ts'), content, 'utf-8');
|
|
53
|
+
}
|
|
54
|
+
} catch (error) {
|
|
55
|
+
// Core directory doesn't exist
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
31
59
|
export async function ensureIndexExports(layerPath) {
|
|
32
60
|
try {
|
|
33
61
|
const subdirs = await fs.readdir(layerPath, { withFileTypes: true });
|