@azure-net/cli 5.1.1 → 6.0.0-next.3

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.
Files changed (180) hide show
  1. package/README.md +201 -0
  2. package/bin/azure-net.js +236 -221
  3. package/dist/bin/azure-net.d.ts +2 -0
  4. package/dist/src/checks/architecture.d.ts +20 -0
  5. package/dist/src/checks/checkDomain.d.ts +1 -0
  6. package/dist/src/checks/checkFoldersStructure.d.ts +1 -0
  7. package/dist/src/checks/checkHooks.d.ts +1 -0
  8. package/dist/src/checks/checkImports.d.ts +1 -0
  9. package/dist/src/checks/checkInternal.d.ts +1 -0
  10. package/dist/src/checks/checkLayerBoundaries.d.ts +1 -0
  11. package/dist/src/checks/checkLayerImports.d.ts +1 -0
  12. package/dist/src/checks/checkPresenterNames.d.ts +1 -0
  13. package/dist/src/checks/checkProject.d.ts +1 -0
  14. package/dist/src/checks/checkProviderGraph.d.ts +1 -0
  15. package/dist/src/checks/checkProviderNames.d.ts +1 -0
  16. package/dist/src/generate/layers/generateRepository.d.ts +1 -0
  17. package/dist/src/generate/layers/generateRepositoryMethod.d.ts +1 -0
  18. package/dist/src/generate/layers/generateUseCases.d.ts +1 -0
  19. package/dist/src/generate/module/generateDomain.d.ts +8 -0
  20. package/dist/src/generate/module/generateModule.d.ts +1 -0
  21. package/dist/src/generate/module/generateModulePreset.d.ts +1 -0
  22. package/dist/src/generate/module/generatePresenter.d.ts +29 -0
  23. package/dist/src/generate/module/generateRepository.d.ts +15 -0
  24. package/dist/src/generate/module/generateRepositoryMethod.d.ts +2 -0
  25. package/dist/src/generate/module/generateSchemaFromType.d.ts +9 -0
  26. package/dist/src/generate/module/generateStore.d.ts +1 -0
  27. package/dist/src/generate/module/generateTypesJson.d.ts +2 -0
  28. package/dist/src/generate/module/generateUseCases.d.ts +1 -0
  29. package/dist/src/generate/module/repositoryModuleShared.d.ts +89 -0
  30. package/dist/src/generate/routes/generateRoutes.d.ts +14 -0
  31. package/dist/src/generate/ui/generateComponent.d.ts +1 -0
  32. package/dist/src/generate/ui/generateDesignComponent.d.ts +1 -0
  33. package/dist/src/generate/ui/generateWidget.d.ts +1 -0
  34. package/dist/src/git/commit.d.ts +23 -0
  35. package/dist/src/git/push.d.ts +11 -0
  36. package/dist/src/git/runGit.d.ts +2 -0
  37. package/dist/src/init/initAliases.d.ts +12 -0
  38. package/dist/src/init/initEdges.d.ts +2 -0
  39. package/dist/src/init/initStructure.d.ts +1 -0
  40. package/dist/src/install/configureCommitTools.d.ts +1 -0
  41. package/dist/src/install/installFresh.d.ts +1 -0
  42. package/dist/src/migrate/migrate.d.ts +22 -0
  43. package/dist/src/migrate/presenterFactories.d.ts +9 -0
  44. package/dist/src/migrate/presenters.d.ts +13 -0
  45. package/dist/src/migrate/translations.d.ts +8 -0
  46. package/dist/src/plugins/addLint.d.ts +5 -0
  47. package/dist/src/scaffolds/createCoreSchema.d.ts +1 -0
  48. package/dist/src/scaffolds/createDatasource.d.ts +1 -0
  49. package/dist/src/scaffolds/createProgram.d.ts +1 -0
  50. package/dist/src/scaffolds/createResponse.d.ts +1 -0
  51. package/dist/src/scaffolds/createSchemaRule.d.ts +1 -0
  52. package/dist/src/scaffolds/createTranslationManager.d.ts +1 -0
  53. package/{src/scaffolds/index.ts → dist/src/scaffolds/index.d.ts} +0 -2
  54. package/dist/src/scaffolds/registerDatasource.d.ts +2 -0
  55. package/dist/src/scaffolds/updateDefaultFactoryConfig.d.ts +1 -0
  56. package/dist/src/utils/architecture.d.ts +31 -0
  57. package/dist/src/utils/contextUtils.d.ts +6 -0
  58. package/dist/src/utils/fileUtils.d.ts +5 -0
  59. package/dist/src/utils/flattenConfig.d.ts +2 -0
  60. package/dist/src/utils/legacyAliases.d.ts +1 -0
  61. package/dist/src/utils/loadConfig.d.ts +16 -0
  62. package/dist/src/utils/packageImports.d.ts +4 -0
  63. package/dist/src/utils/sharedFoundation.d.ts +20 -0
  64. package/dist/src/utils/viteConfig.d.ts +9 -0
  65. package/package.json +17 -7
  66. package/src/checks/architecture.js +154 -0
  67. package/src/checks/checkDomain.js +124 -154
  68. package/src/checks/checkFoldersStructure.js +64 -52
  69. package/src/checks/checkHooks.js +12 -12
  70. package/src/checks/checkImports.js +26 -142
  71. package/src/checks/checkInternal.js +27 -24
  72. package/src/checks/checkLayerBoundaries.js +22 -197
  73. package/src/checks/checkLayerImports.js +14 -134
  74. package/src/checks/checkPresenterNames.js +156 -143
  75. package/src/checks/checkProject.js +27 -26
  76. package/src/checks/checkProviderGraph.js +182 -166
  77. package/src/checks/checkProviderNames.js +123 -112
  78. package/src/generate/layers/generateRepository.js +1 -109
  79. package/src/generate/layers/generateRepositoryMethod.js +1 -90
  80. package/src/generate/layers/generateUseCases.js +1 -44
  81. package/src/generate/module/generateDomain.js +81 -105
  82. package/src/generate/module/generateModule.js +34 -68
  83. package/src/generate/module/generateModulePreset.js +188 -248
  84. package/src/generate/module/generatePresenter.js +441 -369
  85. package/src/generate/module/generateRepository.js +102 -121
  86. package/src/generate/module/generateRepositoryMethod.js +117 -0
  87. package/src/generate/module/generateSchemaFromType.js +283 -280
  88. package/src/generate/module/generateStore.js +41 -0
  89. package/src/generate/module/generateTypesJson.js +196 -195
  90. package/src/generate/module/generateUseCases.js +47 -55
  91. package/src/generate/module/repositoryModuleShared.js +480 -459
  92. package/src/generate/routes/generateRoutes.js +4 -7
  93. package/src/generate/ui/generateComponent.js +44 -64
  94. package/src/generate/ui/generateDesignComponent.js +21 -41
  95. package/src/generate/ui/generateWidget.js +21 -41
  96. package/src/git/commit.js +67 -0
  97. package/src/git/push.js +19 -0
  98. package/src/git/runGit.js +11 -0
  99. package/src/init/initAliases.js +19 -135
  100. package/src/init/initEdges.js +79 -54
  101. package/src/init/initStructure.js +31 -145
  102. package/src/install/configureCommitTools.js +1 -0
  103. package/src/install/installFresh.js +39 -68
  104. package/src/migrate/migrate.js +1027 -0
  105. package/src/migrate/presenterFactories.js +189 -0
  106. package/src/migrate/presenters.js +373 -0
  107. package/src/migrate/translations.js +213 -0
  108. package/src/plugins/addLint.js +52 -219
  109. package/src/scaffolds/createCoreSchema.js +65 -91
  110. package/src/scaffolds/createDatasource.js +67 -101
  111. package/src/scaffolds/createProgram.js +8 -8
  112. package/src/scaffolds/createResponse.js +29 -29
  113. package/src/scaffolds/createSchemaRule.js +19 -19
  114. package/src/scaffolds/createTranslationManager.js +84 -37
  115. package/src/scaffolds/index.js +0 -2
  116. package/src/scaffolds/registerDatasource.js +59 -0
  117. package/src/scaffolds/updateDefaultFactoryConfig.js +31 -0
  118. package/src/utils/architecture.js +145 -0
  119. package/src/utils/contextUtils.js +32 -65
  120. package/src/utils/fileUtils.js +69 -50
  121. package/src/utils/flattenConfig.js +38 -0
  122. package/src/utils/legacyAliases.js +75 -0
  123. package/src/utils/loadConfig.js +76 -40
  124. package/src/utils/packageImports.js +63 -0
  125. package/src/utils/sharedFoundation.js +36 -42
  126. package/src/utils/viteConfig.js +295 -0
  127. package/.prettierrc +0 -7
  128. package/bin/azure-net.ts +0 -308
  129. package/eslint.config.js +0 -34
  130. package/src/checks/checkDomain.ts +0 -223
  131. package/src/checks/checkFoldersStructure.ts +0 -85
  132. package/src/checks/checkHooks.ts +0 -22
  133. package/src/checks/checkImports.ts +0 -193
  134. package/src/checks/checkInternal.ts +0 -48
  135. package/src/checks/checkLayerBoundaries.ts +0 -255
  136. package/src/checks/checkLayerImports.ts +0 -185
  137. package/src/checks/checkPresenterNames.ts +0 -203
  138. package/src/checks/checkProject.ts +0 -45
  139. package/src/checks/checkProviderGraph.ts +0 -234
  140. package/src/checks/checkProviderNames.ts +0 -165
  141. package/src/generate/layers/generateRepository.ts +0 -123
  142. package/src/generate/layers/generateRepositoryMethod.ts +0 -102
  143. package/src/generate/layers/generateUseCases.ts +0 -50
  144. package/src/generate/layers/repositoryShared.js +0 -506
  145. package/src/generate/layers/repositoryShared.ts +0 -662
  146. package/src/generate/module/generateDomain.ts +0 -147
  147. package/src/generate/module/generateModule.ts +0 -84
  148. package/src/generate/module/generateModulePreset.ts +0 -338
  149. package/src/generate/module/generatePresenter.ts +0 -498
  150. package/src/generate/module/generateRepository.ts +0 -158
  151. package/src/generate/module/generateSchemaFromType.ts +0 -368
  152. package/src/generate/module/generateTypesJson.ts +0 -259
  153. package/src/generate/module/generateUseCases.ts +0 -67
  154. package/src/generate/module/repositoryModuleShared.ts +0 -669
  155. package/src/generate/routes/generateRoutes.ts +0 -275
  156. package/src/generate/ui/generateComponent.ts +0 -100
  157. package/src/generate/ui/generateDesignComponent.ts +0 -71
  158. package/src/generate/ui/generateWidget.ts +0 -71
  159. package/src/init/initAliases.ts +0 -172
  160. package/src/init/initEdges.ts +0 -74
  161. package/src/init/initStructure.ts +0 -172
  162. package/src/install/installFresh.ts +0 -93
  163. package/src/plugins/addLint.ts +0 -274
  164. package/src/scaffolds/createCoreSchema.ts +0 -130
  165. package/src/scaffolds/createDatasource.ts +0 -161
  166. package/src/scaffolds/createDatasourceProvider.js +0 -127
  167. package/src/scaffolds/createDatasourceProvider.ts +0 -161
  168. package/src/scaffolds/createPresenterFactory.js +0 -83
  169. package/src/scaffolds/createPresenterFactory.ts +0 -102
  170. package/src/scaffolds/createProgram.ts +0 -19
  171. package/src/scaffolds/createResponse.ts +0 -66
  172. package/src/scaffolds/createSchemaRule.ts +0 -44
  173. package/src/scaffolds/createTranslationManager.ts +0 -80
  174. package/src/utils/contextUtils.ts +0 -88
  175. package/src/utils/fileUtils.ts +0 -74
  176. package/src/utils/loadConfig.ts +0 -68
  177. package/src/utils/sharedFoundation.ts +0 -70
  178. package/tsconfig.json +0 -19
  179. /package/{src/checks/index.ts → dist/src/checks/index.d.ts} +0 -0
  180. /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
- }