@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.
Files changed (67) hide show
  1. package/bin/azure-net.js +5 -46
  2. package/bin/azure-net.ts +5 -5
  3. package/package.json +1 -1
  4. package/src/checks/checkDomain.js +8 -38
  5. package/src/checks/checkFoldersStructure.js +0 -14
  6. package/src/checks/checkHooks.js +0 -5
  7. package/src/checks/checkImports.js +0 -1
  8. package/src/checks/checkInternal.js +0 -1
  9. package/src/checks/checkLayerBoundaries.js +50 -54
  10. package/src/checks/checkLayerBoundaries.ts +55 -58
  11. package/src/checks/checkPresenterNames.js +1 -37
  12. package/src/checks/checkPresenterNames.ts +1 -6
  13. package/src/checks/checkProject.js +0 -6
  14. package/src/checks/checkProviderGraph.js +1 -38
  15. package/src/checks/checkProviderNames.js +0 -28
  16. package/src/checks/index.js +0 -1
  17. package/src/generate/layers/generateRepository.js +4 -19
  18. package/src/generate/layers/generateRepositoryMethod.js +0 -12
  19. package/src/generate/layers/generateUseCases.js +0 -6
  20. package/src/generate/layers/repositoryShared.js +41 -104
  21. package/src/generate/layers/repositoryShared.ts +17 -12
  22. package/src/generate/module/generateDomain.js +0 -25
  23. package/src/generate/module/generateModule.js +0 -10
  24. package/src/generate/module/generateModulePreset.js +10 -51
  25. package/src/generate/module/generateModulePreset.ts +9 -8
  26. package/src/generate/module/generatePresenter.js +366 -371
  27. package/src/generate/module/generatePresenter.ts +76 -20
  28. package/src/generate/module/generateRepository.js +0 -17
  29. package/src/generate/module/generateSchemaFromType.js +9 -58
  30. package/src/generate/module/generateSchemaFromType.ts +1 -2
  31. package/src/generate/module/generateTypesJson.js +4 -45
  32. package/src/generate/module/generateUseCases.js +0 -9
  33. package/src/generate/module/repositoryModuleShared.js +21 -98
  34. package/src/generate/module/repositoryModuleShared.ts +14 -10
  35. package/src/generate/ui/generateComponent.js +0 -16
  36. package/src/generate/ui/generateDesignComponent.js +0 -12
  37. package/src/generate/ui/generateWidget.js +0 -12
  38. package/src/init/initAliases.js +42 -64
  39. package/src/init/initAliases.ts +47 -42
  40. package/src/init/initEdges.js +0 -15
  41. package/src/init/initStructure.js +48 -21
  42. package/src/init/initStructure.ts +51 -3
  43. package/src/install/installFresh.js +0 -16
  44. package/src/plugins/addLint.js +11 -46
  45. package/src/scaffolds/createCoreSchema.js +6 -40
  46. package/src/scaffolds/createCoreSchema.ts +6 -18
  47. package/src/scaffolds/createDatasource.js +26 -61
  48. package/src/scaffolds/createDatasource.ts +26 -40
  49. package/src/scaffolds/createDatasourceProvider.js +19 -56
  50. package/src/scaffolds/createDatasourceProvider.ts +20 -34
  51. package/src/scaffolds/createPresenterFactory.js +67 -94
  52. package/src/scaffolds/createPresenterFactory.ts +7 -19
  53. package/src/scaffolds/createProgram.js +1 -5
  54. package/src/scaffolds/createResponse.js +3 -11
  55. package/src/scaffolds/createResponse.ts +3 -1
  56. package/src/scaffolds/createSchemaRule.js +3 -8
  57. package/src/scaffolds/createSchemaRule.ts +3 -1
  58. package/src/scaffolds/createTranslationManager.js +3 -14
  59. package/src/scaffolds/createTranslationManager.ts +3 -1
  60. package/src/utils/contextUtils.js +5 -20
  61. package/src/utils/contextUtils.ts +2 -3
  62. package/src/utils/fileUtils.js +3 -38
  63. package/src/utils/fileUtils.ts +0 -26
  64. package/src/utils/loadConfig.js +1 -14
  65. package/src/utils/loadConfig.ts +1 -3
  66. package/src/utils/sharedFoundation.js +48 -0
  67. package/src/utils/sharedFoundation.ts +70 -0
@@ -3,11 +3,12 @@ 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, resolveConfigFile } from '../utils/loadConfig.js';
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 NormalizedContext = { name: string; alias: string };
10
- type DatasourceChoiceValue = null | { name: string; source: 'core' | 'context' };
11
+ type DatasourceChoiceValue = null | { name: string; source: 'shared' | 'context' };
11
12
 
12
13
  const createProviderTemplateWithoutDatasource = (
13
14
  providerName: string,
@@ -45,26 +46,6 @@ export const ${providerName} = createBoundaryProvider('${contextPrefix}${provide
45
46
  `;
46
47
  };
47
48
 
48
- const getCoreAliasOrThrow = async (): Promise<string> => {
49
- const configRef = resolveConfigFile();
50
- if (!configRef.exists) {
51
- throw new Error(
52
- 'azure-net.config is not configured. Run "azure-net init folders-structure" and do not forget to fill contexts if you need them.'
53
- );
54
- }
55
-
56
- const content = await fs.readFile(configRef.filepath, 'utf-8');
57
- const aliasMatch = content.match(/coreAlias\s*:\s*['"`]([^'"`]+)['"`]/);
58
- const alias = aliasMatch?.[1]?.trim();
59
- if (!alias) {
60
- throw new Error(
61
- 'azure-net.config is not configured. Run "azure-net init folders-structure" and do not forget to fill contexts if you need them.'
62
- );
63
- }
64
-
65
- return alias.startsWith('$') ? alias : `$${alias}`;
66
- };
67
-
68
49
  const getDatasourcesFromPath = async (targetPath: string): Promise<string[]> => {
69
50
  try {
70
51
  const files = await fs.readdir(targetPath);
@@ -74,11 +55,11 @@ const getDatasourcesFromPath = async (targetPath: string): Promise<string[]> =>
74
55
  }
75
56
  };
76
57
 
77
- const resolveContextPrefix = (target: string): string => (target === 'core' ? 'Core' : toPascalCase(target));
58
+ const resolveContextPrefix = (target: string): string => (target === '__shared__' ? 'Shared' : toPascalCase(target));
78
59
 
79
60
  const resolveProviderPath = (target: string): string => {
80
- if (target === 'core') {
81
- return path.join(process.cwd(), 'src', 'core', 'provider');
61
+ if (target === '__shared__') {
62
+ throw new Error('Shared provider path must be resolved async.');
82
63
  }
83
64
 
84
65
  return path.join(process.cwd(), 'src', 'app', target, 'layers', 'infrastructure', 'providers');
@@ -109,7 +90,10 @@ export default async function createDatasourceProvider(): Promise<void> {
109
90
  const providerName = ensureProviderName(String(providerNameRaw ?? 'DatasourceProvider'));
110
91
  const config = await loadUserConfig();
111
92
  const contexts = normalizeContexts(config.contexts) as NormalizedContext[];
112
- const contextChoices = [{ title: 'core', value: 'core' }, ...contexts.map((context) => ({ title: context.name, value: context.name }))];
93
+ const contextChoices = [
94
+ { title: 'shared foundation', value: '__shared__' },
95
+ ...contexts.map((context) => ({ title: context.name, value: context.name }))
96
+ ];
113
97
 
114
98
  const { target } = await prompts({
115
99
  type: 'select',
@@ -119,18 +103,19 @@ export default async function createDatasourceProvider(): Promise<void> {
119
103
  initial: 0
120
104
  });
121
105
 
122
- const selectedTarget = String(target ?? 'core');
123
- const coreDatasources = await getDatasourcesFromPath(path.join(process.cwd(), 'src', 'core', 'datasource'));
106
+ const selectedTarget = String(target ?? '__shared__');
107
+ const { sharedAlias, sharedContext } = await getSharedState();
108
+ const sharedDatasources = await getDatasourcesFromPath(getFoundationConstructPath(sharedContext.name, 'datasource'));
124
109
  const contextDatasources =
125
- selectedTarget === 'core'
110
+ selectedTarget === '__shared__'
126
111
  ? []
127
112
  : await getDatasourcesFromPath(
128
113
  path.join(process.cwd(), 'src', 'app', selectedTarget, 'layers', 'infrastructure', 'http', 'datasources')
129
114
  );
130
115
 
131
116
  const datasourceChoices: Array<{ title: string; value: DatasourceChoiceValue }> = [{ title: 'No datasource', value: null }];
132
- for (const datasource of coreDatasources) {
133
- datasourceChoices.push({ title: `${datasource} (core)`, value: { name: datasource, source: 'core' } });
117
+ for (const datasource of sharedDatasources) {
118
+ datasourceChoices.push({ title: `${datasource} (shared foundation)`, value: { name: datasource, source: 'shared' } });
134
119
  }
135
120
  for (const datasource of contextDatasources) {
136
121
  datasourceChoices.push({ title: `${datasource} (${selectedTarget})`, value: { name: datasource, source: 'context' } });
@@ -152,14 +137,15 @@ export default async function createDatasourceProvider(): Promise<void> {
152
137
  content = createProviderTemplateWithoutDatasource(providerName, contextPrefix);
153
138
  } else {
154
139
  const importPath =
155
- selectedDatasource.source === 'core'
156
- ? `${await getCoreAliasOrThrow()}/datasource`
140
+ selectedDatasource.source === 'shared'
141
+ ? getFoundationConstructImportPath(sharedAlias, 'datasource')
157
142
  : `${resolveContextAlias(contexts, selectedTarget)}/layers/infrastructure/http/datasources`;
158
143
 
159
144
  content = createProviderTemplateWithDatasource(providerName, contextPrefix, selectedDatasource.name, importPath);
160
145
  }
161
146
 
162
- const providerPath = resolveProviderPath(selectedTarget);
147
+ const providerPath =
148
+ selectedTarget === '__shared__' ? getFoundationConstructPath(sharedContext.name, 'provider') : resolveProviderPath(selectedTarget);
163
149
  await fs.mkdir(providerPath, { recursive: true });
164
150
 
165
151
  const filePath = path.join(providerPath, `${providerName}.ts`);
@@ -4,109 +4,82 @@ 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';
8
+ const createPresenterFactoryTemplate = (factoryName) => `import { createAsyncHelpers, createPresenterFactory } from '@azure-net/kit/delivery';
7
9
 
8
- const createPresenterFactoryTemplate = (
9
- factoryName
10
- ) => `import { createErrorHandler, createAsyncHelpers, createPresenterFactory } from '@azure-net/kit/delivery';
11
-
12
- export const AsyncHelpers = createAsyncHelpers({ handler: createErrorHandler() });
10
+ export const AsyncHelpers = createAsyncHelpers();
13
11
 
14
12
  export const ${factoryName} = createPresenterFactory({ ...AsyncHelpers });
15
13
  `;
16
-
17
14
  const resolveConfigFile = (cwd) => {
18
- const tsPath = path.join(cwd, 'azure-net.config.ts');
19
- const jsPath = path.join(cwd, 'azure-net.config.js');
20
-
21
- if (fsSync.existsSync(tsPath)) {
22
- return { filepath: tsPath, type: 'ts', exists: true, content: fsSync.readFileSync(tsPath, 'utf-8') };
23
- }
24
- if (fsSync.existsSync(jsPath)) {
25
- return { filepath: jsPath, type: 'js', exists: true, content: fsSync.readFileSync(jsPath, 'utf-8') };
26
- }
27
-
28
- return { filepath: tsPath, type: 'ts', exists: false, content: '' };
15
+ const tsPath = path.join(cwd, 'azure-net.config.ts');
16
+ const jsPath = path.join(cwd, 'azure-net.config.js');
17
+ if (fsSync.existsSync(tsPath)) {
18
+ return { filepath: tsPath, type: 'ts', exists: true, content: fsSync.readFileSync(tsPath, 'utf-8') };
19
+ }
20
+ if (fsSync.existsSync(jsPath)) {
21
+ return { filepath: jsPath, type: 'js', exists: true, content: fsSync.readFileSync(jsPath, 'utf-8') };
22
+ }
23
+ return { filepath: tsPath, type: 'ts', exists: false, content: '' };
29
24
  };
30
-
31
25
  const buildDefaultPresenterFactoryConfigEntry = (factoryName) => {
32
- return `defaultPresenterFactory: '${factoryName}'`;
26
+ return `defaultPresenterFactory: '${factoryName}'`;
33
27
  };
34
-
35
28
  const upsertDefaultPresenterFactoryConfig = (content, factoryName) => {
36
- const hasExportDefaultObject = /export\s+default\s*\{[\s\S]*\}\s*;?/.test(content);
37
- const defaultFactoryEntry = buildDefaultPresenterFactoryConfigEntry(factoryName);
38
- const coreAliasEntry = `coreAlias: '$core'`;
39
-
40
- if (!hasExportDefaultObject) {
41
- return `export default {\n\t${coreAliasEntry},\n\t${defaultFactoryEntry}\n};\n`;
42
- }
43
-
44
- let nextContent = content;
45
-
46
- if (/defaultPresenterFactory\s*:/.test(nextContent)) {
47
- nextContent = nextContent.replace(/defaultPresenterFactory\s*:\s*(\{[\s\S]*?\n\s*\}|['"`][^'"`]+['"`])/m, defaultFactoryEntry);
48
- } else if (/defaultPresenter\s*:/.test(nextContent)) {
49
- nextContent = nextContent.replace(/defaultPresenter\s*:\s*(\{[\s\S]*?\n\s*\}|['"`][^'"`]+['"`])/m, defaultFactoryEntry);
50
- } else {
51
- nextContent = nextContent.replace(/export\s+default\s*\{([\s\S]*)\}\s*;?/, (_full, body) => {
52
- const trimmedRight = body.replace(/\s*$/, '');
53
- if (!trimmedRight.length) {
54
- return `export default {\n\t${defaultFactoryEntry}\n};`;
55
- }
56
-
57
- const withComma = trimmedRight.endsWith(',') ? trimmedRight : `${trimmedRight},`;
58
- return `export default {${withComma}\n\t${defaultFactoryEntry}\n};`;
59
- });
60
- }
61
-
62
- if (/coreAlias\s*:/.test(nextContent)) {
63
- return nextContent.replace(/coreAlias\s*:\s*['"`][^'"`]+['"`]/, coreAliasEntry);
64
- }
65
-
66
- return nextContent.replace(/export\s+default\s*\{([\s\S]*)\}\s*;?/, (_full, body) => {
67
- const trimmedRight = body.replace(/\s*$/, '');
68
- if (!trimmedRight.length) {
69
- return `export default {\n\t${coreAliasEntry}\n};`;
70
- }
71
-
72
- const withComma = trimmedRight.endsWith(',') ? trimmedRight : `${trimmedRight},`;
73
- return `export default {${withComma}\n\t${coreAliasEntry}\n};`;
74
- });
29
+ const hasExportDefaultObject = /export\s+default\s*\{[\s\S]*\}\s*;?/.test(content);
30
+ const defaultFactoryEntry = buildDefaultPresenterFactoryConfigEntry(factoryName);
31
+ if (!hasExportDefaultObject) {
32
+ return `export default {\n\t${defaultFactoryEntry}\n};\n`;
33
+ }
34
+ let nextContent = content;
35
+ if (/defaultPresenterFactory\s*:/.test(nextContent)) {
36
+ nextContent = nextContent.replace(/defaultPresenterFactory\s*:\s*(\{[\s\S]*?\n\s*\}|['"`][^'"`]+['"`])/m, defaultFactoryEntry);
37
+ }
38
+ else if (/defaultPresenter\s*:/.test(nextContent)) {
39
+ nextContent = nextContent.replace(/defaultPresenter\s*:\s*(\{[\s\S]*?\n\s*\}|['"`][^'"`]+['"`])/m, defaultFactoryEntry);
40
+ }
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;
75
52
  };
76
-
77
53
  export default async function createPresenterFactory() {
78
- const { presenterFactoryNameRaw } = await prompts({
79
- type: 'text',
80
- name: 'presenterFactoryNameRaw',
81
- message: 'Presenter factory name:',
82
- initial: 'AppPresenter'
83
- });
84
-
85
- const presenterFactoryName = toPascalCase(String(presenterFactoryNameRaw ?? 'AppPresenter')) || 'AppPresenter';
86
- const presenterRootPath = path.join(process.cwd(), 'src', 'core', 'presenter');
87
- const filePath = path.join(presenterRootPath, `${presenterFactoryName}.ts`);
88
-
89
- await fs.mkdir(presenterRootPath, { recursive: true });
90
-
91
- const created = await writeIfNotExists(filePath, createPresenterFactoryTemplate(presenterFactoryName));
92
- if (!created) {
93
- console.log(`⚠️ Presenter factory "${presenterFactoryName}" already exists. File was not overwritten.`);
94
- } else {
95
- await updateIndexTs(presenterRootPath);
96
- console.log(`✅ Presenter factory created: ${filePath}`);
97
- }
98
-
99
- const { useAsDefault } = await prompts({
100
- type: 'confirm',
101
- name: 'useAsDefault',
102
- message: 'Use this presenter factory as default for the project?',
103
- initial: true
104
- });
105
-
106
- if (!useAsDefault) return;
107
-
108
- const config = resolveConfigFile(process.cwd());
109
- const nextContent = upsertDefaultPresenterFactoryConfig(config.content, presenterFactoryName);
110
- await fs.writeFile(config.filepath, nextContent, 'utf-8');
111
- console.log(`✅ Default presenter factory saved to ${path.basename(config.filepath)}`);
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
+ }
69
+ else {
70
+ await updateIndexTs(presenterRootPath);
71
+ console.log(`✅ Presenter factory created: ${filePath}`);
72
+ }
73
+ const { useAsDefault } = await prompts({
74
+ type: 'confirm',
75
+ name: 'useAsDefault',
76
+ message: 'Use this presenter factory as default for the project?',
77
+ initial: true
78
+ });
79
+ if (!useAsDefault)
80
+ return;
81
+ const config = resolveConfigFile(process.cwd());
82
+ const nextContent = upsertDefaultPresenterFactoryConfig(config.content, presenterFactoryName);
83
+ await fs.writeFile(config.filepath, nextContent, 'utf-8');
84
+ console.log(`✅ Default presenter factory saved to ${path.basename(config.filepath)}`);
112
85
  }
@@ -4,14 +4,15 @@ 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 ConfigPath = 'ts' | 'js';
9
10
 
10
11
  const createPresenterFactoryTemplate = (
11
12
  factoryName: string
12
- ): string => `import { createErrorHandler, createAsyncHelpers, createPresenterFactory } from '@azure-net/kit/delivery';
13
+ ): string => `import { createAsyncHelpers, createPresenterFactory } from '@azure-net/kit/delivery';
13
14
 
14
- export const AsyncHelpers = createAsyncHelpers({ handler: createErrorHandler() });
15
+ export const AsyncHelpers = createAsyncHelpers();
15
16
 
16
17
  export const ${factoryName} = createPresenterFactory({ ...AsyncHelpers });
17
18
  `;
@@ -37,10 +38,9 @@ const buildDefaultPresenterFactoryConfigEntry = (factoryName: string): string =>
37
38
  const upsertDefaultPresenterFactoryConfig = (content: string, factoryName: string): string => {
38
39
  const hasExportDefaultObject = /export\s+default\s*\{[\s\S]*\}\s*;?/.test(content);
39
40
  const defaultFactoryEntry = buildDefaultPresenterFactoryConfigEntry(factoryName);
40
- const coreAliasEntry = `coreAlias: '$core'`;
41
41
 
42
42
  if (!hasExportDefaultObject) {
43
- return `export default {\n\t${coreAliasEntry},\n\t${defaultFactoryEntry}\n};\n`;
43
+ return `export default {\n\t${defaultFactoryEntry}\n};\n`;
44
44
  }
45
45
 
46
46
  let nextContent = content;
@@ -60,20 +60,7 @@ const upsertDefaultPresenterFactoryConfig = (content: string, factoryName: strin
60
60
  return `export default {${withComma}\n\t${defaultFactoryEntry}\n};`;
61
61
  });
62
62
  }
63
-
64
- if (/coreAlias\s*:/.test(nextContent)) {
65
- return nextContent.replace(/coreAlias\s*:\s*['"`][^'"`]+['"`]/, coreAliasEntry);
66
- }
67
-
68
- return nextContent.replace(/export\s+default\s*\{([\s\S]*)\}\s*;?/, (_full, body: string) => {
69
- const trimmedRight = body.replace(/\s*$/, '');
70
- if (!trimmedRight.length) {
71
- return `export default {\n\t${coreAliasEntry}\n};`;
72
- }
73
-
74
- const withComma = trimmedRight.endsWith(',') ? trimmedRight : `${trimmedRight},`;
75
- return `export default {${withComma}\n\t${coreAliasEntry}\n};`;
76
- });
63
+ return nextContent;
77
64
  };
78
65
 
79
66
  export default async function createPresenterFactory(): Promise<void> {
@@ -85,7 +72,8 @@ export default async function createPresenterFactory(): Promise<void> {
85
72
  });
86
73
 
87
74
  const presenterFactoryName = toPascalCase(String(presenterFactoryNameRaw ?? 'AppPresenter')) || 'AppPresenter';
88
- const presenterRootPath = path.join(process.cwd(), 'src', 'core', 'presenter');
75
+ const { sharedContext } = await getSharedState();
76
+ const presenterRootPath = getFoundationConstructPath(sharedContext.name, 'presenter');
89
77
  const filePath = path.join(presenterRootPath, `${presenterFactoryName}.ts`);
90
78
 
91
79
  await fs.mkdir(presenterRootPath, { recursive: true });
@@ -1,19 +1,15 @@
1
1
  import path from 'node:path';
2
2
  import { writeIfNotExists } from '../utils/fileUtils.js';
3
-
4
3
  const createProgramTemplate = () => `import { createApp } from '@azure-net/kit';
5
4
 
6
- export const { register, App } = createApp((app) => app);
5
+ export const { register, Container } = createApp((app) => app);
7
6
  `;
8
-
9
7
  export default async function createProgram() {
10
8
  const programPath = path.join(process.cwd(), 'src', 'program.ts');
11
9
  const created = await writeIfNotExists(programPath, createProgramTemplate());
12
-
13
10
  if (!created) {
14
11
  console.log('⚠️ Program already exists. Nothing was overwritten.');
15
12
  return;
16
13
  }
17
-
18
14
  console.log(`✅ Program created: ${programPath}`);
19
15
  }
@@ -3,7 +3,7 @@ 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
-
6
+ import { getFoundationConstructPath, getSharedState } from '../utils/sharedFoundation.js';
7
7
  const createResponseWithWrapperTemplate = (name) => {
8
8
  const interfaceName = `I${name}`;
9
9
  return `import { ResponseBuilder } from '@azure-net/kit/infra';
@@ -19,17 +19,14 @@ export class ${name}<TData = unknown, TMeta = unknown> extends ResponseBuilder<T
19
19
  }
20
20
  `;
21
21
  };
22
-
23
22
  const createResponseSimpleTemplate = (name) => `import { ResponseBuilder } from '@azure-net/kit/infra';
24
23
 
25
24
  export class ${name}<TData = unknown, TMeta = unknown> extends ResponseBuilder<TData, TMeta> {}
26
25
  `;
27
-
28
26
  const ensureResponseName = (rawName) => {
29
27
  const normalized = toPascalCase(rawName || 'ApiResponse') || 'ApiResponse';
30
28
  return normalized.endsWith('Response') ? normalized : `${normalized}Response`;
31
29
  };
32
-
33
30
  export default async function createResponse() {
34
31
  const { responseNameRaw } = await prompts({
35
32
  type: 'text',
@@ -37,28 +34,23 @@ export default async function createResponse() {
37
34
  message: 'Response class name:',
38
35
  initial: 'ApiResponse'
39
36
  });
40
-
41
37
  const responseName = ensureResponseName(String(responseNameRaw ?? 'ApiResponse'));
42
-
43
38
  const { useCommonResponseWrapper } = await prompts({
44
39
  type: 'confirm',
45
40
  name: 'useCommonResponseWrapper',
46
41
  message: 'Use common backend response wrapper interface?',
47
42
  initial: true
48
43
  });
49
-
50
- const responseRoot = path.join(process.cwd(), 'src', 'core', 'response');
44
+ const { sharedContext } = await getSharedState();
45
+ const responseRoot = getFoundationConstructPath(sharedContext.name, 'response');
51
46
  const filePath = path.join(responseRoot, `${responseName}.ts`);
52
47
  await fs.mkdir(responseRoot, { recursive: true });
53
-
54
48
  const template = useCommonResponseWrapper ? createResponseWithWrapperTemplate(responseName) : createResponseSimpleTemplate(responseName);
55
49
  const created = await writeIfNotExists(filePath, template);
56
50
  await updateIndexTs(responseRoot);
57
-
58
51
  if (!created) {
59
52
  console.log(`⚠️ Response "${responseName}" already exists. File was not overwritten.`);
60
53
  return;
61
54
  }
62
-
63
55
  console.log(`✅ Response created: ${filePath}`);
64
56
  }
@@ -3,6 +3,7 @@ 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 { getFoundationConstructPath, getSharedState } from '../utils/sharedFoundation.js';
6
7
 
7
8
  const createResponseWithWrapperTemplate = (name: string): string => {
8
9
  const interfaceName = `I${name}`;
@@ -47,7 +48,8 @@ export default async function createResponse(): Promise<void> {
47
48
  initial: true
48
49
  });
49
50
 
50
- const responseRoot = path.join(process.cwd(), 'src', 'core', 'response');
51
+ const { sharedContext } = await getSharedState();
52
+ const responseRoot = getFoundationConstructPath(sharedContext.name, 'response');
51
53
  const filePath = path.join(responseRoot, `${responseName}.ts`);
52
54
  await fs.mkdir(responseRoot, { recursive: true });
53
55
 
@@ -3,7 +3,7 @@ import path from 'node:path';
3
3
  import prompts from 'prompts';
4
4
  import { writeIfNotExists, updateIndexTs } from '../utils/fileUtils.js';
5
5
  import { toPascalCase, toCamelCase } from '../utils/contextUtils.js';
6
-
6
+ import { getFoundationConstructPath, getSharedState } from '../utils/sharedFoundation.js';
7
7
  const createSchemaRuleTemplate = (ruleName) => `import type { ValidationParams, ValidationRuleResult } from '@azure-net/kit/delivery';
8
8
 
9
9
  export const ${ruleName} = <T = unknown, D = unknown>(): ValidationRuleResult<T, D> => {
@@ -12,7 +12,6 @@ export const ${ruleName} = <T = unknown, D = unknown>(): ValidationRuleResult<T,
12
12
  \t};
13
13
  };
14
14
  `;
15
-
16
15
  export default async function createSchemaRule() {
17
16
  const { ruleNameRaw } = await prompts({
18
17
  type: 'text',
@@ -20,21 +19,17 @@ export default async function createSchemaRule() {
20
19
  message: 'Schema rule name:',
21
20
  initial: 'File'
22
21
  });
23
-
24
22
  const pascalName = toPascalCase(String(ruleNameRaw ?? 'File')) || 'File';
25
23
  const camelName = toCamelCase(pascalName) || 'file';
26
- const rulesPath = path.join(process.cwd(), 'src', 'core', 'schema', 'custom-rules');
24
+ const { sharedContext } = await getSharedState();
25
+ const rulesPath = path.join(getFoundationConstructPath(sharedContext.name, 'schema'), 'custom-rules');
27
26
  const filePath = path.join(rulesPath, `${pascalName}.ts`);
28
-
29
27
  await fs.mkdir(rulesPath, { recursive: true });
30
-
31
28
  const created = await writeIfNotExists(filePath, createSchemaRuleTemplate(camelName));
32
29
  await updateIndexTs(rulesPath);
33
-
34
30
  if (!created) {
35
31
  console.log(`⚠️ Schema rule "${pascalName}" already exists. File was not overwritten.`);
36
32
  return;
37
33
  }
38
-
39
34
  console.log(`✅ Schema rule created: ${filePath}`);
40
35
  }
@@ -3,6 +3,7 @@ import path from 'node:path';
3
3
  import prompts from 'prompts';
4
4
  import { writeIfNotExists, updateIndexTs } from '../utils/fileUtils.js';
5
5
  import { toPascalCase, toCamelCase } from '../utils/contextUtils.js';
6
+ import { getFoundationConstructPath, getSharedState } from '../utils/sharedFoundation.js';
6
7
 
7
8
  const createSchemaRuleTemplate = (
8
9
  ruleName: string
@@ -25,7 +26,8 @@ export default async function createSchemaRule(): Promise<void> {
25
26
 
26
27
  const pascalName = toPascalCase(String(ruleNameRaw ?? 'File')) || 'File';
27
28
  const camelName = toCamelCase(pascalName) || 'file';
28
- const rulesPath = path.join(process.cwd(), 'src', 'core', 'schema', 'custom-rules');
29
+ const { sharedContext } = await getSharedState();
30
+ const rulesPath = path.join(getFoundationConstructPath(sharedContext.name, 'schema'), 'custom-rules');
29
31
  const filePath = path.join(rulesPath, `${pascalName}.ts`);
30
32
 
31
33
  await fs.mkdir(rulesPath, { recursive: true });
@@ -2,17 +2,15 @@ import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import prompts from 'prompts';
4
4
  import { writeIfNotExists } from '../utils/fileUtils.js';
5
-
5
+ import { getLocalizationPath, getSharedState } from '../utils/sharedFoundation.js';
6
6
  const parseLocales = (rawLocales) => {
7
7
  const parsed = String(rawLocales ?? '')
8
8
  .split(',')
9
9
  .map((item) => item.trim().toLowerCase())
10
10
  .filter(Boolean);
11
-
12
11
  const unique = Array.from(new Set(parsed));
13
12
  return unique.length ? unique : ['en', 'ru'];
14
13
  };
15
-
16
14
  const createTranslationIndexTemplate = (defaultLocale) => `import { messages } from './locales/index.js';
17
15
  import { createTranslations, type Path } from '@azure-net/kit/i18n';
18
16
 
@@ -30,17 +28,14 @@ export type MessageKeys = Path<MessagesList>;
30
28
  export type TranslationParam = MessageKeys | string | TranslationExtended;
31
29
  export type AvailableLocales = keyof typeof messages;
32
30
  `;
33
-
34
31
  const createLocalesIndexTemplate = (locales) => {
35
32
  const lines = locales.map((locale) => `\t${locale}: () => import('./${locale}/index.js').then((res) => res.default)`);
36
33
  return `export const messages = {\n${lines.join(',\n')}\n};\n`;
37
34
  };
38
-
39
35
  const createLocaleTemplate = () => `export default {
40
36
  \ttest: 'test'
41
37
  };
42
38
  `;
43
-
44
39
  export default async function createTranslationManager() {
45
40
  const { localesRaw } = await prompts({
46
41
  type: 'text',
@@ -48,9 +43,7 @@ export default async function createTranslationManager() {
48
43
  message: 'Enter locales (comma separated):',
49
44
  initial: 'en, ru'
50
45
  });
51
-
52
46
  const locales = parseLocales(String(localesRaw ?? 'en, ru'));
53
-
54
47
  const { defaultLocale } = await prompts({
55
48
  type: 'select',
56
49
  name: 'defaultLocale',
@@ -58,21 +51,17 @@ export default async function createTranslationManager() {
58
51
  choices: locales.map((locale) => ({ title: locale, value: locale })),
59
52
  initial: 0
60
53
  });
61
-
62
54
  const selectedDefaultLocale = String(defaultLocale ?? locales[0] ?? 'en');
63
-
64
- const translationRoot = path.join(process.cwd(), 'src', 'core', 'translation');
55
+ const { sharedContext } = await getSharedState();
56
+ const translationRoot = getLocalizationPath(sharedContext.name);
65
57
  const localesRoot = path.join(translationRoot, 'locales');
66
58
  await fs.mkdir(localesRoot, { recursive: true });
67
-
68
59
  await writeIfNotExists(path.join(translationRoot, 'index.ts'), createTranslationIndexTemplate(selectedDefaultLocale));
69
60
  await writeIfNotExists(path.join(localesRoot, 'index.ts'), createLocalesIndexTemplate(locales));
70
-
71
61
  for (const locale of locales) {
72
62
  const localeDir = path.join(localesRoot, locale);
73
63
  await fs.mkdir(localeDir, { recursive: true });
74
64
  await writeIfNotExists(path.join(localeDir, 'index.ts'), createLocaleTemplate());
75
65
  }
76
-
77
66
  console.log(`✅ Translation manager created: ${translationRoot}`);
78
67
  }
@@ -2,6 +2,7 @@ import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import prompts from 'prompts';
4
4
  import { writeIfNotExists } from '../utils/fileUtils.js';
5
+ import { getLocalizationPath, getSharedState } from '../utils/sharedFoundation.js';
5
6
 
6
7
  const parseLocales = (rawLocales: string): string[] => {
7
8
  const parsed = String(rawLocales ?? '')
@@ -61,7 +62,8 @@ export default async function createTranslationManager(): Promise<void> {
61
62
 
62
63
  const selectedDefaultLocale = String(defaultLocale ?? locales[0] ?? 'en');
63
64
 
64
- const translationRoot = path.join(process.cwd(), 'src', 'core', 'translation');
65
+ const { sharedContext } = await getSharedState();
66
+ const translationRoot = getLocalizationPath(sharedContext.name);
65
67
  const localesRoot = path.join(translationRoot, 'locales');
66
68
  await fs.mkdir(localesRoot, { recursive: true });
67
69