@azure-net/cli 5.0.0-3 → 5.0.0

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 +29 -76
  27. package/src/generate/module/generatePresenter.ts +15 -10
  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 +5 -34
  52. package/src/scaffolds/createPresenterFactory.ts +5 -17
  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
@@ -2,10 +2,9 @@ import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import { loadUserConfig } from '../utils/loadConfig.js';
4
4
  import initAliases, { normalizeContexts } from './initAliases.js';
5
-
5
+ import { getSharedEssentialsPath } from '../utils/sharedFoundation.js';
6
6
  const ROOT = path.join(process.cwd(), 'src');
7
7
  const APP_ROOT = path.join(ROOT, 'app');
8
-
9
8
  const CONTEXT_DIRS = [
10
9
  'ui',
11
10
  'layers',
@@ -19,9 +18,22 @@ const CONTEXT_DIRS = [
19
18
  'layers/infrastructure/http/repositories',
20
19
  'layers/presentation'
21
20
  ];
22
-
23
- const SHARED_DIRS = ['core'];
24
-
21
+ const SHARED_ESSENTIALS_DIRS = [
22
+ '',
23
+ 'foundation',
24
+ 'foundation/abstracts',
25
+ 'foundation/constants',
26
+ 'foundation/constructs',
27
+ 'foundation/constructs/datasource',
28
+ 'foundation/constructs/presenter',
29
+ 'foundation/constructs/provider',
30
+ 'foundation/constructs/response',
31
+ 'foundation/constructs/schema',
32
+ 'foundation/constructs/schema/custom-rules',
33
+ 'foundation/helpers',
34
+ 'localization',
35
+ 'pipelines'
36
+ ];
25
37
  const ensureDir = async (dirPath) => {
26
38
  try {
27
39
  await fs.mkdir(dirPath, { recursive: true });
@@ -29,7 +41,6 @@ const ensureDir = async (dirPath) => {
29
41
  console.warn(`⚠️ Failed to create directory: ${dirPath}`, error);
30
42
  }
31
43
  };
32
-
33
44
  const ensureFile = async (filePath, content) => {
34
45
  try {
35
46
  await fs.access(filePath);
@@ -37,7 +48,6 @@ const ensureFile = async (filePath, content) => {
37
48
  } catch {
38
49
  // File is missing
39
50
  }
40
-
41
51
  try {
42
52
  await fs.mkdir(path.dirname(filePath), { recursive: true });
43
53
  await fs.writeFile(filePath, content, 'utf-8');
@@ -45,20 +55,17 @@ const ensureFile = async (filePath, content) => {
45
55
  console.warn(`⚠️ Failed to create file: ${filePath}`, error);
46
56
  }
47
57
  };
48
-
49
58
  const toPascalCase = (value) =>
50
59
  value
51
60
  .split(/[-_\s]+/)
52
61
  .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
53
62
  .join('');
54
-
55
63
  const createInfrastructureProvider = (contextName) => `import { createBoundaryProvider } from '@azure-net/kit';
56
64
 
57
65
  export const ${contextName}InfrastructureProvider = createBoundaryProvider('${contextName}InfrastructureProvider', {
58
66
  \tregister: () => ({})
59
67
  });
60
68
  `;
61
-
62
69
  const createApplicationProvider = (contextName) => `import { createBoundaryProvider } from '@azure-net/kit';
63
70
  import { ${contextName}InfrastructureProvider } from '../../infrastructure/providers';
64
71
 
@@ -67,7 +74,6 @@ export const ${contextName}ApplicationProvider = createBoundaryProvider('${conte
67
74
  \tregister: () => ({})
68
75
  });
69
76
  `;
70
-
71
77
  const printContextsError = () => {
72
78
  console.error('❌ Cannot generate folders structure: `contexts` is missing or empty in azure-net.config.ts/js');
73
79
  console.error('Add contexts first, for example:');
@@ -77,13 +83,32 @@ const printContextsError = () => {
77
83
  console.error("\t// contexts: [{ name: 'web', alias: '$web' }, { name: 'admin', alias: '$admin' }]");
78
84
  console.error('};');
79
85
  };
80
-
86
+ const printSharedAliasError = () => {
87
+ console.error('❌ Cannot generate folders structure: `sharedAlias` is missing in azure-net.config.ts/js');
88
+ console.error('Add shared context and alias first, for example:');
89
+ console.error('export default {');
90
+ console.error("\tsharedAlias: '$shared-kernel',");
91
+ console.error("\tcontexts: [{ name: 'shared-kernel', alias: '$shared-kernel' }, 'public']");
92
+ console.error('};');
93
+ };
94
+ const ensureSharedEssentialsStructure = async (contexts, sharedAlias) => {
95
+ const normalizedSharedAlias = sharedAlias.startsWith('$') ? sharedAlias : `$${sharedAlias}`;
96
+ const sharedContext = contexts.find((context) => context.alias === normalizedSharedAlias);
97
+ if (!sharedContext) {
98
+ console.error(`❌ sharedAlias "${normalizedSharedAlias}" does not point to any configured context.`);
99
+ return false;
100
+ }
101
+ const essentialsRoot = getSharedEssentialsPath(sharedContext.name);
102
+ for (const dir of SHARED_ESSENTIALS_DIRS) {
103
+ await ensureDir(path.join(essentialsRoot, dir));
104
+ }
105
+ return true;
106
+ };
81
107
  const ensureContextStructure = async (context) => {
82
108
  const contextRoot = path.join(APP_ROOT, context.name);
83
109
  for (const dir of CONTEXT_DIRS) {
84
110
  await ensureDir(path.join(contextRoot, dir));
85
111
  }
86
-
87
112
  const contextName = toPascalCase(context.name);
88
113
  const infraProviderPath = path.join(contextRoot, 'layers', 'infrastructure', 'providers', 'InfrastructureProvider.ts');
89
114
  const infraProviderIndex = path.join(contextRoot, 'layers', 'infrastructure', 'providers', 'index.ts');
@@ -91,7 +116,6 @@ const ensureContextStructure = async (context) => {
91
116
  const appProviderIndex = path.join(contextRoot, 'layers', 'application', 'providers', 'index.ts');
92
117
  const repositoriesIndex = path.join(contextRoot, 'layers', 'infrastructure', 'http', 'repositories', 'index.ts');
93
118
  const useCasesIndex = path.join(contextRoot, 'layers', 'application', 'use-cases', 'index.ts');
94
-
95
119
  await ensureFile(infraProviderPath, createInfrastructureProvider(contextName));
96
120
  await ensureFile(infraProviderIndex, `export * from './InfrastructureProvider';\n`);
97
121
  await ensureFile(appProviderPath, createApplicationProvider(contextName));
@@ -99,24 +123,27 @@ const ensureContextStructure = async (context) => {
99
123
  await ensureFile(repositoriesIndex, '');
100
124
  await ensureFile(useCasesIndex, '');
101
125
  };
102
-
103
126
  export default async function initStructure() {
104
127
  const config = await loadUserConfig();
105
128
  const contexts = normalizeContexts(config.contexts);
106
-
107
129
  if (!contexts.length) {
108
130
  printContextsError();
109
131
  return;
110
132
  }
111
-
112
- for (const sharedDir of SHARED_DIRS) {
113
- await ensureDir(path.join(ROOT, sharedDir));
133
+ const sharedAlias = String(config.sharedAlias ?? '').trim();
134
+ if (!sharedAlias.length) {
135
+ printSharedAliasError();
136
+ process.exitCode = 1;
137
+ return;
114
138
  }
115
-
116
139
  for (const context of contexts) {
117
140
  await ensureContextStructure(context);
118
141
  }
119
-
142
+ const sharedCreated = await ensureSharedEssentialsStructure(contexts, sharedAlias);
143
+ if (!sharedCreated) {
144
+ process.exitCode = 1;
145
+ return;
146
+ }
120
147
  await initAliases();
121
148
  console.log('✅ Folders structure initialized');
122
149
  }
@@ -2,6 +2,7 @@ import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import { loadUserConfig } from '../utils/loadConfig.js';
4
4
  import initAliases, { normalizeContexts } from './initAliases.js';
5
+ import { getSharedEssentialsPath } from '../utils/sharedFoundation.js';
5
6
 
6
7
  type ContextConfig = { name: string; alias: string };
7
8
 
@@ -22,7 +23,19 @@ const CONTEXT_DIRS = [
22
23
  'layers/presentation'
23
24
  ];
24
25
 
25
- const SHARED_DIRS = ['core'];
26
+ const SHARED_ESSENTIALS_DIRS = [
27
+ '',
28
+ 'foundation',
29
+ 'foundation/constructs',
30
+ 'foundation/constructs/datasource',
31
+ 'foundation/constructs/presenter',
32
+ 'foundation/constructs/provider',
33
+ 'foundation/constructs/response',
34
+ 'foundation/constructs/schema',
35
+ 'foundation/constructs/schema/custom-rules',
36
+ 'localization',
37
+ 'pipelines'
38
+ ];
26
39
 
27
40
  const ensureDir = async (dirPath: string): Promise<void> => {
28
41
  try {
@@ -80,6 +93,32 @@ const printContextsError = () => {
80
93
  console.error('};');
81
94
  };
82
95
 
96
+ const printSharedAliasError = () => {
97
+ console.error('❌ Cannot generate folders structure: `sharedAlias` is missing in azure-net.config.ts/js');
98
+ console.error('Add shared context and alias first, for example:');
99
+ console.error('export default {');
100
+ console.error("\tsharedAlias: '$shared-kernel',");
101
+ console.error("\tcontexts: [{ name: 'shared-kernel', alias: '$shared-kernel' }, 'public']");
102
+ console.error('};');
103
+ };
104
+
105
+ const ensureSharedEssentialsStructure = async (contexts: ContextConfig[], sharedAlias: string): Promise<boolean> => {
106
+ const normalizedSharedAlias = sharedAlias.startsWith('$') ? sharedAlias : `$${sharedAlias}`;
107
+ const sharedContext = contexts.find((context) => context.alias === normalizedSharedAlias);
108
+
109
+ if (!sharedContext) {
110
+ console.error(`❌ sharedAlias "${normalizedSharedAlias}" does not point to any configured context.`);
111
+ return false;
112
+ }
113
+
114
+ const essentialsRoot = getSharedEssentialsPath(sharedContext.name);
115
+ for (const dir of SHARED_ESSENTIALS_DIRS) {
116
+ await ensureDir(path.join(essentialsRoot, dir));
117
+ }
118
+
119
+ return true;
120
+ };
121
+
83
122
  const ensureContextStructure = async (context: ContextConfig): Promise<void> => {
84
123
  const contextRoot = path.join(APP_ROOT, context.name);
85
124
  for (const dir of CONTEXT_DIRS) {
@@ -111,14 +150,23 @@ export default async function initStructure(): Promise<void> {
111
150
  return;
112
151
  }
113
152
 
114
- for (const sharedDir of SHARED_DIRS) {
115
- await ensureDir(path.join(ROOT, sharedDir));
153
+ const sharedAlias = String(config.sharedAlias ?? '').trim();
154
+ if (!sharedAlias.length) {
155
+ printSharedAliasError();
156
+ process.exitCode = 1;
157
+ return;
116
158
  }
117
159
 
118
160
  for (const context of contexts) {
119
161
  await ensureContextStructure(context);
120
162
  }
121
163
 
164
+ const sharedCreated = await ensureSharedEssentialsStructure(contexts, sharedAlias);
165
+ if (!sharedCreated) {
166
+ process.exitCode = 1;
167
+ return;
168
+ }
169
+
122
170
  await initAliases();
123
171
  console.log('✅ Folders structure initialized');
124
172
  }
@@ -13,7 +13,6 @@ import {
13
13
  createResponse,
14
14
  createTranslationManager
15
15
  } from '../scaffolds/index.js';
16
-
17
16
  const printContextsError = () => {
18
17
  console.error('❌ Cannot run "install fresh": `contexts` is missing or empty in azure-net.config.ts/js');
19
18
  console.error('Add contexts first, for example:');
@@ -23,7 +22,6 @@ const printContextsError = () => {
23
22
  console.error("\t// contexts: [{ name: 'web', alias: '$web' }, { name: 'admin', alias: '$admin' }]");
24
23
  console.error('};');
25
24
  };
26
-
27
25
  const askConfirm = async (message) => {
28
26
  const result = await prompts({
29
27
  type: 'confirm',
@@ -31,14 +29,11 @@ const askConfirm = async (message) => {
31
29
  message,
32
30
  initial: true
33
31
  });
34
-
35
32
  return Boolean(result.confirmed);
36
33
  };
37
-
38
34
  const runOptionalStep = async (question, action) => {
39
35
  const shouldRun = await askConfirm(question);
40
36
  if (!shouldRun) return;
41
-
42
37
  try {
43
38
  await action();
44
39
  } catch (error) {
@@ -46,48 +41,37 @@ const runOptionalStep = async (question, action) => {
46
41
  console.warn(error);
47
42
  }
48
43
  };
49
-
50
44
  export default async function installFresh() {
51
45
  const config = await loadUserConfig();
52
46
  const contexts = normalizeContexts(config.contexts);
53
-
54
47
  if (!contexts.length) {
55
48
  printContextsError();
56
49
  process.exitCode = 1;
57
50
  return;
58
51
  }
59
-
60
52
  await initStructure();
61
53
  await initEdges();
62
54
  await createProgram();
63
-
64
55
  await runOptionalStep('Add commit tools (lint/commit conventions)?', async () => {
65
56
  await addLint();
66
57
  });
67
-
68
58
  await runOptionalStep('Create schema factory?', async () => {
69
59
  await createCoreSchema();
70
60
  });
71
-
72
61
  await runOptionalStep('Create presenter factory?', async () => {
73
62
  await createPresenterFactory();
74
63
  });
75
-
76
64
  await runOptionalStep('Create API response?', async () => {
77
65
  await createResponse();
78
66
  });
79
-
80
67
  await runOptionalStep('Create datasource?', async () => {
81
68
  await createDatasource();
82
69
  });
83
-
84
70
  await runOptionalStep('Create datasource provider?', async () => {
85
71
  await createDatasourceProvider();
86
72
  });
87
-
88
73
  await runOptionalStep('Create translation manager (i18n)?', async () => {
89
74
  await createTranslationManager();
90
75
  });
91
-
92
76
  console.log('✅ install fresh completed');
93
77
  }
@@ -1,9 +1,7 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { execSync } from 'node:child_process';
4
-
5
4
  const dependencies = ['@commitlint/cli', 'semantic-release', '@semantic-release/git', 'git-cz', 'husky', 'commitizen', 'env-cmd'];
6
-
7
5
  const commitlintConfig = `export default {
8
6
  rules: {
9
7
  'body-leading-blank': [2, 'always'],
@@ -17,7 +15,6 @@ const commitlintConfig = `export default {
17
15
  }
18
16
  };
19
17
  `;
20
-
21
18
  const releaseConfig = `export default {
22
19
  branches: ['main', 'dev'],
23
20
  dryRun: false,
@@ -44,7 +41,6 @@ const releaseConfig = `export default {
44
41
  ]
45
42
  };
46
43
  `;
47
-
48
44
  const prettierConfig = `{
49
45
  "useTabs": true,
50
46
  "singleQuote": true,
@@ -63,7 +59,6 @@ const prettierConfig = `{
63
59
  ]
64
60
  }
65
61
  `;
66
-
67
62
  const resolveInstallCommand = (manager) => {
68
63
  const deps = dependencies.join(' ');
69
64
  switch (manager) {
@@ -75,11 +70,8 @@ const resolveInstallCommand = (manager) => {
75
70
  return `yarn add -D ${deps}`;
76
71
  case 'bun':
77
72
  return `bun add -d ${deps}`;
78
- default:
79
- return `pnpm add -D ${deps}`;
80
73
  }
81
74
  };
82
-
83
75
  const resolveRunScriptCommand = (manager, script) => {
84
76
  switch (manager) {
85
77
  case 'pnpm':
@@ -90,11 +82,8 @@ const resolveRunScriptCommand = (manager, script) => {
90
82
  return `yarn ${script}`;
91
83
  case 'bun':
92
84
  return `bun run ${script}`;
93
- default:
94
- return `pnpm ${script}`;
95
85
  }
96
86
  };
97
-
98
87
  const resolveHuskyCommand = (manager) => {
99
88
  switch (manager) {
100
89
  case 'pnpm':
@@ -105,11 +94,8 @@ const resolveHuskyCommand = (manager) => {
105
94
  return 'yarn husky';
106
95
  case 'bun':
107
96
  return 'bunx husky';
108
- default:
109
- return 'pnpm exec husky';
110
97
  }
111
98
  };
112
-
113
99
  const detectPackageManager = (cwd) => {
114
100
  if (fs.existsSync(path.join(cwd, 'bun.lock')) || fs.existsSync(path.join(cwd, 'bun.lockb'))) return 'bun';
115
101
  if (fs.existsSync(path.join(cwd, 'pnpm-lock.yaml'))) return 'pnpm';
@@ -117,12 +103,10 @@ const detectPackageManager = (cwd) => {
117
103
  if (fs.existsSync(path.join(cwd, 'package-lock.json'))) return 'npm';
118
104
  return undefined;
119
105
  };
120
-
121
106
  const parseConfigState = (cwd) => {
122
107
  const tsPath = path.join(cwd, 'azure-net.config.ts');
123
108
  const jsPath = path.join(cwd, 'azure-net.config.js');
124
109
  const configPath = fs.existsSync(tsPath) ? tsPath : fs.existsSync(jsPath) ? jsPath : null;
125
-
126
110
  if (!configPath) {
127
111
  return {
128
112
  configPath: null,
@@ -131,77 +115,66 @@ const parseConfigState = (cwd) => {
131
115
  validPackageManager: null
132
116
  };
133
117
  }
134
-
135
118
  const content = fs.readFileSync(configPath, 'utf-8');
136
119
  const hasPackageManagerKey = /packageManager\s*:/.test(content);
137
120
  const managerMatch = content.match(/packageManager\s*:\s*['"`](bun|pnpm|npm|yarn)['"`]/);
138
- const validPackageManager = managerMatch?.[1] ?? null;
139
-
121
+ const validPackageManager = managerMatch?.[1];
140
122
  return {
141
123
  configPath,
142
124
  content,
143
125
  hasPackageManagerKey,
144
- validPackageManager
126
+ validPackageManager: validPackageManager ?? null
145
127
  };
146
128
  };
147
-
148
129
  const upsertPackageManagerInConfig = (content, manager) => {
149
130
  const packageManagerEntry = `packageManager: '${manager}'`;
150
131
  const hasExportDefaultObject = /export\s+default\s*\{[\s\S]*\}\s*;?/.test(content);
151
-
152
132
  if (!hasExportDefaultObject) {
153
133
  return `export default {\n\t${packageManagerEntry}\n};\n`;
154
134
  }
155
-
156
135
  if (/packageManager\s*:/.test(content)) {
157
136
  return content.replace(/packageManager\s*:\s*['"`][^'"`]+['"`]/, packageManagerEntry);
158
137
  }
159
-
160
138
  return content.replace(/export\s+default\s*\{([\s\S]*?)\}\s*;?/, (_full, body) => {
161
139
  const trimmedRight = body.replace(/\s*$/, '');
162
140
  if (!trimmedRight.length) {
163
141
  return `export default {\n\t${packageManagerEntry}\n};`;
164
142
  }
165
-
166
143
  const withComma = trimmedRight.endsWith(',') ? trimmedRight : `${trimmedRight},`;
167
144
  return `export default {${withComma}\n\t${packageManagerEntry}\n};`;
168
145
  });
169
146
  };
170
-
171
147
  const localOnlyPrepareScript = `node -e "const local = !process.env.CI && process.env.NODE_ENV !== 'production' && !process.env.DOCKER && !process.env.CONTAINER; process.exit(local ? 1 : 0)" || (husky && svelte-kit sync)`;
172
-
173
148
  const selectPackageManager = async (cwd, preset) => {
174
149
  if (preset) return preset;
175
150
  const { default: prompts } = await import('prompts');
176
-
177
- const order = ['bun', 'pnpm', 'npm', 'yarn'];
178
151
  const detected = detectPackageManager(cwd);
179
152
  const response = await prompts({
180
153
  type: 'select',
181
154
  name: 'manager',
182
155
  message: 'Choose your package manager:',
183
- choices: order.map((item) => ({ title: item, value: item })),
184
- initial: detected ? order.indexOf(detected) : 0
156
+ choices: [
157
+ { title: 'bun', value: 'bun' },
158
+ { title: 'pnpm', value: 'pnpm' },
159
+ { title: 'npm', value: 'npm' },
160
+ { title: 'yarn', value: 'yarn' }
161
+ ],
162
+ initial: detected ? ['bun', 'pnpm', 'npm', 'yarn'].indexOf(detected) : 0
185
163
  });
186
-
187
164
  if (!response.manager) {
188
165
  throw new Error('Package manager is required');
189
166
  }
190
167
  return response.manager;
191
168
  };
192
-
193
169
  export default async function addLint(options = {}) {
194
170
  const cwd = process.cwd();
195
171
  const pkgPath = path.join(cwd, 'package.json');
196
-
197
172
  if (!fs.existsSync(pkgPath)) {
198
173
  console.error('❌ package.json not found in this directory');
199
174
  process.exit(1);
200
175
  }
201
-
202
176
  const configState = parseConfigState(cwd);
203
177
  const manager = configState.validPackageManager ?? (await selectPackageManager(cwd, options.manager));
204
-
205
178
  if (!configState.configPath) {
206
179
  const newConfigPath = path.join(cwd, 'azure-net.config.ts');
207
180
  fs.writeFileSync(newConfigPath, `export default {\n\tpackageManager: '${manager}'\n};\n`);
@@ -209,49 +182,41 @@ export default async function addLint(options = {}) {
209
182
  const nextConfig = upsertPackageManagerInConfig(configState.content ?? '', manager);
210
183
  fs.writeFileSync(configState.configPath, nextConfig);
211
184
  }
212
-
213
185
  const installCommand = resolveInstallCommand(manager);
214
186
  const runFormatCommand = resolveRunScriptCommand(manager, 'format');
215
187
  const preCommitScript = `${resolveRunScriptCommand(manager, 'lint')} && ${resolveRunScriptCommand(manager, 'check')}`;
216
188
  const commitScript = `${resolveRunScriptCommand(manager, 'format')} && git add . && git-cz && git push`;
217
189
  const releaseScript = `${resolveRunScriptCommand(manager, 'commit')} && ${resolveRunScriptCommand(manager, 'semantic-release')}`;
218
-
219
190
  console.log(`📦 Installing packages with ${manager}...`);
220
191
  execSync(installCommand, { stdio: 'inherit' });
221
-
222
192
  console.log('📁 Updating package.json...');
223
193
  const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
224
194
  pkg.scripts = {
225
- ...(pkg.scripts || {}),
195
+ ...(pkg.scripts ?? {}),
226
196
  precommit: preCommitScript,
227
197
  prepare: localOnlyPrepareScript,
228
198
  'semantic-release': 'env-cmd semantic-release',
229
199
  commit: commitScript,
230
200
  release: releaseScript
231
201
  };
232
-
233
- pkg.config = pkg.config || {};
202
+ pkg.config = pkg.config ?? {};
234
203
  pkg.config.commitizen = {
235
204
  path: 'git-cz'
236
205
  };
237
-
238
206
  fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 4));
239
207
  fs.writeFileSync(path.join(cwd, 'commitlint.config.ts'), commitlintConfig);
240
208
  fs.writeFileSync(path.join(cwd, 'release.config.ts'), releaseConfig);
241
209
  fs.writeFileSync(path.join(cwd, '.prettierrc'), prettierConfig);
242
-
243
210
  console.log('🔧 Initializing Husky...');
244
211
  try {
245
212
  execSync(resolveHuskyCommand(manager), { stdio: 'inherit' });
246
213
  } catch {
247
214
  console.warn('⚠️ Husky initialization skipped (command failed in current environment).');
248
215
  }
249
-
250
216
  try {
251
217
  execSync(runFormatCommand, { stdio: 'inherit' });
252
218
  } catch {
253
219
  console.warn('⚠️ Format script execution skipped (script may be missing).');
254
220
  }
255
-
256
221
  console.log(`✅ Linting and release setup completed! Added prepare script: ${localOnlyPrepareScript}`);
257
222
  }
@@ -4,7 +4,7 @@ import path from 'node:path';
4
4
  import prompts from 'prompts';
5
5
  import { writeIfNotExists, updateIndexTs } from '../utils/fileUtils.js';
6
6
  import { toPascalCase } from '../utils/contextUtils.js';
7
-
7
+ import { getFoundationConstructPath, getSharedState } from '../utils/sharedFoundation.js';
8
8
  const resolvePresetImportName = (preset) => {
9
9
  switch (preset) {
10
10
  case 'ru':
@@ -13,11 +13,8 @@ const resolvePresetImportName = (preset) => {
13
13
  return 'validationMessagesEn';
14
14
  case 'i18n':
15
15
  return 'validationMessagesI18n';
16
- default:
17
- return 'validationMessagesI18n';
18
16
  }
19
17
  };
20
-
21
18
  const createSchemaFactoryTemplate = (
22
19
  factoryName,
23
20
  messagesImportName
@@ -25,36 +22,27 @@ const createSchemaFactoryTemplate = (
25
22
 
26
23
  export const ${factoryName} = createSchemaFactory(createRules(${messagesImportName}));
27
24
  `;
28
-
29
25
  const resolveConfigFile = (cwd) => {
30
26
  const tsPath = path.join(cwd, 'azure-net.config.ts');
31
27
  const jsPath = path.join(cwd, 'azure-net.config.js');
32
-
33
28
  if (fsSync.existsSync(tsPath)) {
34
29
  return { filepath: tsPath, type: 'ts', exists: true, content: fsSync.readFileSync(tsPath, 'utf-8') };
35
30
  }
36
31
  if (fsSync.existsSync(jsPath)) {
37
32
  return { filepath: jsPath, type: 'js', exists: true, content: fsSync.readFileSync(jsPath, 'utf-8') };
38
33
  }
39
-
40
34
  return { filepath: tsPath, type: 'ts', exists: false, content: '' };
41
35
  };
42
-
43
36
  const buildDefaultSchemaFactoryConfigEntry = (factoryName) => {
44
37
  return `defaultSchemaFactory: '${factoryName}'`;
45
38
  };
46
-
47
39
  const upsertDefaultSchemaFactoryConfig = (content, factoryName) => {
48
40
  const hasExportDefaultObject = /export\s+default\s*\{[\s\S]*\}\s*;?/.test(content);
49
41
  const defaultFactoryEntry = buildDefaultSchemaFactoryConfigEntry(factoryName);
50
- const coreAliasEntry = `coreAlias: '$core'`;
51
-
52
42
  if (!hasExportDefaultObject) {
53
- return `export default {\n\t${coreAliasEntry},\n\t${defaultFactoryEntry}\n};\n`;
43
+ return `export default {\n\t${defaultFactoryEntry}\n};\n`;
54
44
  }
55
-
56
45
  let nextContent = content;
57
-
58
46
  if (/defaultSchemaFactory\s*:/.test(nextContent)) {
59
47
  nextContent = nextContent.replace(/defaultSchemaFactory\s*:\s*(\{[\s\S]*?\n\s*\}|['"`][^'"`]+['"`])/m, defaultFactoryEntry);
60
48
  } else if (/defaultSchema\s*:/.test(nextContent)) {
@@ -65,27 +53,12 @@ const upsertDefaultSchemaFactoryConfig = (content, factoryName) => {
65
53
  if (!trimmedRight.length) {
66
54
  return `export default {\n\t${defaultFactoryEntry}\n};`;
67
55
  }
68
-
69
56
  const withComma = trimmedRight.endsWith(',') ? trimmedRight : `${trimmedRight},`;
70
57
  return `export default {${withComma}\n\t${defaultFactoryEntry}\n};`;
71
58
  });
72
59
  }
73
-
74
- if (/coreAlias\s*:/.test(nextContent)) {
75
- return nextContent.replace(/coreAlias\s*:\s*['"`][^'"`]+['"`]/, coreAliasEntry);
76
- }
77
-
78
- return nextContent.replace(/export\s+default\s*\{([\s\S]*)\}\s*;?/, (_full, body) => {
79
- const trimmedRight = body.replace(/\s*$/, '');
80
- if (!trimmedRight.length) {
81
- return `export default {\n\t${coreAliasEntry}\n};`;
82
- }
83
-
84
- const withComma = trimmedRight.endsWith(',') ? trimmedRight : `${trimmedRight},`;
85
- return `export default {${withComma}\n\t${coreAliasEntry}\n};`;
86
- });
60
+ return nextContent;
87
61
  };
88
-
89
62
  export default async function createCoreSchema() {
90
63
  const { schemaFactoryNameRaw } = await prompts({
91
64
  type: 'text',
@@ -93,9 +66,7 @@ export default async function createCoreSchema() {
93
66
  message: 'Schema factory name:',
94
67
  initial: 'Schema'
95
68
  });
96
-
97
69
  const schemaFactoryName = toPascalCase(String(schemaFactoryNameRaw ?? 'Schema')) || 'Schema';
98
-
99
70
  const { preset } = await prompts({
100
71
  type: 'select',
101
72
  name: 'preset',
@@ -107,33 +78,28 @@ export default async function createCoreSchema() {
107
78
  ],
108
79
  initial: 2
109
80
  });
110
-
111
81
  const selectedPreset = preset ?? 'i18n';
112
82
  const messagesImportName = resolvePresetImportName(selectedPreset);
113
- const coreSchemaPath = path.join(process.cwd(), 'src', 'core', 'schema');
83
+ const { sharedContext } = await getSharedState();
84
+ const coreSchemaPath = getFoundationConstructPath(sharedContext.name, 'schema');
114
85
  const customRulesPath = path.join(coreSchemaPath, 'custom-rules');
115
86
  const filePath = path.join(coreSchemaPath, `${schemaFactoryName}.ts`);
116
-
117
87
  await fs.mkdir(coreSchemaPath, { recursive: true });
118
88
  await fs.mkdir(customRulesPath, { recursive: true });
119
-
120
89
  const created = await writeIfNotExists(filePath, createSchemaFactoryTemplate(schemaFactoryName, messagesImportName));
121
90
  if (!created) {
122
91
  console.log(`⚠️ Schema factory "${schemaFactoryName}" already exists. File was not overwritten.`);
123
92
  } else {
124
93
  await updateIndexTs(coreSchemaPath);
125
- console.log(`✅ Core schema factory created: ${filePath}`);
94
+ console.log(`✅ Shared schema factory created: ${filePath}`);
126
95
  }
127
-
128
96
  const { useAsDefault } = await prompts({
129
97
  type: 'confirm',
130
98
  name: 'useAsDefault',
131
99
  message: 'Use this schema factory as default for the project?',
132
100
  initial: true
133
101
  });
134
-
135
102
  if (!useAsDefault) return;
136
-
137
103
  const config = resolveConfigFile(process.cwd());
138
104
  const nextContent = upsertDefaultSchemaFactoryConfig(config.content, schemaFactoryName);
139
105
  await fs.writeFile(config.filepath, nextContent, 'utf-8');