@azure-net/cli 5.1.0 → 6.0.0-next.2
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/README.md +189 -0
- package/bin/azure-net.js +236 -221
- package/dist/bin/azure-net.d.ts +2 -0
- package/dist/src/checks/architecture.d.ts +20 -0
- package/dist/src/checks/checkDomain.d.ts +1 -0
- package/dist/src/checks/checkFoldersStructure.d.ts +1 -0
- package/dist/src/checks/checkHooks.d.ts +1 -0
- package/dist/src/checks/checkImports.d.ts +1 -0
- package/dist/src/checks/checkInternal.d.ts +1 -0
- package/dist/src/checks/checkLayerBoundaries.d.ts +1 -0
- package/dist/src/checks/checkLayerImports.d.ts +1 -0
- package/dist/src/checks/checkPresenterNames.d.ts +1 -0
- package/dist/src/checks/checkProject.d.ts +1 -0
- package/dist/src/checks/checkProviderGraph.d.ts +1 -0
- package/dist/src/checks/checkProviderNames.d.ts +1 -0
- package/dist/src/generate/layers/generateRepository.d.ts +1 -0
- package/dist/src/generate/layers/generateRepositoryMethod.d.ts +1 -0
- package/dist/src/generate/layers/generateUseCases.d.ts +1 -0
- package/dist/src/generate/module/generateDomain.d.ts +8 -0
- package/dist/src/generate/module/generateModule.d.ts +1 -0
- package/dist/src/generate/module/generateModulePreset.d.ts +1 -0
- package/dist/src/generate/module/generatePresenter.d.ts +29 -0
- package/dist/src/generate/module/generateRepository.d.ts +15 -0
- package/dist/src/generate/module/generateRepositoryMethod.d.ts +2 -0
- package/dist/src/generate/module/generateSchemaFromType.d.ts +9 -0
- package/dist/src/generate/module/generateStore.d.ts +1 -0
- package/dist/src/generate/module/generateTypesJson.d.ts +2 -0
- package/dist/src/generate/module/generateUseCases.d.ts +1 -0
- package/dist/src/generate/module/repositoryModuleShared.d.ts +89 -0
- package/dist/src/generate/routes/generateRoutes.d.ts +14 -0
- package/dist/src/generate/ui/generateComponent.d.ts +1 -0
- package/dist/src/generate/ui/generateDesignComponent.d.ts +1 -0
- package/dist/src/generate/ui/generateWidget.d.ts +1 -0
- package/dist/src/git/commit.d.ts +23 -0
- package/dist/src/git/push.d.ts +11 -0
- package/dist/src/git/runGit.d.ts +2 -0
- package/dist/src/init/initAliases.d.ts +12 -0
- package/dist/src/init/initEdges.d.ts +2 -0
- package/dist/src/init/initStructure.d.ts +1 -0
- package/dist/src/install/configureCommitTools.d.ts +1 -0
- package/dist/src/install/installFresh.d.ts +1 -0
- package/dist/src/migrate/migrate.d.ts +22 -0
- package/dist/src/migrate/presenters.d.ts +7 -0
- package/dist/src/plugins/addLint.d.ts +5 -0
- package/dist/src/scaffolds/createCoreSchema.d.ts +1 -0
- package/dist/src/scaffolds/createDatasource.d.ts +1 -0
- package/dist/src/scaffolds/createProgram.d.ts +1 -0
- package/dist/src/scaffolds/createResponse.d.ts +1 -0
- package/dist/src/scaffolds/createSchemaRule.d.ts +1 -0
- package/dist/src/scaffolds/createTranslationManager.d.ts +1 -0
- package/{src/scaffolds/index.ts → dist/src/scaffolds/index.d.ts} +0 -2
- package/dist/src/scaffolds/registerDatasource.d.ts +2 -0
- package/dist/src/scaffolds/updateDefaultFactoryConfig.d.ts +1 -0
- package/dist/src/utils/architecture.d.ts +31 -0
- package/dist/src/utils/contextUtils.d.ts +6 -0
- package/dist/src/utils/fileUtils.d.ts +5 -0
- package/dist/src/utils/flattenConfig.d.ts +2 -0
- package/dist/src/utils/legacyAliases.d.ts +1 -0
- package/dist/src/utils/loadConfig.d.ts +16 -0
- package/dist/src/utils/packageImports.d.ts +4 -0
- package/dist/src/utils/sharedFoundation.d.ts +20 -0
- package/dist/src/utils/viteConfig.d.ts +9 -0
- package/package.json +48 -36
- package/src/checks/architecture.js +154 -0
- package/src/checks/checkDomain.js +124 -154
- package/src/checks/checkFoldersStructure.js +64 -52
- package/src/checks/checkHooks.js +12 -12
- package/src/checks/checkImports.js +26 -142
- package/src/checks/checkInternal.js +27 -24
- package/src/checks/checkLayerBoundaries.js +22 -197
- package/src/checks/checkLayerImports.js +14 -134
- package/src/checks/checkPresenterNames.js +156 -143
- package/src/checks/checkProject.js +27 -26
- package/src/checks/checkProviderGraph.js +182 -166
- package/src/checks/checkProviderNames.js +123 -112
- package/src/generate/layers/generateRepository.js +1 -109
- package/src/generate/layers/generateRepositoryMethod.js +1 -90
- package/src/generate/layers/generateUseCases.js +1 -44
- package/src/generate/module/generateDomain.js +81 -105
- package/src/generate/module/generateModule.js +34 -68
- package/src/generate/module/generateModulePreset.js +188 -248
- package/src/generate/module/generatePresenter.js +441 -369
- package/src/generate/module/generateRepository.js +102 -121
- package/src/generate/module/generateRepositoryMethod.js +117 -0
- package/src/generate/module/generateSchemaFromType.js +283 -280
- package/src/generate/module/generateStore.js +41 -0
- package/src/generate/module/generateTypesJson.js +196 -195
- package/src/generate/module/generateUseCases.js +47 -55
- package/src/generate/module/repositoryModuleShared.js +480 -459
- package/src/generate/routes/generateRoutes.js +165 -174
- package/src/generate/ui/generateComponent.js +44 -64
- package/src/generate/ui/generateDesignComponent.js +21 -41
- package/src/generate/ui/generateWidget.js +21 -41
- package/src/git/commit.js +67 -0
- package/src/git/push.js +19 -0
- package/src/git/runGit.js +11 -0
- package/src/init/initAliases.js +19 -135
- package/src/init/initEdges.js +79 -54
- package/src/init/initStructure.js +31 -145
- package/src/install/configureCommitTools.js +1 -0
- package/src/install/installFresh.js +39 -68
- package/src/migrate/migrate.js +914 -0
- package/src/migrate/presenters.js +265 -0
- package/src/plugins/addLint.js +52 -219
- package/src/scaffolds/createCoreSchema.js +65 -91
- package/src/scaffolds/createDatasource.js +67 -101
- package/src/scaffolds/createProgram.js +8 -8
- package/src/scaffolds/createResponse.js +29 -29
- package/src/scaffolds/createSchemaRule.js +19 -19
- package/src/scaffolds/createTranslationManager.js +84 -37
- package/src/scaffolds/index.js +0 -2
- package/src/scaffolds/registerDatasource.js +59 -0
- package/src/scaffolds/updateDefaultFactoryConfig.js +31 -0
- package/src/utils/architecture.js +145 -0
- package/src/utils/contextUtils.js +32 -65
- package/src/utils/fileUtils.js +69 -50
- package/src/utils/flattenConfig.js +38 -0
- package/src/utils/legacyAliases.js +75 -0
- package/src/utils/loadConfig.js +76 -40
- package/src/utils/packageImports.js +63 -0
- package/src/utils/sharedFoundation.js +36 -42
- package/src/utils/viteConfig.js +295 -0
- package/.prettierrc +0 -7
- package/bin/azure-net.ts +0 -308
- package/eslint.config.js +0 -34
- package/src/checks/checkDomain.ts +0 -223
- package/src/checks/checkFoldersStructure.ts +0 -85
- package/src/checks/checkHooks.ts +0 -22
- package/src/checks/checkImports.ts +0 -193
- package/src/checks/checkInternal.ts +0 -48
- package/src/checks/checkLayerBoundaries.ts +0 -255
- package/src/checks/checkLayerImports.ts +0 -185
- package/src/checks/checkPresenterNames.ts +0 -203
- package/src/checks/checkProject.ts +0 -45
- package/src/checks/checkProviderGraph.ts +0 -234
- package/src/checks/checkProviderNames.ts +0 -165
- package/src/generate/layers/generateRepository.ts +0 -123
- package/src/generate/layers/generateRepositoryMethod.ts +0 -102
- package/src/generate/layers/generateUseCases.ts +0 -50
- package/src/generate/layers/repositoryShared.js +0 -506
- package/src/generate/layers/repositoryShared.ts +0 -662
- package/src/generate/module/generateDomain.ts +0 -147
- package/src/generate/module/generateModule.ts +0 -84
- package/src/generate/module/generateModulePreset.ts +0 -338
- package/src/generate/module/generatePresenter.ts +0 -498
- package/src/generate/module/generateRepository.ts +0 -158
- package/src/generate/module/generateSchemaFromType.ts +0 -368
- package/src/generate/module/generateTypesJson.ts +0 -259
- package/src/generate/module/generateUseCases.ts +0 -67
- package/src/generate/module/repositoryModuleShared.ts +0 -669
- package/src/generate/routes/generateRoutes.ts +0 -282
- package/src/generate/ui/generateComponent.ts +0 -100
- package/src/generate/ui/generateDesignComponent.ts +0 -71
- package/src/generate/ui/generateWidget.ts +0 -71
- package/src/init/initAliases.ts +0 -172
- package/src/init/initEdges.ts +0 -74
- package/src/init/initStructure.ts +0 -172
- package/src/install/installFresh.ts +0 -93
- package/src/plugins/addLint.ts +0 -274
- package/src/scaffolds/createCoreSchema.ts +0 -130
- package/src/scaffolds/createDatasource.ts +0 -161
- package/src/scaffolds/createDatasourceProvider.js +0 -127
- package/src/scaffolds/createDatasourceProvider.ts +0 -161
- package/src/scaffolds/createPresenterFactory.js +0 -83
- package/src/scaffolds/createPresenterFactory.ts +0 -102
- package/src/scaffolds/createProgram.ts +0 -19
- package/src/scaffolds/createResponse.ts +0 -66
- package/src/scaffolds/createSchemaRule.ts +0 -44
- package/src/scaffolds/createTranslationManager.ts +0 -80
- package/src/utils/contextUtils.ts +0 -88
- package/src/utils/fileUtils.ts +0 -74
- package/src/utils/loadConfig.ts +0 -68
- package/src/utils/sharedFoundation.ts +0 -70
- package/tsconfig.json +0 -19
- /package/{src/checks/index.ts → dist/src/checks/index.d.ts} +0 -0
- /package/{src/plugins/index.ts → dist/src/plugins/index.d.ts} +0 -0
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import fsSync from 'node:fs';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import prompts from 'prompts';
|
|
5
|
-
import { writeIfNotExists, updateIndexTs } from '../utils/fileUtils.js';
|
|
6
|
-
import { toPascalCase } from '../utils/contextUtils.js';
|
|
7
|
-
import { getFoundationConstructPath, getSharedState } from '../utils/sharedFoundation.js';
|
|
8
|
-
|
|
9
|
-
type MessagePreset = 'ru' | 'en' | 'i18n';
|
|
10
|
-
type ConfigPath = 'ts' | 'js';
|
|
11
|
-
|
|
12
|
-
const resolvePresetImportName = (preset: MessagePreset): string => {
|
|
13
|
-
switch (preset) {
|
|
14
|
-
case 'ru':
|
|
15
|
-
return 'validationMessagesRu';
|
|
16
|
-
case 'en':
|
|
17
|
-
return 'validationMessagesEn';
|
|
18
|
-
case 'i18n':
|
|
19
|
-
return 'validationMessagesI18n';
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
const createSchemaFactoryTemplate = (
|
|
24
|
-
factoryName: string,
|
|
25
|
-
messagesImportName: string
|
|
26
|
-
): string => `import { createSchemaFactory, createRules, ${messagesImportName} } from '@azure-net/kit/delivery';
|
|
27
|
-
|
|
28
|
-
export const ${factoryName} = createSchemaFactory(createRules(${messagesImportName}));
|
|
29
|
-
`;
|
|
30
|
-
|
|
31
|
-
const resolveConfigFile = (cwd: string): { filepath: string; type: ConfigPath; exists: boolean; content: string } => {
|
|
32
|
-
const tsPath = path.join(cwd, 'azure-net.config.ts');
|
|
33
|
-
const jsPath = path.join(cwd, 'azure-net.config.js');
|
|
34
|
-
|
|
35
|
-
if (fsSync.existsSync(tsPath)) {
|
|
36
|
-
return { filepath: tsPath, type: 'ts', exists: true, content: fsSync.readFileSync(tsPath, 'utf-8') };
|
|
37
|
-
}
|
|
38
|
-
if (fsSync.existsSync(jsPath)) {
|
|
39
|
-
return { filepath: jsPath, type: 'js', exists: true, content: fsSync.readFileSync(jsPath, 'utf-8') };
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return { filepath: tsPath, type: 'ts', exists: false, content: '' };
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const buildDefaultSchemaFactoryConfigEntry = (factoryName: string): string => {
|
|
46
|
-
return `defaultSchemaFactory: '${factoryName}'`;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const upsertDefaultSchemaFactoryConfig = (content: string, factoryName: string): string => {
|
|
50
|
-
const hasExportDefaultObject = /export\s+default\s*\{[\s\S]*\}\s*;?/.test(content);
|
|
51
|
-
const defaultFactoryEntry = buildDefaultSchemaFactoryConfigEntry(factoryName);
|
|
52
|
-
|
|
53
|
-
if (!hasExportDefaultObject) {
|
|
54
|
-
return `export default {\n\t${defaultFactoryEntry}\n};\n`;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
let nextContent = content;
|
|
58
|
-
|
|
59
|
-
if (/defaultSchemaFactory\s*:/.test(nextContent)) {
|
|
60
|
-
nextContent = nextContent.replace(/defaultSchemaFactory\s*:\s*(\{[\s\S]*?\n\s*\}|['"`][^'"`]+['"`])/m, defaultFactoryEntry);
|
|
61
|
-
} else if (/defaultSchema\s*:/.test(nextContent)) {
|
|
62
|
-
nextContent = nextContent.replace(/defaultSchema\s*:\s*(\{[\s\S]*?\n\s*\}|['"`][^'"`]+['"`])/m, defaultFactoryEntry);
|
|
63
|
-
} else {
|
|
64
|
-
nextContent = nextContent.replace(/export\s+default\s*\{([\s\S]*)\}\s*;?/, (_full, body: string) => {
|
|
65
|
-
const trimmedRight = body.replace(/\s*$/, '');
|
|
66
|
-
if (!trimmedRight.length) {
|
|
67
|
-
return `export default {\n\t${defaultFactoryEntry}\n};`;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const withComma = trimmedRight.endsWith(',') ? trimmedRight : `${trimmedRight},`;
|
|
71
|
-
return `export default {${withComma}\n\t${defaultFactoryEntry}\n};`;
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
return nextContent;
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
export default async function createCoreSchema(): Promise<void> {
|
|
78
|
-
const { schemaFactoryNameRaw } = await prompts({
|
|
79
|
-
type: 'text',
|
|
80
|
-
name: 'schemaFactoryNameRaw',
|
|
81
|
-
message: 'Schema factory name:',
|
|
82
|
-
initial: 'Schema'
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
const schemaFactoryName = toPascalCase(String(schemaFactoryNameRaw ?? 'Schema')) || 'Schema';
|
|
86
|
-
|
|
87
|
-
const { preset } = await prompts({
|
|
88
|
-
type: 'select',
|
|
89
|
-
name: 'preset',
|
|
90
|
-
message: 'Choose validation messages:',
|
|
91
|
-
choices: [
|
|
92
|
-
{ title: 'Russian', value: 'ru' },
|
|
93
|
-
{ title: 'English', value: 'en' },
|
|
94
|
-
{ title: 'i18n', value: 'i18n' }
|
|
95
|
-
],
|
|
96
|
-
initial: 2
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
const selectedPreset = (preset ?? 'i18n') as MessagePreset;
|
|
100
|
-
const messagesImportName = resolvePresetImportName(selectedPreset);
|
|
101
|
-
const { sharedContext } = await getSharedState();
|
|
102
|
-
const coreSchemaPath = getFoundationConstructPath(sharedContext.name, 'schema');
|
|
103
|
-
const customRulesPath = path.join(coreSchemaPath, 'custom-rules');
|
|
104
|
-
const filePath = path.join(coreSchemaPath, `${schemaFactoryName}.ts`);
|
|
105
|
-
|
|
106
|
-
await fs.mkdir(coreSchemaPath, { recursive: true });
|
|
107
|
-
await fs.mkdir(customRulesPath, { recursive: true });
|
|
108
|
-
|
|
109
|
-
const created = await writeIfNotExists(filePath, createSchemaFactoryTemplate(schemaFactoryName, messagesImportName));
|
|
110
|
-
if (!created) {
|
|
111
|
-
console.log(`⚠️ Schema factory "${schemaFactoryName}" already exists. File was not overwritten.`);
|
|
112
|
-
} else {
|
|
113
|
-
await updateIndexTs(coreSchemaPath);
|
|
114
|
-
console.log(`✅ Shared schema factory created: ${filePath}`);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const { useAsDefault } = await prompts({
|
|
118
|
-
type: 'confirm',
|
|
119
|
-
name: 'useAsDefault',
|
|
120
|
-
message: 'Use this schema factory as default for the project?',
|
|
121
|
-
initial: true
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
if (!useAsDefault) return;
|
|
125
|
-
|
|
126
|
-
const config = resolveConfigFile(process.cwd());
|
|
127
|
-
const nextContent = upsertDefaultSchemaFactoryConfig(config.content, schemaFactoryName);
|
|
128
|
-
await fs.writeFile(config.filepath, nextContent, 'utf-8');
|
|
129
|
-
console.log(`✅ Default schema factory saved to ${path.basename(config.filepath)}`);
|
|
130
|
-
}
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import prompts from 'prompts';
|
|
4
|
-
import { writeIfNotExists, updateIndexTs } from '../utils/fileUtils.js';
|
|
5
|
-
import { toPascalCase } from '../utils/contextUtils.js';
|
|
6
|
-
import { loadUserConfig } from '../utils/loadConfig.js';
|
|
7
|
-
import { normalizeContexts } from '../init/initAliases.js';
|
|
8
|
-
import { getFoundationConstructImportPath, getFoundationConstructPath, getSharedState } from '../utils/sharedFoundation.js';
|
|
9
|
-
|
|
10
|
-
type ContextChoice = { title: string; value: string };
|
|
11
|
-
|
|
12
|
-
const createDatasourceTemplateWithoutResponse = (
|
|
13
|
-
className: string
|
|
14
|
-
): string => `import { BaseHttpDatasource, type CreateRequestCallbackType } from '@azure-net/kit/infra';
|
|
15
|
-
|
|
16
|
-
export class ${className} extends BaseHttpDatasource {
|
|
17
|
-
\tasync createRequest<T>(callback: CreateRequestCallbackType<T>) {
|
|
18
|
-
\t\treturn await this.createRawRequest<T>(callback);
|
|
19
|
-
\t}
|
|
20
|
-
}
|
|
21
|
-
`;
|
|
22
|
-
|
|
23
|
-
const createDatasourceTemplateWithResponseAndInterface = (
|
|
24
|
-
className: string,
|
|
25
|
-
responseName: string,
|
|
26
|
-
responseImportPath: string
|
|
27
|
-
): string => `import { BaseHttpDatasource, type CreateRequestCallbackType } from '@azure-net/kit/infra';
|
|
28
|
-
import { ${responseName}, type I${responseName} } from '${responseImportPath}';
|
|
29
|
-
|
|
30
|
-
export class ${className} extends BaseHttpDatasource {
|
|
31
|
-
\tasync createRequest<T>(callback: CreateRequestCallbackType<I${responseName}<T>>) {
|
|
32
|
-
\t\treturn new ${responseName}<T>(await this.createRawRequest<I${responseName}<T>>(callback));
|
|
33
|
-
\t}
|
|
34
|
-
}
|
|
35
|
-
`;
|
|
36
|
-
|
|
37
|
-
const createDatasourceTemplateWithResponse = (
|
|
38
|
-
className: string,
|
|
39
|
-
responseName: string,
|
|
40
|
-
responseImportPath: string
|
|
41
|
-
): string => `import { BaseHttpDatasource, type CreateRequestCallbackType } from '@azure-net/kit/infra';
|
|
42
|
-
import { ${responseName} } from '${responseImportPath}';
|
|
43
|
-
|
|
44
|
-
export class ${className} extends BaseHttpDatasource {
|
|
45
|
-
\tasync createRequest<T>(callback: CreateRequestCallbackType<T>) {
|
|
46
|
-
\t\treturn new ${responseName}<T>(await this.createRawRequest<T>(callback));
|
|
47
|
-
\t}
|
|
48
|
-
}
|
|
49
|
-
`;
|
|
50
|
-
|
|
51
|
-
const ensureDatasourceClassName = (rawName: string): string => {
|
|
52
|
-
const normalized = toPascalCase(rawName || 'MockApi');
|
|
53
|
-
return normalized.endsWith('Datasource') ? normalized : `${normalized}Datasource`;
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const getContextChoices = async (): Promise<ContextChoice[]> => {
|
|
57
|
-
const config = await loadUserConfig();
|
|
58
|
-
const contexts = normalizeContexts(config.contexts);
|
|
59
|
-
|
|
60
|
-
const choices: ContextChoice[] = [{ title: 'shared foundation', value: '__shared__' }];
|
|
61
|
-
for (const context of contexts) {
|
|
62
|
-
choices.push({ title: context.name, value: context.name });
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return choices;
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
const getSharedResponses = async (): Promise<string[]> => {
|
|
69
|
-
const { sharedContext } = await getSharedState();
|
|
70
|
-
const responsesPath = getFoundationConstructPath(sharedContext.name, 'response');
|
|
71
|
-
try {
|
|
72
|
-
const files = await fs.readdir(responsesPath);
|
|
73
|
-
return files.filter((file) => file.endsWith('.ts') && file !== 'index.ts').map((file) => file.replace(/\.ts$/, ''));
|
|
74
|
-
} catch {
|
|
75
|
-
return [];
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
const hasResponseInterface = async (responseName: string): Promise<boolean> => {
|
|
80
|
-
const { sharedContext } = await getSharedState();
|
|
81
|
-
const responsePath = path.join(getFoundationConstructPath(sharedContext.name, 'response'), `${responseName}.ts`);
|
|
82
|
-
try {
|
|
83
|
-
const content = await fs.readFile(responsePath, 'utf-8');
|
|
84
|
-
const interfaceRegex = new RegExp(`export\\s+interface\\s+I${responseName}\\b`);
|
|
85
|
-
return interfaceRegex.test(content);
|
|
86
|
-
} catch {
|
|
87
|
-
return false;
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
const resolveTargetPath = (target: string): string => {
|
|
92
|
-
if (target === '__shared__') {
|
|
93
|
-
throw new Error('Shared target path must be resolved async.');
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return path.join(process.cwd(), 'src', 'app', target, 'layers', 'infrastructure', 'http', 'datasources');
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
export default async function createDatasource(): Promise<void> {
|
|
100
|
-
const { datasourceNameRaw } = await prompts({
|
|
101
|
-
type: 'text',
|
|
102
|
-
name: 'datasourceNameRaw',
|
|
103
|
-
message: 'Datasource name:',
|
|
104
|
-
initial: 'MockApi'
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
const className = ensureDatasourceClassName(String(datasourceNameRaw ?? 'MockApi'));
|
|
108
|
-
|
|
109
|
-
const contextChoices = await getContextChoices();
|
|
110
|
-
const { target } = await prompts({
|
|
111
|
-
type: 'select',
|
|
112
|
-
name: 'target',
|
|
113
|
-
message: 'Where to create datasource?',
|
|
114
|
-
choices: contextChoices,
|
|
115
|
-
initial: 0
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
const selectedTarget = String(target ?? '__shared__');
|
|
119
|
-
const sharedResponses = await getSharedResponses();
|
|
120
|
-
|
|
121
|
-
let selectedResponse: string | null = null;
|
|
122
|
-
if (sharedResponses.length > 0) {
|
|
123
|
-
const { responseName } = await prompts({
|
|
124
|
-
type: 'select',
|
|
125
|
-
name: 'responseName',
|
|
126
|
-
message: 'Select response for datasource:',
|
|
127
|
-
choices: [{ title: 'No response', value: null }, ...sharedResponses.map((response) => ({ title: response, value: response }))],
|
|
128
|
-
initial: 0
|
|
129
|
-
});
|
|
130
|
-
selectedResponse = responseName ? String(responseName) : null;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
let content: string;
|
|
134
|
-
if (!selectedResponse) {
|
|
135
|
-
content = createDatasourceTemplateWithoutResponse(className);
|
|
136
|
-
} else {
|
|
137
|
-
const { sharedAlias } = await getSharedState();
|
|
138
|
-
const responseImportPath = getFoundationConstructImportPath(sharedAlias, 'response');
|
|
139
|
-
const withInterface = await hasResponseInterface(selectedResponse);
|
|
140
|
-
content = withInterface
|
|
141
|
-
? createDatasourceTemplateWithResponseAndInterface(className, selectedResponse, responseImportPath)
|
|
142
|
-
: createDatasourceTemplateWithResponse(className, selectedResponse, responseImportPath);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const targetPath =
|
|
146
|
-
selectedTarget === '__shared__'
|
|
147
|
-
? getFoundationConstructPath((await getSharedState()).sharedContext.name, 'datasource')
|
|
148
|
-
: resolveTargetPath(selectedTarget);
|
|
149
|
-
await fs.mkdir(targetPath, { recursive: true });
|
|
150
|
-
|
|
151
|
-
const filePath = path.join(targetPath, `${className}.ts`);
|
|
152
|
-
const created = await writeIfNotExists(filePath, content);
|
|
153
|
-
await updateIndexTs(targetPath);
|
|
154
|
-
|
|
155
|
-
if (!created) {
|
|
156
|
-
console.log(`⚠️ Datasource "${className}" already exists. File was not overwritten.`);
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
console.log(`✅ Datasource created: ${filePath}`);
|
|
161
|
-
}
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import prompts from 'prompts';
|
|
4
|
-
import { writeIfNotExists, updateIndexTs } from '../utils/fileUtils.js';
|
|
5
|
-
import { toPascalCase } from '../utils/contextUtils.js';
|
|
6
|
-
import { loadUserConfig } from '../utils/loadConfig.js';
|
|
7
|
-
import { normalizeContexts } from '../init/initAliases.js';
|
|
8
|
-
import { getFoundationConstructImportPath, getFoundationConstructPath, getSharedState } from '../utils/sharedFoundation.js';
|
|
9
|
-
const createProviderTemplateWithoutDatasource = (providerName, contextPrefix) => `import { createBoundaryProvider } from '@azure-net/kit';
|
|
10
|
-
|
|
11
|
-
export const ${providerName} = createBoundaryProvider('${contextPrefix}${providerName}', {
|
|
12
|
-
\tregister: () => ({})
|
|
13
|
-
});
|
|
14
|
-
`;
|
|
15
|
-
const createProviderTemplateWithDatasource = (providerName, contextPrefix, datasourceName, datasourceImportPath) => {
|
|
16
|
-
const factoryNameBase = datasourceName.endsWith('Datasource') ? datasourceName.slice(0, -'Datasource'.length) : datasourceName;
|
|
17
|
-
const datasourceFactoryName = `${factoryNameBase || datasourceName}Rest`;
|
|
18
|
-
return `import { ${datasourceName} } from '${datasourceImportPath}';
|
|
19
|
-
import { createHttpServiceInstance } from '@azure-net/kit/infra';
|
|
20
|
-
import { createBoundaryProvider } from '@azure-net/kit';
|
|
21
|
-
|
|
22
|
-
export const ${providerName} = createBoundaryProvider('${contextPrefix}${providerName}', {
|
|
23
|
-
\tregister: () => ({
|
|
24
|
-
\t\t${datasourceFactoryName}: () =>
|
|
25
|
-
\t\t\tnew ${datasourceName}({
|
|
26
|
-
\t\t\t\thttp: createHttpServiceInstance({
|
|
27
|
-
\t\t\t\t\tprefixUrl: 'https://localhost'
|
|
28
|
-
\t\t\t\t})
|
|
29
|
-
\t\t\t})
|
|
30
|
-
\t})
|
|
31
|
-
});
|
|
32
|
-
`;
|
|
33
|
-
};
|
|
34
|
-
const getDatasourcesFromPath = async (targetPath) => {
|
|
35
|
-
try {
|
|
36
|
-
const files = await fs.readdir(targetPath);
|
|
37
|
-
return files.filter((file) => file.endsWith('.ts') && file !== 'index.ts').map((file) => file.replace(/\.ts$/, ''));
|
|
38
|
-
} catch {
|
|
39
|
-
return [];
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
const resolveContextPrefix = (target) => (target === '__shared__' ? 'Shared' : toPascalCase(target));
|
|
43
|
-
const resolveProviderPath = (target) => {
|
|
44
|
-
if (target === '__shared__') {
|
|
45
|
-
throw new Error('Shared provider path must be resolved async.');
|
|
46
|
-
}
|
|
47
|
-
return path.join(process.cwd(), 'src', 'app', target, 'layers', 'infrastructure', 'providers');
|
|
48
|
-
};
|
|
49
|
-
const resolveContextAlias = (contexts, targetContext) => {
|
|
50
|
-
const found = contexts.find((context) => context.name === targetContext);
|
|
51
|
-
if (!found) {
|
|
52
|
-
return `$${targetContext}`;
|
|
53
|
-
}
|
|
54
|
-
return found.alias.startsWith('$') ? found.alias : `$${found.alias}`;
|
|
55
|
-
};
|
|
56
|
-
const ensureProviderName = (rawName) => {
|
|
57
|
-
const normalized = toPascalCase(rawName || 'DatasourceProvider') || 'DatasourceProvider';
|
|
58
|
-
return normalized.endsWith('Provider') ? normalized : `${normalized}Provider`;
|
|
59
|
-
};
|
|
60
|
-
export default async function createDatasourceProvider() {
|
|
61
|
-
const { providerNameRaw } = await prompts({
|
|
62
|
-
type: 'text',
|
|
63
|
-
name: 'providerNameRaw',
|
|
64
|
-
message: 'Datasource provider name:',
|
|
65
|
-
initial: 'DatasourceProvider'
|
|
66
|
-
});
|
|
67
|
-
const providerName = ensureProviderName(String(providerNameRaw ?? 'DatasourceProvider'));
|
|
68
|
-
const config = await loadUserConfig();
|
|
69
|
-
const contexts = normalizeContexts(config.contexts);
|
|
70
|
-
const contextChoices = [
|
|
71
|
-
{ title: 'shared foundation', value: '__shared__' },
|
|
72
|
-
...contexts.map((context) => ({ title: context.name, value: context.name }))
|
|
73
|
-
];
|
|
74
|
-
const { target } = await prompts({
|
|
75
|
-
type: 'select',
|
|
76
|
-
name: 'target',
|
|
77
|
-
message: 'Where to create datasource provider?',
|
|
78
|
-
choices: contextChoices,
|
|
79
|
-
initial: 0
|
|
80
|
-
});
|
|
81
|
-
const selectedTarget = String(target ?? '__shared__');
|
|
82
|
-
const { sharedAlias, sharedContext } = await getSharedState();
|
|
83
|
-
const sharedDatasources = await getDatasourcesFromPath(getFoundationConstructPath(sharedContext.name, 'datasource'));
|
|
84
|
-
const contextDatasources =
|
|
85
|
-
selectedTarget === '__shared__'
|
|
86
|
-
? []
|
|
87
|
-
: await getDatasourcesFromPath(
|
|
88
|
-
path.join(process.cwd(), 'src', 'app', selectedTarget, 'layers', 'infrastructure', 'http', 'datasources')
|
|
89
|
-
);
|
|
90
|
-
const datasourceChoices = [{ title: 'No datasource', value: null }];
|
|
91
|
-
for (const datasource of sharedDatasources) {
|
|
92
|
-
datasourceChoices.push({ title: `${datasource} (shared foundation)`, value: { name: datasource, source: 'shared' } });
|
|
93
|
-
}
|
|
94
|
-
for (const datasource of contextDatasources) {
|
|
95
|
-
datasourceChoices.push({ title: `${datasource} (${selectedTarget})`, value: { name: datasource, source: 'context' } });
|
|
96
|
-
}
|
|
97
|
-
const { datasourceSelection } = await prompts({
|
|
98
|
-
type: 'select',
|
|
99
|
-
name: 'datasourceSelection',
|
|
100
|
-
message: 'Select datasource:',
|
|
101
|
-
choices: datasourceChoices,
|
|
102
|
-
initial: 0
|
|
103
|
-
});
|
|
104
|
-
const selectedDatasource = datasourceSelection ?? null;
|
|
105
|
-
const contextPrefix = resolveContextPrefix(selectedTarget);
|
|
106
|
-
let content;
|
|
107
|
-
if (!selectedDatasource) {
|
|
108
|
-
content = createProviderTemplateWithoutDatasource(providerName, contextPrefix);
|
|
109
|
-
} else {
|
|
110
|
-
const importPath =
|
|
111
|
-
selectedDatasource.source === 'shared'
|
|
112
|
-
? getFoundationConstructImportPath(sharedAlias, 'datasource')
|
|
113
|
-
: `${resolveContextAlias(contexts, selectedTarget)}/layers/infrastructure/http/datasources`;
|
|
114
|
-
content = createProviderTemplateWithDatasource(providerName, contextPrefix, selectedDatasource.name, importPath);
|
|
115
|
-
}
|
|
116
|
-
const providerPath =
|
|
117
|
-
selectedTarget === '__shared__' ? getFoundationConstructPath(sharedContext.name, 'provider') : resolveProviderPath(selectedTarget);
|
|
118
|
-
await fs.mkdir(providerPath, { recursive: true });
|
|
119
|
-
const filePath = path.join(providerPath, `${providerName}.ts`);
|
|
120
|
-
const created = await writeIfNotExists(filePath, content);
|
|
121
|
-
await updateIndexTs(providerPath);
|
|
122
|
-
if (!created) {
|
|
123
|
-
console.log(`⚠️ Datasource provider "${providerName}" already exists. File was not overwritten.`);
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
console.log(`✅ Datasource provider created: ${filePath}`);
|
|
127
|
-
}
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import prompts from 'prompts';
|
|
4
|
-
import { writeIfNotExists, updateIndexTs } from '../utils/fileUtils.js';
|
|
5
|
-
import { toPascalCase } from '../utils/contextUtils.js';
|
|
6
|
-
import { loadUserConfig } from '../utils/loadConfig.js';
|
|
7
|
-
import { normalizeContexts } from '../init/initAliases.js';
|
|
8
|
-
import { getFoundationConstructImportPath, getFoundationConstructPath, getSharedState } from '../utils/sharedFoundation.js';
|
|
9
|
-
|
|
10
|
-
type NormalizedContext = { name: string; alias: string };
|
|
11
|
-
type DatasourceChoiceValue = null | { name: string; source: 'shared' | 'context' };
|
|
12
|
-
|
|
13
|
-
const createProviderTemplateWithoutDatasource = (
|
|
14
|
-
providerName: string,
|
|
15
|
-
contextPrefix: string
|
|
16
|
-
): string => `import { createBoundaryProvider } from '@azure-net/kit';
|
|
17
|
-
|
|
18
|
-
export const ${providerName} = createBoundaryProvider('${contextPrefix}${providerName}', {
|
|
19
|
-
\tregister: () => ({})
|
|
20
|
-
});
|
|
21
|
-
`;
|
|
22
|
-
|
|
23
|
-
const createProviderTemplateWithDatasource = (
|
|
24
|
-
providerName: string,
|
|
25
|
-
contextPrefix: string,
|
|
26
|
-
datasourceName: string,
|
|
27
|
-
datasourceImportPath: string
|
|
28
|
-
): string => {
|
|
29
|
-
const factoryNameBase = datasourceName.endsWith('Datasource') ? datasourceName.slice(0, -'Datasource'.length) : datasourceName;
|
|
30
|
-
const datasourceFactoryName = `${factoryNameBase || datasourceName}Rest`;
|
|
31
|
-
|
|
32
|
-
return `import { ${datasourceName} } from '${datasourceImportPath}';
|
|
33
|
-
import { createHttpServiceInstance } from '@azure-net/kit/infra';
|
|
34
|
-
import { createBoundaryProvider } from '@azure-net/kit';
|
|
35
|
-
|
|
36
|
-
export const ${providerName} = createBoundaryProvider('${contextPrefix}${providerName}', {
|
|
37
|
-
\tregister: () => ({
|
|
38
|
-
\t\t${datasourceFactoryName}: () =>
|
|
39
|
-
\t\t\tnew ${datasourceName}({
|
|
40
|
-
\t\t\t\thttp: createHttpServiceInstance({
|
|
41
|
-
\t\t\t\t\tprefixUrl: 'https://localhost'
|
|
42
|
-
\t\t\t\t})
|
|
43
|
-
\t\t\t})
|
|
44
|
-
\t})
|
|
45
|
-
});
|
|
46
|
-
`;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const getDatasourcesFromPath = async (targetPath: string): Promise<string[]> => {
|
|
50
|
-
try {
|
|
51
|
-
const files = await fs.readdir(targetPath);
|
|
52
|
-
return files.filter((file) => file.endsWith('.ts') && file !== 'index.ts').map((file) => file.replace(/\.ts$/, ''));
|
|
53
|
-
} catch {
|
|
54
|
-
return [];
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const resolveContextPrefix = (target: string): string => (target === '__shared__' ? 'Shared' : toPascalCase(target));
|
|
59
|
-
|
|
60
|
-
const resolveProviderPath = (target: string): string => {
|
|
61
|
-
if (target === '__shared__') {
|
|
62
|
-
throw new Error('Shared provider path must be resolved async.');
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return path.join(process.cwd(), 'src', 'app', target, 'layers', 'infrastructure', 'providers');
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
const resolveContextAlias = (contexts: NormalizedContext[], targetContext: string): string => {
|
|
69
|
-
const found = contexts.find((context) => context.name === targetContext);
|
|
70
|
-
if (!found) {
|
|
71
|
-
return `$${targetContext}`;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return found.alias.startsWith('$') ? found.alias : `$${found.alias}`;
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
const ensureProviderName = (rawName: string): string => {
|
|
78
|
-
const normalized = toPascalCase(rawName || 'DatasourceProvider') || 'DatasourceProvider';
|
|
79
|
-
return normalized.endsWith('Provider') ? normalized : `${normalized}Provider`;
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
export default async function createDatasourceProvider(): Promise<void> {
|
|
83
|
-
const { providerNameRaw } = await prompts({
|
|
84
|
-
type: 'text',
|
|
85
|
-
name: 'providerNameRaw',
|
|
86
|
-
message: 'Datasource provider name:',
|
|
87
|
-
initial: 'DatasourceProvider'
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
const providerName = ensureProviderName(String(providerNameRaw ?? 'DatasourceProvider'));
|
|
91
|
-
const config = await loadUserConfig();
|
|
92
|
-
const contexts = normalizeContexts(config.contexts) as NormalizedContext[];
|
|
93
|
-
const contextChoices = [
|
|
94
|
-
{ title: 'shared foundation', value: '__shared__' },
|
|
95
|
-
...contexts.map((context) => ({ title: context.name, value: context.name }))
|
|
96
|
-
];
|
|
97
|
-
|
|
98
|
-
const { target } = await prompts({
|
|
99
|
-
type: 'select',
|
|
100
|
-
name: 'target',
|
|
101
|
-
message: 'Where to create datasource provider?',
|
|
102
|
-
choices: contextChoices,
|
|
103
|
-
initial: 0
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
const selectedTarget = String(target ?? '__shared__');
|
|
107
|
-
const { sharedAlias, sharedContext } = await getSharedState();
|
|
108
|
-
const sharedDatasources = await getDatasourcesFromPath(getFoundationConstructPath(sharedContext.name, 'datasource'));
|
|
109
|
-
const contextDatasources =
|
|
110
|
-
selectedTarget === '__shared__'
|
|
111
|
-
? []
|
|
112
|
-
: await getDatasourcesFromPath(
|
|
113
|
-
path.join(process.cwd(), 'src', 'app', selectedTarget, 'layers', 'infrastructure', 'http', 'datasources')
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
const datasourceChoices: Array<{ title: string; value: DatasourceChoiceValue }> = [{ title: 'No datasource', value: null }];
|
|
117
|
-
for (const datasource of sharedDatasources) {
|
|
118
|
-
datasourceChoices.push({ title: `${datasource} (shared foundation)`, value: { name: datasource, source: 'shared' } });
|
|
119
|
-
}
|
|
120
|
-
for (const datasource of contextDatasources) {
|
|
121
|
-
datasourceChoices.push({ title: `${datasource} (${selectedTarget})`, value: { name: datasource, source: 'context' } });
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const { datasourceSelection } = await prompts({
|
|
125
|
-
type: 'select',
|
|
126
|
-
name: 'datasourceSelection',
|
|
127
|
-
message: 'Select datasource:',
|
|
128
|
-
choices: datasourceChoices,
|
|
129
|
-
initial: 0
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
const selectedDatasource = (datasourceSelection ?? null) as DatasourceChoiceValue;
|
|
133
|
-
const contextPrefix = resolveContextPrefix(selectedTarget);
|
|
134
|
-
let content: string;
|
|
135
|
-
|
|
136
|
-
if (!selectedDatasource) {
|
|
137
|
-
content = createProviderTemplateWithoutDatasource(providerName, contextPrefix);
|
|
138
|
-
} else {
|
|
139
|
-
const importPath =
|
|
140
|
-
selectedDatasource.source === 'shared'
|
|
141
|
-
? getFoundationConstructImportPath(sharedAlias, 'datasource')
|
|
142
|
-
: `${resolveContextAlias(contexts, selectedTarget)}/layers/infrastructure/http/datasources`;
|
|
143
|
-
|
|
144
|
-
content = createProviderTemplateWithDatasource(providerName, contextPrefix, selectedDatasource.name, importPath);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const providerPath =
|
|
148
|
-
selectedTarget === '__shared__' ? getFoundationConstructPath(sharedContext.name, 'provider') : resolveProviderPath(selectedTarget);
|
|
149
|
-
await fs.mkdir(providerPath, { recursive: true });
|
|
150
|
-
|
|
151
|
-
const filePath = path.join(providerPath, `${providerName}.ts`);
|
|
152
|
-
const created = await writeIfNotExists(filePath, content);
|
|
153
|
-
await updateIndexTs(providerPath);
|
|
154
|
-
|
|
155
|
-
if (!created) {
|
|
156
|
-
console.log(`⚠️ Datasource provider "${providerName}" already exists. File was not overwritten.`);
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
console.log(`✅ Datasource provider created: ${filePath}`);
|
|
161
|
-
}
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import fsSync from 'node:fs';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import prompts from 'prompts';
|
|
5
|
-
import { writeIfNotExists, updateIndexTs } from '../utils/fileUtils.js';
|
|
6
|
-
import { toPascalCase } from '../utils/contextUtils.js';
|
|
7
|
-
import { getFoundationConstructPath, getSharedState } from '../utils/sharedFoundation.js';
|
|
8
|
-
const createPresenterFactoryTemplate = (
|
|
9
|
-
factoryName
|
|
10
|
-
) => `import { createAsyncHelpers, createPresenterFactory } from '@azure-net/kit/delivery';
|
|
11
|
-
|
|
12
|
-
export const AsyncHelpers = createAsyncHelpers();
|
|
13
|
-
|
|
14
|
-
export const ${factoryName} = createPresenterFactory({ ...AsyncHelpers });
|
|
15
|
-
`;
|
|
16
|
-
const resolveConfigFile = (cwd) => {
|
|
17
|
-
const tsPath = path.join(cwd, 'azure-net.config.ts');
|
|
18
|
-
const jsPath = path.join(cwd, 'azure-net.config.js');
|
|
19
|
-
if (fsSync.existsSync(tsPath)) {
|
|
20
|
-
return { filepath: tsPath, type: 'ts', exists: true, content: fsSync.readFileSync(tsPath, 'utf-8') };
|
|
21
|
-
}
|
|
22
|
-
if (fsSync.existsSync(jsPath)) {
|
|
23
|
-
return { filepath: jsPath, type: 'js', exists: true, content: fsSync.readFileSync(jsPath, 'utf-8') };
|
|
24
|
-
}
|
|
25
|
-
return { filepath: tsPath, type: 'ts', exists: false, content: '' };
|
|
26
|
-
};
|
|
27
|
-
const buildDefaultPresenterFactoryConfigEntry = (factoryName) => {
|
|
28
|
-
return `defaultPresenterFactory: '${factoryName}'`;
|
|
29
|
-
};
|
|
30
|
-
const upsertDefaultPresenterFactoryConfig = (content, factoryName) => {
|
|
31
|
-
const hasExportDefaultObject = /export\s+default\s*\{[\s\S]*\}\s*;?/.test(content);
|
|
32
|
-
const defaultFactoryEntry = buildDefaultPresenterFactoryConfigEntry(factoryName);
|
|
33
|
-
if (!hasExportDefaultObject) {
|
|
34
|
-
return `export default {\n\t${defaultFactoryEntry}\n};\n`;
|
|
35
|
-
}
|
|
36
|
-
let nextContent = content;
|
|
37
|
-
if (/defaultPresenterFactory\s*:/.test(nextContent)) {
|
|
38
|
-
nextContent = nextContent.replace(/defaultPresenterFactory\s*:\s*(\{[\s\S]*?\n\s*\}|['"`][^'"`]+['"`])/m, defaultFactoryEntry);
|
|
39
|
-
} else if (/defaultPresenter\s*:/.test(nextContent)) {
|
|
40
|
-
nextContent = nextContent.replace(/defaultPresenter\s*:\s*(\{[\s\S]*?\n\s*\}|['"`][^'"`]+['"`])/m, defaultFactoryEntry);
|
|
41
|
-
} else {
|
|
42
|
-
nextContent = nextContent.replace(/export\s+default\s*\{([\s\S]*)\}\s*;?/, (_full, body) => {
|
|
43
|
-
const trimmedRight = body.replace(/\s*$/, '');
|
|
44
|
-
if (!trimmedRight.length) {
|
|
45
|
-
return `export default {\n\t${defaultFactoryEntry}\n};`;
|
|
46
|
-
}
|
|
47
|
-
const withComma = trimmedRight.endsWith(',') ? trimmedRight : `${trimmedRight},`;
|
|
48
|
-
return `export default {${withComma}\n\t${defaultFactoryEntry}\n};`;
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
return nextContent;
|
|
52
|
-
};
|
|
53
|
-
export default async function createPresenterFactory() {
|
|
54
|
-
const { presenterFactoryNameRaw } = await prompts({
|
|
55
|
-
type: 'text',
|
|
56
|
-
name: 'presenterFactoryNameRaw',
|
|
57
|
-
message: 'Presenter factory name:',
|
|
58
|
-
initial: 'AppPresenter'
|
|
59
|
-
});
|
|
60
|
-
const presenterFactoryName = toPascalCase(String(presenterFactoryNameRaw ?? 'AppPresenter')) || 'AppPresenter';
|
|
61
|
-
const { sharedContext } = await getSharedState();
|
|
62
|
-
const presenterRootPath = getFoundationConstructPath(sharedContext.name, 'presenter');
|
|
63
|
-
const filePath = path.join(presenterRootPath, `${presenterFactoryName}.ts`);
|
|
64
|
-
await fs.mkdir(presenterRootPath, { recursive: true });
|
|
65
|
-
const created = await writeIfNotExists(filePath, createPresenterFactoryTemplate(presenterFactoryName));
|
|
66
|
-
if (!created) {
|
|
67
|
-
console.log(`⚠️ Presenter factory "${presenterFactoryName}" already exists. File was not overwritten.`);
|
|
68
|
-
} else {
|
|
69
|
-
await updateIndexTs(presenterRootPath);
|
|
70
|
-
console.log(`✅ Presenter factory created: ${filePath}`);
|
|
71
|
-
}
|
|
72
|
-
const { useAsDefault } = await prompts({
|
|
73
|
-
type: 'confirm',
|
|
74
|
-
name: 'useAsDefault',
|
|
75
|
-
message: 'Use this presenter factory as default for the project?',
|
|
76
|
-
initial: true
|
|
77
|
-
});
|
|
78
|
-
if (!useAsDefault) return;
|
|
79
|
-
const config = resolveConfigFile(process.cwd());
|
|
80
|
-
const nextContent = upsertDefaultPresenterFactoryConfig(config.content, presenterFactoryName);
|
|
81
|
-
await fs.writeFile(config.filepath, nextContent, 'utf-8');
|
|
82
|
-
console.log(`✅ Default presenter factory saved to ${path.basename(config.filepath)}`);
|
|
83
|
-
}
|