@azure-net/cli 5.0.0-3 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/azure-net.js +5 -46
- package/bin/azure-net.ts +5 -5
- package/package.json +1 -1
- package/src/checks/checkDomain.js +8 -38
- package/src/checks/checkFoldersStructure.js +0 -14
- package/src/checks/checkHooks.js +0 -5
- package/src/checks/checkImports.js +0 -1
- package/src/checks/checkInternal.js +0 -1
- package/src/checks/checkLayerBoundaries.js +50 -54
- package/src/checks/checkLayerBoundaries.ts +55 -58
- package/src/checks/checkPresenterNames.js +1 -37
- package/src/checks/checkPresenterNames.ts +1 -6
- package/src/checks/checkProject.js +0 -6
- package/src/checks/checkProviderGraph.js +1 -38
- package/src/checks/checkProviderNames.js +0 -28
- package/src/checks/index.js +0 -1
- package/src/generate/layers/generateRepository.js +4 -19
- package/src/generate/layers/generateRepositoryMethod.js +0 -12
- package/src/generate/layers/generateUseCases.js +0 -6
- package/src/generate/layers/repositoryShared.js +41 -104
- package/src/generate/layers/repositoryShared.ts +17 -12
- package/src/generate/module/generateDomain.js +0 -25
- package/src/generate/module/generateModule.js +0 -10
- package/src/generate/module/generateModulePreset.js +10 -51
- package/src/generate/module/generateModulePreset.ts +9 -8
- package/src/generate/module/generatePresenter.js +366 -371
- package/src/generate/module/generatePresenter.ts +76 -20
- package/src/generate/module/generateRepository.js +0 -17
- package/src/generate/module/generateSchemaFromType.js +9 -58
- package/src/generate/module/generateSchemaFromType.ts +1 -2
- package/src/generate/module/generateTypesJson.js +4 -45
- package/src/generate/module/generateUseCases.js +0 -9
- package/src/generate/module/repositoryModuleShared.js +21 -98
- package/src/generate/module/repositoryModuleShared.ts +14 -10
- package/src/generate/ui/generateComponent.js +0 -16
- package/src/generate/ui/generateDesignComponent.js +0 -12
- package/src/generate/ui/generateWidget.js +0 -12
- package/src/init/initAliases.js +42 -64
- package/src/init/initAliases.ts +47 -42
- package/src/init/initEdges.js +0 -15
- package/src/init/initStructure.js +48 -21
- package/src/init/initStructure.ts +51 -3
- package/src/install/installFresh.js +0 -16
- package/src/plugins/addLint.js +11 -46
- package/src/scaffolds/createCoreSchema.js +6 -40
- package/src/scaffolds/createCoreSchema.ts +6 -18
- package/src/scaffolds/createDatasource.js +26 -61
- package/src/scaffolds/createDatasource.ts +26 -40
- package/src/scaffolds/createDatasourceProvider.js +19 -56
- package/src/scaffolds/createDatasourceProvider.ts +20 -34
- package/src/scaffolds/createPresenterFactory.js +67 -94
- package/src/scaffolds/createPresenterFactory.ts +7 -19
- package/src/scaffolds/createProgram.js +1 -5
- package/src/scaffolds/createResponse.js +3 -11
- package/src/scaffolds/createResponse.ts +3 -1
- package/src/scaffolds/createSchemaRule.js +3 -8
- package/src/scaffolds/createSchemaRule.ts +3 -1
- package/src/scaffolds/createTranslationManager.js +3 -14
- package/src/scaffolds/createTranslationManager.ts +3 -1
- package/src/utils/contextUtils.js +5 -20
- package/src/utils/contextUtils.ts +2 -3
- package/src/utils/fileUtils.js +3 -38
- package/src/utils/fileUtils.ts +0 -26
- package/src/utils/loadConfig.js +1 -14
- package/src/utils/loadConfig.ts +1 -3
- package/src/utils/sharedFoundation.js +48 -0
- package/src/utils/sharedFoundation.ts +70 -0
|
@@ -5,7 +5,6 @@ import { normalizeContexts } from '../../init/initAliases.js';
|
|
|
5
5
|
import { loadUserConfig } from '../../utils/loadConfig.js';
|
|
6
6
|
import { toKebabCase, toPascalCase } from '../../utils/contextUtils.js';
|
|
7
7
|
import { updateIndexTs, writeIfNotExists } from '../../utils/fileUtils.js';
|
|
8
|
-
|
|
9
8
|
const parseInterfaceNames = (rawValue) =>
|
|
10
9
|
String(rawValue ?? '')
|
|
11
10
|
.split(',')
|
|
@@ -13,35 +12,27 @@ const parseInterfaceNames = (rawValue) =>
|
|
|
13
12
|
.filter(Boolean)
|
|
14
13
|
.map((item) => toPascalCase(item))
|
|
15
14
|
.filter(Boolean);
|
|
16
|
-
|
|
17
15
|
const toFileNameFromInterface = (interfaceName) => interfaceName.replace(/^I/, '') || 'Type';
|
|
18
|
-
|
|
19
16
|
const validateInterfaceNames = (rawValue) => {
|
|
20
17
|
const names = parseInterfaceNames(rawValue);
|
|
21
18
|
if (!names.length) return 'Provide at least one interface name';
|
|
22
|
-
|
|
23
19
|
for (const name of names) {
|
|
24
20
|
if (!name.startsWith('I')) {
|
|
25
21
|
return `Interface "${name}" must start with "I"`;
|
|
26
22
|
}
|
|
27
23
|
}
|
|
28
|
-
|
|
29
24
|
return true;
|
|
30
25
|
};
|
|
31
|
-
|
|
32
26
|
const createInterfaceContent = (name) => `export interface ${name} {
|
|
33
27
|
\t[key: string]: unknown;
|
|
34
28
|
}
|
|
35
29
|
`;
|
|
36
|
-
|
|
37
30
|
const writeRootIndex = async (domainPath) => {
|
|
38
31
|
const content = `export * from './model';
|
|
39
32
|
export * from './ports';
|
|
40
33
|
`;
|
|
41
|
-
|
|
42
34
|
await fs.writeFile(path.join(domainPath, 'index.ts'), content, 'utf-8');
|
|
43
35
|
};
|
|
44
|
-
|
|
45
36
|
const selectContext = async () => {
|
|
46
37
|
const config = await loadUserConfig();
|
|
47
38
|
const contexts = normalizeContexts(config.contexts);
|
|
@@ -49,7 +40,6 @@ const selectContext = async () => {
|
|
|
49
40
|
console.error('❌ Cannot generate domain: `contexts` is missing or empty in azure-net.config.ts/js');
|
|
50
41
|
return null;
|
|
51
42
|
}
|
|
52
|
-
|
|
53
43
|
const { context } = await prompts({
|
|
54
44
|
type: 'select',
|
|
55
45
|
name: 'context',
|
|
@@ -57,21 +47,16 @@ const selectContext = async () => {
|
|
|
57
47
|
choices: contexts.map((item) => ({ title: item.name, value: item.name })),
|
|
58
48
|
initial: 0
|
|
59
49
|
});
|
|
60
|
-
|
|
61
50
|
return context ? String(context) : null;
|
|
62
51
|
};
|
|
63
|
-
|
|
64
52
|
const createInterfacesInLayer = async (layerPath, names) => {
|
|
65
53
|
for (const interfaceName of names) {
|
|
66
54
|
const fileName = toFileNameFromInterface(interfaceName);
|
|
67
55
|
const filePath = path.join(layerPath, `${fileName}.ts`);
|
|
68
|
-
// eslint-disable-next-line no-await-in-loop
|
|
69
56
|
await writeIfNotExists(filePath, createInterfaceContent(interfaceName));
|
|
70
57
|
}
|
|
71
|
-
|
|
72
58
|
await updateIndexTs(layerPath);
|
|
73
59
|
};
|
|
74
|
-
|
|
75
60
|
export default async function generateDomain(options = {}) {
|
|
76
61
|
const { entityRaw } = await prompts({
|
|
77
62
|
type: 'text',
|
|
@@ -80,7 +65,6 @@ export default async function generateDomain(options = {}) {
|
|
|
80
65
|
initial: options.entityName ?? '',
|
|
81
66
|
validate: (value) => (String(value ?? '').trim().length > 0 ? true : 'Entity name is required')
|
|
82
67
|
});
|
|
83
|
-
|
|
84
68
|
let context = options.contextName ? String(options.contextName) : null;
|
|
85
69
|
if (!context) {
|
|
86
70
|
context = await selectContext();
|
|
@@ -89,22 +73,18 @@ export default async function generateDomain(options = {}) {
|
|
|
89
73
|
process.exitCode = 1;
|
|
90
74
|
return null;
|
|
91
75
|
}
|
|
92
|
-
|
|
93
76
|
const entityName = toKebabCase(String(entityRaw ?? '').trim()) || 'entity';
|
|
94
77
|
const domainPath = path.join(process.cwd(), 'src', 'app', context, 'layers', 'domain', entityName);
|
|
95
78
|
const modelPath = path.join(domainPath, 'model');
|
|
96
79
|
const portsPath = path.join(domainPath, 'ports');
|
|
97
|
-
|
|
98
80
|
await fs.mkdir(modelPath, { recursive: true });
|
|
99
81
|
await fs.mkdir(portsPath, { recursive: true });
|
|
100
|
-
|
|
101
82
|
const { shouldCreateModels } = await prompts({
|
|
102
83
|
type: 'confirm',
|
|
103
84
|
name: 'shouldCreateModels',
|
|
104
85
|
message: 'Create model interfaces?',
|
|
105
86
|
initial: true
|
|
106
87
|
});
|
|
107
|
-
|
|
108
88
|
if (shouldCreateModels) {
|
|
109
89
|
const { modelNamesRaw } = await prompts({
|
|
110
90
|
type: 'text',
|
|
@@ -112,20 +92,17 @@ export default async function generateDomain(options = {}) {
|
|
|
112
92
|
message: 'Model interface names (comma separated, start with I):',
|
|
113
93
|
validate: validateInterfaceNames
|
|
114
94
|
});
|
|
115
|
-
|
|
116
95
|
const modelNames = parseInterfaceNames(modelNamesRaw);
|
|
117
96
|
await createInterfacesInLayer(modelPath, modelNames);
|
|
118
97
|
} else {
|
|
119
98
|
await updateIndexTs(modelPath);
|
|
120
99
|
}
|
|
121
|
-
|
|
122
100
|
const { shouldCreatePorts } = await prompts({
|
|
123
101
|
type: 'confirm',
|
|
124
102
|
name: 'shouldCreatePorts',
|
|
125
103
|
message: 'Create port interfaces?',
|
|
126
104
|
initial: true
|
|
127
105
|
});
|
|
128
|
-
|
|
129
106
|
if (shouldCreatePorts) {
|
|
130
107
|
const { portNamesRaw } = await prompts({
|
|
131
108
|
type: 'text',
|
|
@@ -133,13 +110,11 @@ export default async function generateDomain(options = {}) {
|
|
|
133
110
|
message: 'Port interface names (comma separated, start with I):',
|
|
134
111
|
validate: validateInterfaceNames
|
|
135
112
|
});
|
|
136
|
-
|
|
137
113
|
const portNames = parseInterfaceNames(portNamesRaw);
|
|
138
114
|
await createInterfacesInLayer(portsPath, portNames);
|
|
139
115
|
} else {
|
|
140
116
|
await updateIndexTs(portsPath);
|
|
141
117
|
}
|
|
142
|
-
|
|
143
118
|
await writeRootIndex(domainPath);
|
|
144
119
|
console.log(`✅ Domain generated: ${domainPath}`);
|
|
145
120
|
return { contextName: context, domainName: entityName, domainPath };
|
|
@@ -4,7 +4,6 @@ import prompts from 'prompts';
|
|
|
4
4
|
import generateDomain from './generateDomain.js';
|
|
5
5
|
import generateRepository from './generateRepository.js';
|
|
6
6
|
import generatePresenter from './generatePresenter.js';
|
|
7
|
-
|
|
8
7
|
const findProviderFile = async (contextName, layerName, preferredFileName) => {
|
|
9
8
|
const providersPath = path.join(process.cwd(), 'src', 'app', contextName, 'layers', layerName, 'providers');
|
|
10
9
|
const preferredPath = path.join(providersPath, preferredFileName);
|
|
@@ -21,7 +20,6 @@ const findProviderFile = async (contextName, layerName, preferredFileName) => {
|
|
|
21
20
|
}
|
|
22
21
|
}
|
|
23
22
|
};
|
|
24
|
-
|
|
25
23
|
const parseProviderConstName = async (providerPath, fallbackName) => {
|
|
26
24
|
try {
|
|
27
25
|
const content = await fs.readFile(providerPath, 'utf-8');
|
|
@@ -31,29 +29,24 @@ const parseProviderConstName = async (providerPath, fallbackName) => {
|
|
|
31
29
|
return fallbackName;
|
|
32
30
|
}
|
|
33
31
|
};
|
|
34
|
-
|
|
35
32
|
export default async function generateModule() {
|
|
36
33
|
const domainResult = await generateDomain();
|
|
37
34
|
if (!domainResult) {
|
|
38
35
|
process.exitCode = 1;
|
|
39
36
|
return;
|
|
40
37
|
}
|
|
41
|
-
|
|
42
38
|
const repositoryResult = await generateRepository({
|
|
43
39
|
contextName: domainResult.contextName,
|
|
44
40
|
domainName: domainResult.domainName,
|
|
45
41
|
forceCreateUseCases: true
|
|
46
42
|
});
|
|
47
|
-
|
|
48
43
|
if (!repositoryResult) {
|
|
49
44
|
process.exitCode = 1;
|
|
50
45
|
return;
|
|
51
46
|
}
|
|
52
|
-
|
|
53
47
|
const infrastructureProviderPath = await findProviderFile(repositoryResult.contextName, 'infrastructure', 'InfrastructureProvider.ts');
|
|
54
48
|
const applicationProviderPath = await findProviderFile(repositoryResult.contextName, 'application', 'ApplicationProvider.ts');
|
|
55
49
|
const infrastructureProviderName = await parseProviderConstName(infrastructureProviderPath, 'InfrastructureProvider');
|
|
56
|
-
|
|
57
50
|
console.log('\n⚠️ Manual provider registration is required before presenter generation.');
|
|
58
51
|
console.log(`Infrastructure provider file: ${infrastructureProviderPath}`);
|
|
59
52
|
console.log(`Application provider file: ${applicationProviderPath}`);
|
|
@@ -64,19 +57,16 @@ export default async function generateModule() {
|
|
|
64
57
|
console.log(
|
|
65
58
|
`- Application register: ${repositoryResult.useCasesName}: () => new ${repositoryResult.useCasesName}(${infrastructureProviderName}().${repositoryResult.repositoryName}),`
|
|
66
59
|
);
|
|
67
|
-
|
|
68
60
|
const { isReadyForPresenter } = await prompts({
|
|
69
61
|
type: 'confirm',
|
|
70
62
|
name: 'isReadyForPresenter',
|
|
71
63
|
message: 'Did you register repository/use-cases in providers and want to continue?',
|
|
72
64
|
initial: false
|
|
73
65
|
});
|
|
74
|
-
|
|
75
66
|
if (!isReadyForPresenter) {
|
|
76
67
|
console.log('ℹ️ Module flow paused. Complete provider wiring and rerun `azure-net generate presenter`.');
|
|
77
68
|
return;
|
|
78
69
|
}
|
|
79
|
-
|
|
80
70
|
await generatePresenter({
|
|
81
71
|
contextName: repositoryResult.contextName,
|
|
82
72
|
useCasesName: repositoryResult.useCasesName
|
|
@@ -11,35 +11,30 @@ import {
|
|
|
11
11
|
getConfigState,
|
|
12
12
|
getRepositoryMeta,
|
|
13
13
|
resolveContextAlias,
|
|
14
|
-
resolveCoreDatasourcesPath,
|
|
15
14
|
resolveDatasourcesPath,
|
|
16
15
|
resolveDomainRootPath,
|
|
17
16
|
resolveRepositoriesPath,
|
|
17
|
+
resolveSharedDatasourcesPath,
|
|
18
18
|
selectContext,
|
|
19
19
|
writeRepositoryInterface
|
|
20
20
|
} from './repositoryModuleShared.js';
|
|
21
|
-
|
|
21
|
+
import { getFoundationConstructImportPath } from '../../utils/sharedFoundation.js';
|
|
22
22
|
const toInterfaceFileName = (interfaceName) => `${String(interfaceName ?? '').replace(/^I/, '') || 'Type'}.ts`;
|
|
23
|
-
|
|
24
23
|
const createInterfaceContent = (interfaceName) => `export interface ${interfaceName} {
|
|
25
24
|
\t[key: string]: unknown;
|
|
26
25
|
}
|
|
27
26
|
`;
|
|
28
|
-
|
|
29
27
|
const writeDomainIndexes = async (domainPath, modelPath, portsPath) => {
|
|
30
28
|
await updateIndexTs(modelPath);
|
|
31
29
|
await updateIndexTs(portsPath);
|
|
32
30
|
await fs.writeFile(path.join(domainPath, 'index.ts'), `export * from './model';\nexport * from './ports';\n`, 'utf-8');
|
|
33
31
|
};
|
|
34
|
-
|
|
35
32
|
const ensureDomainScaffold = async ({ contextName, entityNamePascal, domainName }) => {
|
|
36
33
|
const domainPath = resolveDomainRootPath(contextName, domainName);
|
|
37
34
|
const modelPath = path.join(domainPath, 'model');
|
|
38
35
|
const portsPath = path.join(domainPath, 'ports');
|
|
39
|
-
|
|
40
36
|
await fs.mkdir(modelPath, { recursive: true });
|
|
41
37
|
await fs.mkdir(portsPath, { recursive: true });
|
|
42
|
-
|
|
43
38
|
const modelInterfaces = [`I${entityNamePascal}`];
|
|
44
39
|
const portInterfaces = [
|
|
45
40
|
`I${entityNamePascal}CreateRequest`,
|
|
@@ -47,49 +42,36 @@ const ensureDomainScaffold = async ({ contextName, entityNamePascal, domainName
|
|
|
47
42
|
`I${entityNamePascal}CollectionResponse`,
|
|
48
43
|
`I${entityNamePascal}CollectionQuery`
|
|
49
44
|
];
|
|
50
|
-
|
|
51
45
|
for (const interfaceName of modelInterfaces) {
|
|
52
46
|
const filePath = path.join(modelPath, toInterfaceFileName(interfaceName));
|
|
53
|
-
// eslint-disable-next-line no-await-in-loop
|
|
54
47
|
await writeIfNotExists(filePath, createInterfaceContent(interfaceName));
|
|
55
48
|
}
|
|
56
|
-
|
|
57
49
|
for (const interfaceName of portInterfaces) {
|
|
58
50
|
const filePath = path.join(portsPath, toInterfaceFileName(interfaceName));
|
|
59
|
-
// eslint-disable-next-line no-await-in-loop
|
|
60
51
|
await writeIfNotExists(filePath, createInterfaceContent(interfaceName));
|
|
61
52
|
}
|
|
62
|
-
|
|
63
53
|
await writeDomainIndexes(domainPath, modelPath, portsPath);
|
|
64
54
|
return { domainPath, modelPath, portsPath };
|
|
65
55
|
};
|
|
66
|
-
|
|
67
56
|
const resolveDatasourceForPreset = async (contextName) => {
|
|
68
|
-
const { contexts,
|
|
57
|
+
const { contexts, sharedAlias } = await getConfigState();
|
|
69
58
|
const contextAlias = resolveContextAlias(contexts, contextName);
|
|
70
|
-
|
|
71
|
-
const coreDatasources = await getAvailableTsNames(resolveCoreDatasourcesPath());
|
|
59
|
+
const sharedDatasources = await getAvailableTsNames(await resolveSharedDatasourcesPath());
|
|
72
60
|
const contextDatasources = await getAvailableTsNames(resolveDatasourcesPath(contextName));
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return { name: 'ApiDatasource', importPath: `${coreAlias}/datasource` };
|
|
61
|
+
if (sharedDatasources.includes('ApiDatasource')) {
|
|
62
|
+
return { name: 'ApiDatasource', importPath: getFoundationConstructImportPath(sharedAlias, 'datasource') };
|
|
76
63
|
}
|
|
77
|
-
|
|
78
64
|
if (contextDatasources.includes('ApiDatasource')) {
|
|
79
65
|
return { name: 'ApiDatasource', importPath: `${contextAlias}/layers/infrastructure/http/datasources` };
|
|
80
66
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
return { name: coreDatasources[0], importPath: `${coreAlias}/datasource` };
|
|
67
|
+
if (sharedDatasources.length) {
|
|
68
|
+
return { name: sharedDatasources[0], importPath: getFoundationConstructImportPath(sharedAlias, 'datasource') };
|
|
84
69
|
}
|
|
85
|
-
|
|
86
70
|
if (contextDatasources.length) {
|
|
87
71
|
return { name: contextDatasources[0], importPath: `${contextAlias}/layers/infrastructure/http/datasources` };
|
|
88
72
|
}
|
|
89
|
-
|
|
90
73
|
return null;
|
|
91
74
|
};
|
|
92
|
-
|
|
93
75
|
const buildPresetMethods = ({ entityNamePascal, route, pathParamType }) => [
|
|
94
76
|
{
|
|
95
77
|
name: 'collection',
|
|
@@ -137,7 +119,6 @@ const buildPresetMethods = ({ entityNamePascal, route, pathParamType }) => [
|
|
|
137
119
|
pathParamType
|
|
138
120
|
}
|
|
139
121
|
];
|
|
140
|
-
|
|
141
122
|
const findProviderFile = async (contextName, layerName, preferredFileName) => {
|
|
142
123
|
const providersPath = path.join(process.cwd(), 'src', 'app', contextName, 'layers', layerName, 'providers');
|
|
143
124
|
const preferredPath = path.join(providersPath, preferredFileName);
|
|
@@ -154,7 +135,6 @@ const findProviderFile = async (contextName, layerName, preferredFileName) => {
|
|
|
154
135
|
}
|
|
155
136
|
}
|
|
156
137
|
};
|
|
157
|
-
|
|
158
138
|
const parseProviderConstName = async (providerPath, fallbackName) => {
|
|
159
139
|
try {
|
|
160
140
|
const content = await fs.readFile(providerPath, 'utf-8');
|
|
@@ -164,21 +144,18 @@ const parseProviderConstName = async (providerPath, fallbackName) => {
|
|
|
164
144
|
return fallbackName;
|
|
165
145
|
}
|
|
166
146
|
};
|
|
167
|
-
|
|
168
147
|
export default async function generateModulePreset() {
|
|
169
148
|
const contextName = await selectContext('Select context for preset module:');
|
|
170
149
|
if (!contextName) {
|
|
171
150
|
process.exitCode = 1;
|
|
172
151
|
return;
|
|
173
152
|
}
|
|
174
|
-
|
|
175
153
|
const { entityNameRaw } = await prompts({
|
|
176
154
|
type: 'text',
|
|
177
155
|
name: 'entityNameRaw',
|
|
178
156
|
message: 'Module name:',
|
|
179
157
|
validate: (value) => (String(value ?? '').trim().length > 0 ? true : 'Module name is required')
|
|
180
158
|
});
|
|
181
|
-
|
|
182
159
|
const { routeRaw } = await prompts({
|
|
183
160
|
type: 'text',
|
|
184
161
|
name: 'routeRaw',
|
|
@@ -190,7 +167,6 @@ export default async function generateModulePreset() {
|
|
|
190
167
|
return route.startsWith('/') ? true : 'Path must start with "/"';
|
|
191
168
|
}
|
|
192
169
|
});
|
|
193
|
-
|
|
194
170
|
const { pathParamType } = await prompts({
|
|
195
171
|
type: 'select',
|
|
196
172
|
name: 'pathParamType',
|
|
@@ -201,51 +177,42 @@ export default async function generateModulePreset() {
|
|
|
201
177
|
],
|
|
202
178
|
initial: 0
|
|
203
179
|
});
|
|
204
|
-
|
|
205
180
|
const entityNamePascal = toPascalCase(String(entityNameRaw ?? '').trim());
|
|
206
181
|
if (!entityNamePascal) {
|
|
207
182
|
console.error('❌ Invalid module name.');
|
|
208
183
|
process.exitCode = 1;
|
|
209
184
|
return;
|
|
210
185
|
}
|
|
211
|
-
|
|
212
186
|
const route = String(routeRaw ?? '').trim();
|
|
213
187
|
if (!route) {
|
|
214
188
|
console.error('❌ Invalid route.');
|
|
215
189
|
process.exitCode = 1;
|
|
216
190
|
return;
|
|
217
191
|
}
|
|
218
|
-
|
|
219
192
|
const resolvedPathParamType = pathParamType === 'number' ? 'number' : 'string';
|
|
220
193
|
const domainName = toKebabCase(entityNamePascal);
|
|
221
|
-
|
|
222
194
|
await ensureDomainScaffold({ contextName, entityNamePascal, domainName });
|
|
223
|
-
|
|
224
195
|
const datasource = await resolveDatasourceForPreset(contextName);
|
|
225
196
|
if (!datasource) {
|
|
226
|
-
console.error('❌ No datasource found in
|
|
197
|
+
console.error('❌ No datasource found in shared foundation or selected context. Create datasource first.');
|
|
227
198
|
process.exitCode = 1;
|
|
228
199
|
return;
|
|
229
200
|
}
|
|
230
|
-
|
|
231
201
|
const methods = buildPresetMethods({
|
|
232
202
|
entityNamePascal,
|
|
233
203
|
route,
|
|
234
204
|
pathParamType: resolvedPathParamType
|
|
235
205
|
});
|
|
236
|
-
|
|
237
206
|
const repositoryClassName = `${entityNamePascal}Repository`;
|
|
238
207
|
const meta = getRepositoryMeta(repositoryClassName);
|
|
239
208
|
const { contexts } = await getConfigState();
|
|
240
209
|
const contextAlias = resolveContextAlias(contexts, contextName);
|
|
241
|
-
|
|
242
210
|
await writeRepositoryInterface({
|
|
243
211
|
contextName,
|
|
244
212
|
domainName,
|
|
245
213
|
meta,
|
|
246
214
|
methods
|
|
247
215
|
});
|
|
248
|
-
|
|
249
216
|
const repositoryContent = buildRepositoryContent({
|
|
250
217
|
meta,
|
|
251
218
|
contextAlias,
|
|
@@ -253,30 +220,25 @@ export default async function generateModulePreset() {
|
|
|
253
220
|
datasource,
|
|
254
221
|
methods
|
|
255
222
|
});
|
|
256
|
-
|
|
257
223
|
const repositoriesPath = resolveRepositoriesPath(contextName);
|
|
258
224
|
await fs.mkdir(repositoriesPath, { recursive: true });
|
|
259
225
|
const repositoryPath = path.join(repositoriesPath, `${meta.className}.ts`);
|
|
260
226
|
const createdRepository = await writeIfNotExists(repositoryPath, repositoryContent);
|
|
261
227
|
await updateIndexTs(repositoriesPath);
|
|
262
|
-
|
|
263
228
|
if (!createdRepository) {
|
|
264
|
-
console.error(`❌ Repository
|
|
229
|
+
console.error(`❌ Repository "${meta.className}" already exists. Preset flow stopped.`);
|
|
265
230
|
process.exitCode = 1;
|
|
266
231
|
return;
|
|
267
232
|
}
|
|
268
|
-
|
|
269
233
|
await createUseCasesForRepository({
|
|
270
234
|
contextName,
|
|
271
235
|
contextAlias,
|
|
272
236
|
domainName,
|
|
273
237
|
repositoryName: meta.className
|
|
274
238
|
});
|
|
275
|
-
|
|
276
239
|
const infrastructureProviderPath = await findProviderFile(contextName, 'infrastructure', 'InfrastructureProvider.ts');
|
|
277
240
|
const applicationProviderPath = await findProviderFile(contextName, 'application', 'ApplicationProvider.ts');
|
|
278
241
|
const infrastructureProviderName = await parseProviderConstName(infrastructureProviderPath, 'InfrastructureProvider');
|
|
279
|
-
|
|
280
242
|
console.log('\n⚠️ Manual provider registration is required before presenter generation.');
|
|
281
243
|
console.log(`Infrastructure provider file: ${infrastructureProviderPath}`);
|
|
282
244
|
console.log(`Application provider file: ${applicationProviderPath}`);
|
|
@@ -285,13 +247,11 @@ export default async function generateModulePreset() {
|
|
|
285
247
|
console.log(
|
|
286
248
|
`- Application register: ${meta.useCasesClassName}: () => new ${meta.useCasesClassName}(${infrastructureProviderName}().${meta.className}),`
|
|
287
249
|
);
|
|
288
|
-
|
|
289
250
|
const { readyAnswer } = await prompts({
|
|
290
251
|
type: 'text',
|
|
291
252
|
name: 'readyAnswer',
|
|
292
253
|
message: 'Type "y" when provider wiring is done:'
|
|
293
254
|
});
|
|
294
|
-
|
|
295
255
|
const normalizedReadyAnswer = String(readyAnswer ?? '')
|
|
296
256
|
.trim()
|
|
297
257
|
.toLowerCase();
|
|
@@ -299,7 +259,6 @@ export default async function generateModulePreset() {
|
|
|
299
259
|
console.log('ℹ️ Preset module flow paused. Complete provider wiring and run `azure-net generate presenter`.');
|
|
300
260
|
return;
|
|
301
261
|
}
|
|
302
|
-
|
|
303
262
|
await generatePresenter({
|
|
304
263
|
contextName,
|
|
305
264
|
useCasesName: meta.useCasesClassName
|
|
@@ -11,13 +11,14 @@ import {
|
|
|
11
11
|
getConfigState,
|
|
12
12
|
getRepositoryMeta,
|
|
13
13
|
resolveContextAlias,
|
|
14
|
-
resolveCoreDatasourcesPath,
|
|
15
14
|
resolveDatasourcesPath,
|
|
16
15
|
resolveDomainRootPath,
|
|
17
16
|
resolveRepositoriesPath,
|
|
17
|
+
resolveSharedDatasourcesPath,
|
|
18
18
|
selectContext,
|
|
19
19
|
writeRepositoryInterface
|
|
20
20
|
} from './repositoryModuleShared.js';
|
|
21
|
+
import { getFoundationConstructImportPath } from '../../utils/sharedFoundation.js';
|
|
21
22
|
|
|
22
23
|
type DatasourceDescriptor = { name: string; importPath: string };
|
|
23
24
|
|
|
@@ -83,22 +84,22 @@ const ensureDomainScaffold = async ({
|
|
|
83
84
|
};
|
|
84
85
|
|
|
85
86
|
const resolveDatasourceForPreset = async (contextName: string): Promise<DatasourceDescriptor | null> => {
|
|
86
|
-
const { contexts,
|
|
87
|
+
const { contexts, sharedAlias } = await getConfigState();
|
|
87
88
|
const contextAlias = resolveContextAlias(contexts, contextName);
|
|
88
89
|
|
|
89
|
-
const
|
|
90
|
+
const sharedDatasources = await getAvailableTsNames(await resolveSharedDatasourcesPath());
|
|
90
91
|
const contextDatasources = await getAvailableTsNames(resolveDatasourcesPath(contextName));
|
|
91
92
|
|
|
92
|
-
if (
|
|
93
|
-
return { name: 'ApiDatasource', importPath:
|
|
93
|
+
if (sharedDatasources.includes('ApiDatasource')) {
|
|
94
|
+
return { name: 'ApiDatasource', importPath: getFoundationConstructImportPath(sharedAlias, 'datasource') };
|
|
94
95
|
}
|
|
95
96
|
|
|
96
97
|
if (contextDatasources.includes('ApiDatasource')) {
|
|
97
98
|
return { name: 'ApiDatasource', importPath: `${contextAlias}/layers/infrastructure/http/datasources` };
|
|
98
99
|
}
|
|
99
100
|
|
|
100
|
-
if (
|
|
101
|
-
return { name:
|
|
101
|
+
if (sharedDatasources.length) {
|
|
102
|
+
return { name: sharedDatasources[0] as string, importPath: getFoundationConstructImportPath(sharedAlias, 'datasource') };
|
|
102
103
|
}
|
|
103
104
|
|
|
104
105
|
if (contextDatasources.length) {
|
|
@@ -253,7 +254,7 @@ export default async function generateModulePreset(): Promise<void> {
|
|
|
253
254
|
|
|
254
255
|
const datasource = await resolveDatasourceForPreset(contextName);
|
|
255
256
|
if (!datasource) {
|
|
256
|
-
console.error('❌ No datasource found in
|
|
257
|
+
console.error('❌ No datasource found in shared foundation or selected context. Create datasource first.');
|
|
257
258
|
process.exitCode = 1;
|
|
258
259
|
return;
|
|
259
260
|
}
|