@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
|
@@ -4,6 +4,7 @@ import path from 'node:path';
|
|
|
4
4
|
import prompts from 'prompts';
|
|
5
5
|
import { writeIfNotExists, updateIndexTs } from '../utils/fileUtils.js';
|
|
6
6
|
import { toPascalCase } from '../utils/contextUtils.js';
|
|
7
|
+
import { getFoundationConstructPath, getSharedState } from '../utils/sharedFoundation.js';
|
|
7
8
|
|
|
8
9
|
type MessagePreset = 'ru' | 'en' | 'i18n';
|
|
9
10
|
type ConfigPath = 'ts' | 'js';
|
|
@@ -48,10 +49,9 @@ const buildDefaultSchemaFactoryConfigEntry = (factoryName: string): string => {
|
|
|
48
49
|
const upsertDefaultSchemaFactoryConfig = (content: string, factoryName: string): string => {
|
|
49
50
|
const hasExportDefaultObject = /export\s+default\s*\{[\s\S]*\}\s*;?/.test(content);
|
|
50
51
|
const defaultFactoryEntry = buildDefaultSchemaFactoryConfigEntry(factoryName);
|
|
51
|
-
const coreAliasEntry = `coreAlias: '$core'`;
|
|
52
52
|
|
|
53
53
|
if (!hasExportDefaultObject) {
|
|
54
|
-
return `export default {\n\t${
|
|
54
|
+
return `export default {\n\t${defaultFactoryEntry}\n};\n`;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
let nextContent = content;
|
|
@@ -71,20 +71,7 @@ const upsertDefaultSchemaFactoryConfig = (content: string, factoryName: string):
|
|
|
71
71
|
return `export default {${withComma}\n\t${defaultFactoryEntry}\n};`;
|
|
72
72
|
});
|
|
73
73
|
}
|
|
74
|
-
|
|
75
|
-
if (/coreAlias\s*:/.test(nextContent)) {
|
|
76
|
-
return nextContent.replace(/coreAlias\s*:\s*['"`][^'"`]+['"`]/, coreAliasEntry);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return nextContent.replace(/export\s+default\s*\{([\s\S]*)\}\s*;?/, (_full, body: string) => {
|
|
80
|
-
const trimmedRight = body.replace(/\s*$/, '');
|
|
81
|
-
if (!trimmedRight.length) {
|
|
82
|
-
return `export default {\n\t${coreAliasEntry}\n};`;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const withComma = trimmedRight.endsWith(',') ? trimmedRight : `${trimmedRight},`;
|
|
86
|
-
return `export default {${withComma}\n\t${coreAliasEntry}\n};`;
|
|
87
|
-
});
|
|
74
|
+
return nextContent;
|
|
88
75
|
};
|
|
89
76
|
|
|
90
77
|
export default async function createCoreSchema(): Promise<void> {
|
|
@@ -111,7 +98,8 @@ export default async function createCoreSchema(): Promise<void> {
|
|
|
111
98
|
|
|
112
99
|
const selectedPreset = (preset ?? 'i18n') as MessagePreset;
|
|
113
100
|
const messagesImportName = resolvePresetImportName(selectedPreset);
|
|
114
|
-
const
|
|
101
|
+
const { sharedContext } = await getSharedState();
|
|
102
|
+
const coreSchemaPath = getFoundationConstructPath(sharedContext.name, 'schema');
|
|
115
103
|
const customRulesPath = path.join(coreSchemaPath, 'custom-rules');
|
|
116
104
|
const filePath = path.join(coreSchemaPath, `${schemaFactoryName}.ts`);
|
|
117
105
|
|
|
@@ -123,7 +111,7 @@ export default async function createCoreSchema(): Promise<void> {
|
|
|
123
111
|
console.log(`⚠️ Schema factory "${schemaFactoryName}" already exists. File was not overwritten.`);
|
|
124
112
|
} else {
|
|
125
113
|
await updateIndexTs(coreSchemaPath);
|
|
126
|
-
console.log(`✅
|
|
114
|
+
console.log(`✅ Shared schema factory created: ${filePath}`);
|
|
127
115
|
}
|
|
128
116
|
|
|
129
117
|
const { useAsDefault } = await prompts({
|
|
@@ -3,9 +3,9 @@ import path from 'node:path';
|
|
|
3
3
|
import prompts from 'prompts';
|
|
4
4
|
import { writeIfNotExists, updateIndexTs } from '../utils/fileUtils.js';
|
|
5
5
|
import { toPascalCase } from '../utils/contextUtils.js';
|
|
6
|
-
import { loadUserConfig
|
|
6
|
+
import { loadUserConfig } from '../utils/loadConfig.js';
|
|
7
7
|
import { normalizeContexts } from '../init/initAliases.js';
|
|
8
|
-
|
|
8
|
+
import { getFoundationConstructImportPath, getFoundationConstructPath, getSharedState } from '../utils/sharedFoundation.js';
|
|
9
9
|
const createDatasourceTemplateWithoutResponse = (
|
|
10
10
|
className
|
|
11
11
|
) => `import { BaseHttpDatasource, type CreateRequestCallbackType } from '@azure-net/kit/infra';
|
|
@@ -16,13 +16,12 @@ export class ${className} extends BaseHttpDatasource {
|
|
|
16
16
|
\t}
|
|
17
17
|
}
|
|
18
18
|
`;
|
|
19
|
-
|
|
20
19
|
const createDatasourceTemplateWithResponseAndInterface = (
|
|
21
20
|
className,
|
|
22
21
|
responseName,
|
|
23
|
-
|
|
22
|
+
responseImportPath
|
|
24
23
|
) => `import { BaseHttpDatasource, type CreateRequestCallbackType } from '@azure-net/kit/infra';
|
|
25
|
-
import { ${responseName}, type I${responseName} } from '${
|
|
24
|
+
import { ${responseName}, type I${responseName} } from '${responseImportPath}';
|
|
26
25
|
|
|
27
26
|
export class ${className} extends BaseHttpDatasource {
|
|
28
27
|
\tasync createRequest<T>(callback: CreateRequestCallbackType<I${responseName}<T>>) {
|
|
@@ -30,13 +29,12 @@ export class ${className} extends BaseHttpDatasource {
|
|
|
30
29
|
\t}
|
|
31
30
|
}
|
|
32
31
|
`;
|
|
33
|
-
|
|
34
32
|
const createDatasourceTemplateWithResponse = (
|
|
35
33
|
className,
|
|
36
34
|
responseName,
|
|
37
|
-
|
|
35
|
+
responseImportPath
|
|
38
36
|
) => `import { BaseHttpDatasource, type CreateRequestCallbackType } from '@azure-net/kit/infra';
|
|
39
|
-
import { ${responseName} } from '${
|
|
37
|
+
import { ${responseName} } from '${responseImportPath}';
|
|
40
38
|
|
|
41
39
|
export class ${className} extends BaseHttpDatasource {
|
|
42
40
|
\tasync createRequest<T>(callback: CreateRequestCallbackType<T>) {
|
|
@@ -44,26 +42,22 @@ export class ${className} extends BaseHttpDatasource {
|
|
|
44
42
|
\t}
|
|
45
43
|
}
|
|
46
44
|
`;
|
|
47
|
-
|
|
48
45
|
const ensureDatasourceClassName = (rawName) => {
|
|
49
46
|
const normalized = toPascalCase(rawName || 'MockApi');
|
|
50
47
|
return normalized.endsWith('Datasource') ? normalized : `${normalized}Datasource`;
|
|
51
48
|
};
|
|
52
|
-
|
|
53
49
|
const getContextChoices = async () => {
|
|
54
50
|
const config = await loadUserConfig();
|
|
55
51
|
const contexts = normalizeContexts(config.contexts);
|
|
56
|
-
|
|
57
|
-
const choices = [{ title: 'core', value: 'core' }];
|
|
52
|
+
const choices = [{ title: 'shared foundation', value: '__shared__' }];
|
|
58
53
|
for (const context of contexts) {
|
|
59
54
|
choices.push({ title: context.name, value: context.name });
|
|
60
55
|
}
|
|
61
|
-
|
|
62
56
|
return choices;
|
|
63
57
|
};
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
const responsesPath =
|
|
58
|
+
const getSharedResponses = async () => {
|
|
59
|
+
const { sharedContext } = await getSharedState();
|
|
60
|
+
const responsesPath = getFoundationConstructPath(sharedContext.name, 'response');
|
|
67
61
|
try {
|
|
68
62
|
const files = await fs.readdir(responsesPath);
|
|
69
63
|
return files.filter((file) => file.endsWith('.ts') && file !== 'index.ts').map((file) => file.replace(/\.ts$/, ''));
|
|
@@ -71,9 +65,9 @@ const getCoreResponses = async () => {
|
|
|
71
65
|
return [];
|
|
72
66
|
}
|
|
73
67
|
};
|
|
74
|
-
|
|
75
68
|
const hasResponseInterface = async (responseName) => {
|
|
76
|
-
const
|
|
69
|
+
const { sharedContext } = await getSharedState();
|
|
70
|
+
const responsePath = path.join(getFoundationConstructPath(sharedContext.name, 'response'), `${responseName}.ts`);
|
|
77
71
|
try {
|
|
78
72
|
const content = await fs.readFile(responsePath, 'utf-8');
|
|
79
73
|
const interfaceRegex = new RegExp(`export\\s+interface\\s+I${responseName}\\b`);
|
|
@@ -82,36 +76,12 @@ const hasResponseInterface = async (responseName) => {
|
|
|
82
76
|
return false;
|
|
83
77
|
}
|
|
84
78
|
};
|
|
85
|
-
|
|
86
|
-
const getConfiguredCoreAliasOrThrow = async () => {
|
|
87
|
-
const configRef = resolveConfigFile();
|
|
88
|
-
if (!configRef.exists) {
|
|
89
|
-
throw new Error(
|
|
90
|
-
'azure-net.config is not configured. Run "azure-net init folders-structure" and do not forget to fill contexts if you need them.'
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const content = await fs.readFile(configRef.filepath, 'utf-8');
|
|
95
|
-
const aliasMatch = content.match(/coreAlias\s*:\s*['"`]([^'"`]+)['"`]/);
|
|
96
|
-
const alias = aliasMatch?.[1]?.trim();
|
|
97
|
-
|
|
98
|
-
if (!alias) {
|
|
99
|
-
throw new Error(
|
|
100
|
-
'azure-net.config is not configured. Run "azure-net init folders-structure" and do not forget to fill contexts if you need them.'
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return alias.startsWith('$') ? alias : `$${alias}`;
|
|
105
|
-
};
|
|
106
|
-
|
|
107
79
|
const resolveTargetPath = (target) => {
|
|
108
|
-
if (target === '
|
|
109
|
-
|
|
80
|
+
if (target === '__shared__') {
|
|
81
|
+
throw new Error('Shared target path must be resolved async.');
|
|
110
82
|
}
|
|
111
|
-
|
|
112
83
|
return path.join(process.cwd(), 'src', 'app', target, 'layers', 'infrastructure', 'http', 'datasources');
|
|
113
84
|
};
|
|
114
|
-
|
|
115
85
|
export default async function createDatasource() {
|
|
116
86
|
const { datasourceNameRaw } = await prompts({
|
|
117
87
|
type: 'text',
|
|
@@ -119,9 +89,7 @@ export default async function createDatasource() {
|
|
|
119
89
|
message: 'Datasource name:',
|
|
120
90
|
initial: 'MockApi'
|
|
121
91
|
});
|
|
122
|
-
|
|
123
92
|
const className = ensureDatasourceClassName(String(datasourceNameRaw ?? 'MockApi'));
|
|
124
|
-
|
|
125
93
|
const contextChoices = await getContextChoices();
|
|
126
94
|
const { target } = await prompts({
|
|
127
95
|
type: 'select',
|
|
@@ -130,44 +98,41 @@ export default async function createDatasource() {
|
|
|
130
98
|
choices: contextChoices,
|
|
131
99
|
initial: 0
|
|
132
100
|
});
|
|
133
|
-
|
|
134
|
-
const
|
|
135
|
-
const coreResponses = await getCoreResponses();
|
|
136
|
-
|
|
101
|
+
const selectedTarget = String(target ?? '__shared__');
|
|
102
|
+
const sharedResponses = await getSharedResponses();
|
|
137
103
|
let selectedResponse = null;
|
|
138
|
-
if (
|
|
104
|
+
if (sharedResponses.length > 0) {
|
|
139
105
|
const { responseName } = await prompts({
|
|
140
106
|
type: 'select',
|
|
141
107
|
name: 'responseName',
|
|
142
108
|
message: 'Select response for datasource:',
|
|
143
|
-
choices: [{ title: 'No response', value: null }, ...
|
|
109
|
+
choices: [{ title: 'No response', value: null }, ...sharedResponses.map((response) => ({ title: response, value: response }))],
|
|
144
110
|
initial: 0
|
|
145
111
|
});
|
|
146
112
|
selectedResponse = responseName ? String(responseName) : null;
|
|
147
113
|
}
|
|
148
|
-
|
|
149
114
|
let content;
|
|
150
115
|
if (!selectedResponse) {
|
|
151
116
|
content = createDatasourceTemplateWithoutResponse(className);
|
|
152
117
|
} else {
|
|
153
|
-
const
|
|
118
|
+
const { sharedAlias } = await getSharedState();
|
|
119
|
+
const responseImportPath = getFoundationConstructImportPath(sharedAlias, 'response');
|
|
154
120
|
const withInterface = await hasResponseInterface(selectedResponse);
|
|
155
121
|
content = withInterface
|
|
156
|
-
? createDatasourceTemplateWithResponseAndInterface(className, selectedResponse,
|
|
157
|
-
: createDatasourceTemplateWithResponse(className, selectedResponse,
|
|
122
|
+
? createDatasourceTemplateWithResponseAndInterface(className, selectedResponse, responseImportPath)
|
|
123
|
+
: createDatasourceTemplateWithResponse(className, selectedResponse, responseImportPath);
|
|
158
124
|
}
|
|
159
|
-
|
|
160
|
-
|
|
125
|
+
const targetPath =
|
|
126
|
+
selectedTarget === '__shared__'
|
|
127
|
+
? getFoundationConstructPath((await getSharedState()).sharedContext.name, 'datasource')
|
|
128
|
+
: resolveTargetPath(selectedTarget);
|
|
161
129
|
await fs.mkdir(targetPath, { recursive: true });
|
|
162
|
-
|
|
163
130
|
const filePath = path.join(targetPath, `${className}.ts`);
|
|
164
131
|
const created = await writeIfNotExists(filePath, content);
|
|
165
132
|
await updateIndexTs(targetPath);
|
|
166
|
-
|
|
167
133
|
if (!created) {
|
|
168
134
|
console.log(`⚠️ Datasource "${className}" already exists. File was not overwritten.`);
|
|
169
135
|
return;
|
|
170
136
|
}
|
|
171
|
-
|
|
172
137
|
console.log(`✅ Datasource created: ${filePath}`);
|
|
173
138
|
}
|
|
@@ -3,8 +3,9 @@ import path from 'node:path';
|
|
|
3
3
|
import prompts from 'prompts';
|
|
4
4
|
import { writeIfNotExists, updateIndexTs } from '../utils/fileUtils.js';
|
|
5
5
|
import { toPascalCase } from '../utils/contextUtils.js';
|
|
6
|
-
import { loadUserConfig
|
|
6
|
+
import { loadUserConfig } from '../utils/loadConfig.js';
|
|
7
7
|
import { normalizeContexts } from '../init/initAliases.js';
|
|
8
|
+
import { getFoundationConstructImportPath, getFoundationConstructPath, getSharedState } from '../utils/sharedFoundation.js';
|
|
8
9
|
|
|
9
10
|
type ContextChoice = { title: string; value: string };
|
|
10
11
|
|
|
@@ -22,9 +23,9 @@ export class ${className} extends BaseHttpDatasource {
|
|
|
22
23
|
const createDatasourceTemplateWithResponseAndInterface = (
|
|
23
24
|
className: string,
|
|
24
25
|
responseName: string,
|
|
25
|
-
|
|
26
|
+
responseImportPath: string
|
|
26
27
|
): string => `import { BaseHttpDatasource, type CreateRequestCallbackType } from '@azure-net/kit/infra';
|
|
27
|
-
import { ${responseName}, type I${responseName} } from '${
|
|
28
|
+
import { ${responseName}, type I${responseName} } from '${responseImportPath}';
|
|
28
29
|
|
|
29
30
|
export class ${className} extends BaseHttpDatasource {
|
|
30
31
|
\tasync createRequest<T>(callback: CreateRequestCallbackType<I${responseName}<T>>) {
|
|
@@ -36,9 +37,9 @@ export class ${className} extends BaseHttpDatasource {
|
|
|
36
37
|
const createDatasourceTemplateWithResponse = (
|
|
37
38
|
className: string,
|
|
38
39
|
responseName: string,
|
|
39
|
-
|
|
40
|
+
responseImportPath: string
|
|
40
41
|
): string => `import { BaseHttpDatasource, type CreateRequestCallbackType } from '@azure-net/kit/infra';
|
|
41
|
-
import { ${responseName} } from '${
|
|
42
|
+
import { ${responseName} } from '${responseImportPath}';
|
|
42
43
|
|
|
43
44
|
export class ${className} extends BaseHttpDatasource {
|
|
44
45
|
\tasync createRequest<T>(callback: CreateRequestCallbackType<T>) {
|
|
@@ -56,7 +57,7 @@ const getContextChoices = async (): Promise<ContextChoice[]> => {
|
|
|
56
57
|
const config = await loadUserConfig();
|
|
57
58
|
const contexts = normalizeContexts(config.contexts);
|
|
58
59
|
|
|
59
|
-
const choices: ContextChoice[] = [{ title: '
|
|
60
|
+
const choices: ContextChoice[] = [{ title: 'shared foundation', value: '__shared__' }];
|
|
60
61
|
for (const context of contexts) {
|
|
61
62
|
choices.push({ title: context.name, value: context.name });
|
|
62
63
|
}
|
|
@@ -64,8 +65,9 @@ const getContextChoices = async (): Promise<ContextChoice[]> => {
|
|
|
64
65
|
return choices;
|
|
65
66
|
};
|
|
66
67
|
|
|
67
|
-
const
|
|
68
|
-
const
|
|
68
|
+
const getSharedResponses = async (): Promise<string[]> => {
|
|
69
|
+
const { sharedContext } = await getSharedState();
|
|
70
|
+
const responsesPath = getFoundationConstructPath(sharedContext.name, 'response');
|
|
69
71
|
try {
|
|
70
72
|
const files = await fs.readdir(responsesPath);
|
|
71
73
|
return files.filter((file) => file.endsWith('.ts') && file !== 'index.ts').map((file) => file.replace(/\.ts$/, ''));
|
|
@@ -75,7 +77,8 @@ const getCoreResponses = async (): Promise<string[]> => {
|
|
|
75
77
|
};
|
|
76
78
|
|
|
77
79
|
const hasResponseInterface = async (responseName: string): Promise<boolean> => {
|
|
78
|
-
const
|
|
80
|
+
const { sharedContext } = await getSharedState();
|
|
81
|
+
const responsePath = path.join(getFoundationConstructPath(sharedContext.name, 'response'), `${responseName}.ts`);
|
|
79
82
|
try {
|
|
80
83
|
const content = await fs.readFile(responsePath, 'utf-8');
|
|
81
84
|
const interfaceRegex = new RegExp(`export\\s+interface\\s+I${responseName}\\b`);
|
|
@@ -85,30 +88,9 @@ const hasResponseInterface = async (responseName: string): Promise<boolean> => {
|
|
|
85
88
|
}
|
|
86
89
|
};
|
|
87
90
|
|
|
88
|
-
const getConfiguredCoreAliasOrThrow = async (): Promise<string> => {
|
|
89
|
-
const configRef = resolveConfigFile();
|
|
90
|
-
if (!configRef.exists) {
|
|
91
|
-
throw new Error(
|
|
92
|
-
'azure-net.config is not configured. Run "azure-net init folders-structure" and do not forget to fill contexts if you need them.'
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const content = await fs.readFile(configRef.filepath, 'utf-8');
|
|
97
|
-
const aliasMatch = content.match(/coreAlias\s*:\s*['"`]([^'"`]+)['"`]/);
|
|
98
|
-
const alias = aliasMatch?.[1]?.trim();
|
|
99
|
-
|
|
100
|
-
if (!alias) {
|
|
101
|
-
throw new Error(
|
|
102
|
-
'azure-net.config is not configured. Run "azure-net init folders-structure" and do not forget to fill contexts if you need them.'
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return alias.startsWith('$') ? alias : `$${alias}`;
|
|
107
|
-
};
|
|
108
|
-
|
|
109
91
|
const resolveTargetPath = (target: string): string => {
|
|
110
|
-
if (target === '
|
|
111
|
-
|
|
92
|
+
if (target === '__shared__') {
|
|
93
|
+
throw new Error('Shared target path must be resolved async.');
|
|
112
94
|
}
|
|
113
95
|
|
|
114
96
|
return path.join(process.cwd(), 'src', 'app', target, 'layers', 'infrastructure', 'http', 'datasources');
|
|
@@ -133,16 +115,16 @@ export default async function createDatasource(): Promise<void> {
|
|
|
133
115
|
initial: 0
|
|
134
116
|
});
|
|
135
117
|
|
|
136
|
-
const selectedTarget = String(target ?? '
|
|
137
|
-
const
|
|
118
|
+
const selectedTarget = String(target ?? '__shared__');
|
|
119
|
+
const sharedResponses = await getSharedResponses();
|
|
138
120
|
|
|
139
121
|
let selectedResponse: string | null = null;
|
|
140
|
-
if (
|
|
122
|
+
if (sharedResponses.length > 0) {
|
|
141
123
|
const { responseName } = await prompts({
|
|
142
124
|
type: 'select',
|
|
143
125
|
name: 'responseName',
|
|
144
126
|
message: 'Select response for datasource:',
|
|
145
|
-
choices: [{ title: 'No response', value: null }, ...
|
|
127
|
+
choices: [{ title: 'No response', value: null }, ...sharedResponses.map((response) => ({ title: response, value: response }))],
|
|
146
128
|
initial: 0
|
|
147
129
|
});
|
|
148
130
|
selectedResponse = responseName ? String(responseName) : null;
|
|
@@ -152,14 +134,18 @@ export default async function createDatasource(): Promise<void> {
|
|
|
152
134
|
if (!selectedResponse) {
|
|
153
135
|
content = createDatasourceTemplateWithoutResponse(className);
|
|
154
136
|
} else {
|
|
155
|
-
const
|
|
137
|
+
const { sharedAlias } = await getSharedState();
|
|
138
|
+
const responseImportPath = getFoundationConstructImportPath(sharedAlias, 'response');
|
|
156
139
|
const withInterface = await hasResponseInterface(selectedResponse);
|
|
157
140
|
content = withInterface
|
|
158
|
-
? createDatasourceTemplateWithResponseAndInterface(className, selectedResponse,
|
|
159
|
-
: createDatasourceTemplateWithResponse(className, selectedResponse,
|
|
141
|
+
? createDatasourceTemplateWithResponseAndInterface(className, selectedResponse, responseImportPath)
|
|
142
|
+
: createDatasourceTemplateWithResponse(className, selectedResponse, responseImportPath);
|
|
160
143
|
}
|
|
161
144
|
|
|
162
|
-
const targetPath =
|
|
145
|
+
const targetPath =
|
|
146
|
+
selectedTarget === '__shared__'
|
|
147
|
+
? getFoundationConstructPath((await getSharedState()).sharedContext.name, 'datasource')
|
|
148
|
+
: resolveTargetPath(selectedTarget);
|
|
163
149
|
await fs.mkdir(targetPath, { recursive: true });
|
|
164
150
|
|
|
165
151
|
const filePath = path.join(targetPath, `${className}.ts`);
|
|
@@ -3,20 +3,18 @@ import path from 'node:path';
|
|
|
3
3
|
import prompts from 'prompts';
|
|
4
4
|
import { writeIfNotExists, updateIndexTs } from '../utils/fileUtils.js';
|
|
5
5
|
import { toPascalCase } from '../utils/contextUtils.js';
|
|
6
|
-
import { loadUserConfig
|
|
6
|
+
import { loadUserConfig } from '../utils/loadConfig.js';
|
|
7
7
|
import { normalizeContexts } from '../init/initAliases.js';
|
|
8
|
-
|
|
8
|
+
import { getFoundationConstructImportPath, getFoundationConstructPath, getSharedState } from '../utils/sharedFoundation.js';
|
|
9
9
|
const createProviderTemplateWithoutDatasource = (providerName, contextPrefix) => `import { createBoundaryProvider } from '@azure-net/kit';
|
|
10
10
|
|
|
11
11
|
export const ${providerName} = createBoundaryProvider('${contextPrefix}${providerName}', {
|
|
12
12
|
\tregister: () => ({})
|
|
13
13
|
});
|
|
14
14
|
`;
|
|
15
|
-
|
|
16
15
|
const createProviderTemplateWithDatasource = (providerName, contextPrefix, datasourceName, datasourceImportPath) => {
|
|
17
16
|
const factoryNameBase = datasourceName.endsWith('Datasource') ? datasourceName.slice(0, -'Datasource'.length) : datasourceName;
|
|
18
17
|
const datasourceFactoryName = `${factoryNameBase || datasourceName}Rest`;
|
|
19
|
-
|
|
20
18
|
return `import { ${datasourceName} } from '${datasourceImportPath}';
|
|
21
19
|
import { createHttpServiceInstance } from '@azure-net/kit/infra';
|
|
22
20
|
import { createBoundaryProvider } from '@azure-net/kit';
|
|
@@ -33,27 +31,6 @@ export const ${providerName} = createBoundaryProvider('${contextPrefix}${provide
|
|
|
33
31
|
});
|
|
34
32
|
`;
|
|
35
33
|
};
|
|
36
|
-
|
|
37
|
-
const getCoreAliasOrThrow = async () => {
|
|
38
|
-
const configRef = resolveConfigFile();
|
|
39
|
-
if (!configRef.exists) {
|
|
40
|
-
throw new Error(
|
|
41
|
-
'azure-net.config is not configured. Run "azure-net init folders-structure" and do not forget to fill contexts if you need them.'
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const content = await fs.readFile(configRef.filepath, 'utf-8');
|
|
46
|
-
const aliasMatch = content.match(/coreAlias\s*:\s*['"`]([^'"`]+)['"`]/);
|
|
47
|
-
const alias = aliasMatch?.[1]?.trim();
|
|
48
|
-
if (!alias) {
|
|
49
|
-
throw new Error(
|
|
50
|
-
'azure-net.config is not configured. Run "azure-net init folders-structure" and do not forget to fill contexts if you need them.'
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return alias.startsWith('$') ? alias : `$${alias}`;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
34
|
const getDatasourcesFromPath = async (targetPath) => {
|
|
58
35
|
try {
|
|
59
36
|
const files = await fs.readdir(targetPath);
|
|
@@ -62,31 +39,24 @@ const getDatasourcesFromPath = async (targetPath) => {
|
|
|
62
39
|
return [];
|
|
63
40
|
}
|
|
64
41
|
};
|
|
65
|
-
|
|
66
|
-
const resolveContextPrefix = (target) => (target === 'core' ? 'Core' : toPascalCase(target));
|
|
67
|
-
|
|
42
|
+
const resolveContextPrefix = (target) => (target === '__shared__' ? 'Shared' : toPascalCase(target));
|
|
68
43
|
const resolveProviderPath = (target) => {
|
|
69
|
-
if (target === '
|
|
70
|
-
|
|
44
|
+
if (target === '__shared__') {
|
|
45
|
+
throw new Error('Shared provider path must be resolved async.');
|
|
71
46
|
}
|
|
72
|
-
|
|
73
47
|
return path.join(process.cwd(), 'src', 'app', target, 'layers', 'infrastructure', 'providers');
|
|
74
48
|
};
|
|
75
|
-
|
|
76
49
|
const resolveContextAlias = (contexts, targetContext) => {
|
|
77
50
|
const found = contexts.find((context) => context.name === targetContext);
|
|
78
51
|
if (!found) {
|
|
79
52
|
return `$${targetContext}`;
|
|
80
53
|
}
|
|
81
|
-
|
|
82
54
|
return found.alias.startsWith('$') ? found.alias : `$${found.alias}`;
|
|
83
55
|
};
|
|
84
|
-
|
|
85
56
|
const ensureProviderName = (rawName) => {
|
|
86
57
|
const normalized = toPascalCase(rawName || 'DatasourceProvider') || 'DatasourceProvider';
|
|
87
58
|
return normalized.endsWith('Provider') ? normalized : `${normalized}Provider`;
|
|
88
59
|
};
|
|
89
|
-
|
|
90
60
|
export default async function createDatasourceProvider() {
|
|
91
61
|
const { providerNameRaw } = await prompts({
|
|
92
62
|
type: 'text',
|
|
@@ -94,12 +64,13 @@ export default async function createDatasourceProvider() {
|
|
|
94
64
|
message: 'Datasource provider name:',
|
|
95
65
|
initial: 'DatasourceProvider'
|
|
96
66
|
});
|
|
97
|
-
|
|
98
67
|
const providerName = ensureProviderName(String(providerNameRaw ?? 'DatasourceProvider'));
|
|
99
68
|
const config = await loadUserConfig();
|
|
100
69
|
const contexts = normalizeContexts(config.contexts);
|
|
101
|
-
const contextChoices = [
|
|
102
|
-
|
|
70
|
+
const contextChoices = [
|
|
71
|
+
{ title: 'shared foundation', value: '__shared__' },
|
|
72
|
+
...contexts.map((context) => ({ title: context.name, value: context.name }))
|
|
73
|
+
];
|
|
103
74
|
const { target } = await prompts({
|
|
104
75
|
type: 'select',
|
|
105
76
|
name: 'target',
|
|
@@ -107,24 +78,22 @@ export default async function createDatasourceProvider() {
|
|
|
107
78
|
choices: contextChoices,
|
|
108
79
|
initial: 0
|
|
109
80
|
});
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
const
|
|
81
|
+
const selectedTarget = String(target ?? '__shared__');
|
|
82
|
+
const { sharedAlias, sharedContext } = await getSharedState();
|
|
83
|
+
const sharedDatasources = await getDatasourcesFromPath(getFoundationConstructPath(sharedContext.name, 'datasource'));
|
|
113
84
|
const contextDatasources =
|
|
114
|
-
selectedTarget === '
|
|
85
|
+
selectedTarget === '__shared__'
|
|
115
86
|
? []
|
|
116
87
|
: await getDatasourcesFromPath(
|
|
117
88
|
path.join(process.cwd(), 'src', 'app', selectedTarget, 'layers', 'infrastructure', 'http', 'datasources')
|
|
118
89
|
);
|
|
119
|
-
|
|
120
90
|
const datasourceChoices = [{ title: 'No datasource', value: null }];
|
|
121
|
-
for (const datasource of
|
|
122
|
-
datasourceChoices.push({ title: `${datasource} (
|
|
91
|
+
for (const datasource of sharedDatasources) {
|
|
92
|
+
datasourceChoices.push({ title: `${datasource} (shared foundation)`, value: { name: datasource, source: 'shared' } });
|
|
123
93
|
}
|
|
124
94
|
for (const datasource of contextDatasources) {
|
|
125
95
|
datasourceChoices.push({ title: `${datasource} (${selectedTarget})`, value: { name: datasource, source: 'context' } });
|
|
126
96
|
}
|
|
127
|
-
|
|
128
97
|
const { datasourceSelection } = await prompts({
|
|
129
98
|
type: 'select',
|
|
130
99
|
name: 'datasourceSelection',
|
|
@@ -132,33 +101,27 @@ export default async function createDatasourceProvider() {
|
|
|
132
101
|
choices: datasourceChoices,
|
|
133
102
|
initial: 0
|
|
134
103
|
});
|
|
135
|
-
|
|
136
104
|
const selectedDatasource = datasourceSelection ?? null;
|
|
137
105
|
const contextPrefix = resolveContextPrefix(selectedTarget);
|
|
138
106
|
let content;
|
|
139
|
-
|
|
140
107
|
if (!selectedDatasource) {
|
|
141
108
|
content = createProviderTemplateWithoutDatasource(providerName, contextPrefix);
|
|
142
109
|
} else {
|
|
143
110
|
const importPath =
|
|
144
|
-
selectedDatasource.source === '
|
|
145
|
-
?
|
|
111
|
+
selectedDatasource.source === 'shared'
|
|
112
|
+
? getFoundationConstructImportPath(sharedAlias, 'datasource')
|
|
146
113
|
: `${resolveContextAlias(contexts, selectedTarget)}/layers/infrastructure/http/datasources`;
|
|
147
|
-
|
|
148
114
|
content = createProviderTemplateWithDatasource(providerName, contextPrefix, selectedDatasource.name, importPath);
|
|
149
115
|
}
|
|
150
|
-
|
|
151
|
-
|
|
116
|
+
const providerPath =
|
|
117
|
+
selectedTarget === '__shared__' ? getFoundationConstructPath(sharedContext.name, 'provider') : resolveProviderPath(selectedTarget);
|
|
152
118
|
await fs.mkdir(providerPath, { recursive: true });
|
|
153
|
-
|
|
154
119
|
const filePath = path.join(providerPath, `${providerName}.ts`);
|
|
155
120
|
const created = await writeIfNotExists(filePath, content);
|
|
156
121
|
await updateIndexTs(providerPath);
|
|
157
|
-
|
|
158
122
|
if (!created) {
|
|
159
123
|
console.log(`⚠️ Datasource provider "${providerName}" already exists. File was not overwritten.`);
|
|
160
124
|
return;
|
|
161
125
|
}
|
|
162
|
-
|
|
163
126
|
console.log(`✅ Datasource provider created: ${filePath}`);
|
|
164
127
|
}
|