@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,7 +2,6 @@ import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import prompts from 'prompts';
4
4
  import { getConfigState, resolveContextAlias, selectContext } from './repositoryModuleShared.js';
5
-
6
5
  const listDirectories = async (targetPath) => {
7
6
  try {
8
7
  const items = await fs.readdir(targetPath, { withFileTypes: true });
@@ -11,7 +10,6 @@ const listDirectories = async (targetPath) => {
11
10
  return [];
12
11
  }
13
12
  };
14
-
15
13
  const listSchemaFiles = async (targetPath) => {
16
14
  try {
17
15
  const files = await fs.readdir(targetPath);
@@ -20,24 +18,18 @@ const listSchemaFiles = async (targetPath) => {
20
18
  return [];
21
19
  }
22
20
  };
23
-
24
21
  const resolveAliasMap = async () => {
25
- const { contexts, coreAlias } = await getConfigState();
22
+ const { contexts } = await getConfigState();
26
23
  const map = new Map();
27
- map.set(coreAlias, path.join(process.cwd(), 'src', 'core'));
28
-
29
24
  for (const context of contexts) {
30
25
  const alias = resolveContextAlias(contexts, context.name);
31
26
  map.set(alias, path.join(process.cwd(), 'src', 'app', context.name));
32
27
  }
33
-
34
28
  return map;
35
29
  };
36
-
37
30
  const resolveImportToFile = async (fromFile, importPath, aliasMap) => {
38
31
  const rawImport = String(importPath ?? '').trim();
39
32
  if (!rawImport.length) return null;
40
-
41
33
  let absolute = '';
42
34
  if (rawImport.startsWith('.')) {
43
35
  absolute = path.resolve(path.dirname(fromFile), rawImport);
@@ -47,7 +39,6 @@ const resolveImportToFile = async (fromFile, importPath, aliasMap) => {
47
39
  const suffix = rawImport === alias ? '' : rawImport.slice(alias.length + 1);
48
40
  absolute = path.join(aliasMap.get(alias), suffix);
49
41
  }
50
-
51
42
  const tsCandidate = absolute.endsWith('.ts') ? absolute : `${absolute}.ts`;
52
43
  try {
53
44
  await fs.access(tsCandidate);
@@ -62,36 +53,34 @@ const resolveImportToFile = async (fromFile, importPath, aliasMap) => {
62
53
  }
63
54
  }
64
55
  };
65
-
66
56
  const extractSchemaTypeName = (content) => {
67
57
  const typeMatch = content.match(/=\s*[A-Za-z0-9_]+<\s*([^>]+?)\s*>\s*\(\)/m);
68
58
  if (!typeMatch) return null;
69
59
  return String(typeMatch[1]).trim();
70
60
  };
71
-
72
61
  const findTypeImportPath = (content, typeName) => {
73
62
  const importRegex = /import\s+type\s+\{([^}]+)\}\s+from\s+['"]([^'"]+)['"]/g;
74
63
  let match;
75
64
  while ((match = importRegex.exec(content)) !== null) {
76
- const imported = match[1]
65
+ const importedList = match[1];
66
+ const sourcePath = match[2];
67
+ if (!importedList || !sourcePath) continue;
68
+ const imported = importedList
77
69
  .split(',')
78
70
  .map((item) => item.trim())
79
71
  .filter(Boolean);
80
72
  if (imported.includes(typeName)) {
81
- return match[2];
73
+ return sourcePath;
82
74
  }
83
75
  }
84
76
  return null;
85
77
  };
86
-
87
78
  const extractInterfaceBody = (content, interfaceName) => {
88
79
  const declarationRegex = new RegExp(`export\\s+interface\\s+${interfaceName}\\s*\\{`);
89
80
  const declarationMatch = content.match(declarationRegex);
90
81
  if (!declarationMatch || declarationMatch.index === undefined) return null;
91
-
92
82
  const openBraceIndex = content.indexOf('{', declarationMatch.index);
93
83
  if (openBraceIndex === -1) return null;
94
-
95
84
  let depth = 0;
96
85
  let closeBraceIndex = -1;
97
86
  for (let index = openBraceIndex; index < content.length; index += 1) {
@@ -105,11 +94,9 @@ const extractInterfaceBody = (content, interfaceName) => {
105
94
  }
106
95
  }
107
96
  }
108
-
109
97
  if (closeBraceIndex === -1) return null;
110
98
  return content.slice(openBraceIndex + 1, closeBraceIndex);
111
99
  };
112
-
113
100
  const resolveRelativeExportPath = async (fromFile, exportPath) => {
114
101
  const absolute = path.resolve(path.dirname(fromFile), exportPath);
115
102
  const tsCandidate = absolute.endsWith('.ts') ? absolute : `${absolute}.ts`;
@@ -126,38 +113,30 @@ const resolveRelativeExportPath = async (fromFile, exportPath) => {
126
113
  }
127
114
  }
128
115
  };
129
-
130
116
  const findInterfaceBodyByExportGraph = async (entryFilePath, interfaceName, visited = new Set()) => {
131
117
  const resolvedPath = path.resolve(entryFilePath);
132
118
  if (visited.has(resolvedPath)) return null;
133
119
  visited.add(resolvedPath);
134
-
135
120
  let content = '';
136
121
  try {
137
122
  content = await fs.readFile(resolvedPath, 'utf-8');
138
123
  } catch {
139
124
  return null;
140
125
  }
141
-
142
126
  const direct = extractInterfaceBody(content, interfaceName);
143
127
  if (direct) return direct;
144
-
145
- const exportRegex = /export\\s+(?:\\*|\\{[^}]+\\})\\s+from\\s+['\"]([^'\"]+)['\"]/g;
128
+ const exportRegex = /export\s+(?:\*|\{[^}]+\})\s+from\s+['"]([^'"]+)['"]/g;
146
129
  let match;
147
130
  while ((match = exportRegex.exec(content)) !== null) {
148
131
  const exportPath = match[1];
149
132
  if (!exportPath || !exportPath.startsWith('.')) continue;
150
- // eslint-disable-next-line no-await-in-loop
151
133
  const nextPath = await resolveRelativeExportPath(resolvedPath, exportPath);
152
134
  if (!nextPath) continue;
153
- // eslint-disable-next-line no-await-in-loop
154
135
  const nested = await findInterfaceBodyByExportGraph(nextPath, interfaceName, visited);
155
136
  if (nested) return nested;
156
137
  }
157
-
158
138
  return null;
159
139
  };
160
-
161
140
  const findInterfaceBodyByScan = async (rootDir, interfaceName) => {
162
141
  const queue = [rootDir];
163
142
  while (queue.length) {
@@ -169,7 +148,6 @@ const findInterfaceBodyByScan = async (rootDir, interfaceName) => {
169
148
  } catch {
170
149
  continue;
171
150
  }
172
-
173
151
  for (const entry of entries) {
174
152
  const absolute = path.join(current, entry.name);
175
153
  if (entry.isDirectory()) {
@@ -177,7 +155,6 @@ const findInterfaceBodyByScan = async (rootDir, interfaceName) => {
177
155
  continue;
178
156
  }
179
157
  if (!entry.isFile() || !entry.name.endsWith('.ts')) continue;
180
- // eslint-disable-next-line no-await-in-loop
181
158
  const content = await fs.readFile(absolute, 'utf-8');
182
159
  const body = extractInterfaceBody(content, interfaceName);
183
160
  if (body) return body;
@@ -185,17 +162,16 @@ const findInterfaceBodyByScan = async (rootDir, interfaceName) => {
185
162
  }
186
163
  return null;
187
164
  };
188
-
189
165
  const extractRuleKeys = (body) => {
190
166
  const keys = [];
191
167
  const keyRegex = /^\s*([A-Za-z_$][A-Za-z0-9_$]*)\s*:/gm;
192
168
  let match;
193
169
  while ((match = keyRegex.exec(body)) !== null) {
194
- keys.push(match[1]);
170
+ const key = match[1];
171
+ if (key) keys.push(key);
195
172
  }
196
173
  return Array.from(new Set(keys));
197
174
  };
198
-
199
175
  const extractInterfaceFields = (body) => {
200
176
  const fields = [];
201
177
  const fieldRegex = /^\s*(?:readonly\s+)?([A-Za-z_$][A-Za-z0-9_$]*)(\?)?\s*:\s*([^;]+);/gm;
@@ -211,53 +187,42 @@ const extractInterfaceFields = (body) => {
211
187
  type
212
188
  });
213
189
  }
214
-
215
190
  const unique = new Map();
216
191
  for (const field of fields) {
217
192
  if (!unique.has(field.name)) unique.set(field.name, field);
218
193
  }
219
194
  return Array.from(unique.values());
220
195
  };
221
-
222
196
  const buildRulesArray = (field) => {
223
197
  const ruleCalls = [];
224
198
  if (!field.optional) {
225
199
  ruleCalls.push('rules.required()');
226
200
  }
227
-
228
201
  if (field.type === 'string') {
229
202
  ruleCalls.push('rules.string()');
230
203
  } else if (field.type === 'number') {
231
204
  ruleCalls.push('rules.number()');
232
205
  }
233
-
234
206
  return `[${ruleCalls.join(', ')}]`;
235
207
  };
236
-
237
208
  const updateRulesObject = (schemaContent, fields) => {
238
209
  const rulesRegex = /\.rules\(\(rules\)\s*=>\s*\(\{([\s\S]*?)\}\)\)/m;
239
210
  const match = schemaContent.match(rulesRegex);
240
211
  if (!match) return null;
241
-
242
212
  const currentBody = match[1] ?? '';
243
213
  const existingKeys = new Set(extractRuleKeys(currentBody));
244
214
  const newLines = fields.filter((field) => !existingKeys.has(field.name)).map((field) => `\t\t${field.name}: ${buildRulesArray(field)},`);
245
-
246
215
  if (!newLines.length) return schemaContent;
247
-
248
216
  const trimmedBody = currentBody.trimEnd();
249
217
  const nextBody = trimmedBody.length ? `${trimmedBody}\n${newLines.join('\n')}\n\t` : `\n${newLines.join('\n')}\n\t`;
250
-
251
218
  return schemaContent.replace(rulesRegex, `.rules((rules) => ({${nextBody}}))`);
252
219
  };
253
-
254
220
  export default async function generateSchemaFromType() {
255
221
  const contextName = await selectContext('Select context for schema update:');
256
222
  if (!contextName) {
257
223
  process.exitCode = 1;
258
224
  return;
259
225
  }
260
-
261
226
  const presentationPath = path.join(process.cwd(), 'src', 'app', contextName, 'layers', 'presentation');
262
227
  const presenterFolders = await listDirectories(presentationPath);
263
228
  if (!presenterFolders.length) {
@@ -265,7 +230,6 @@ export default async function generateSchemaFromType() {
265
230
  process.exitCode = 1;
266
231
  return;
267
232
  }
268
-
269
233
  const { presenterFolder } = await prompts({
270
234
  type: 'select',
271
235
  name: 'presenterFolder',
@@ -273,12 +237,10 @@ export default async function generateSchemaFromType() {
273
237
  choices: presenterFolders.map((item) => ({ title: item, value: item })),
274
238
  initial: 0
275
239
  });
276
-
277
240
  if (!presenterFolder) {
278
241
  process.exitCode = 1;
279
242
  return;
280
243
  }
281
-
282
244
  const schemaFolderPath = path.join(presentationPath, String(presenterFolder), 'schema');
283
245
  const schemas = await listSchemaFiles(schemaFolderPath);
284
246
  if (!schemas.length) {
@@ -286,7 +248,6 @@ export default async function generateSchemaFromType() {
286
248
  process.exitCode = 1;
287
249
  return;
288
250
  }
289
-
290
251
  const { schemaFile } = await prompts({
291
252
  type: 'select',
292
253
  name: 'schemaFile',
@@ -294,29 +255,24 @@ export default async function generateSchemaFromType() {
294
255
  choices: schemas.map((item) => ({ title: item, value: item })),
295
256
  initial: 0
296
257
  });
297
-
298
258
  if (!schemaFile) {
299
259
  process.exitCode = 1;
300
260
  return;
301
261
  }
302
-
303
262
  const schemaPath = path.join(schemaFolderPath, String(schemaFile));
304
263
  const schemaContent = await fs.readFile(schemaPath, 'utf-8');
305
-
306
264
  const typeName = extractSchemaTypeName(schemaContent);
307
265
  if (!typeName) {
308
266
  console.error('❌ Unable to resolve schema generic type.');
309
267
  process.exitCode = 1;
310
268
  return;
311
269
  }
312
-
313
270
  const importPath = findTypeImportPath(schemaContent, typeName);
314
271
  if (!importPath) {
315
272
  console.error(`❌ Unable to find import for type "${typeName}".`);
316
273
  process.exitCode = 1;
317
274
  return;
318
275
  }
319
-
320
276
  const aliasMap = await resolveAliasMap();
321
277
  const typeFilePath = await resolveImportToFile(schemaPath, importPath, aliasMap);
322
278
  if (!typeFilePath) {
@@ -324,7 +280,6 @@ export default async function generateSchemaFromType() {
324
280
  process.exitCode = 1;
325
281
  return;
326
282
  }
327
-
328
283
  let interfaceBody = await findInterfaceBodyByExportGraph(typeFilePath, typeName);
329
284
  if (!interfaceBody) {
330
285
  interfaceBody = await findInterfaceBodyByScan(path.dirname(typeFilePath), typeName);
@@ -334,25 +289,21 @@ export default async function generateSchemaFromType() {
334
289
  process.exitCode = 1;
335
290
  return;
336
291
  }
337
-
338
292
  const interfaceFields = extractInterfaceFields(interfaceBody);
339
293
  if (!interfaceFields.length) {
340
294
  console.log('ℹ️ Interface has no explicit keys to transfer into rules.');
341
295
  return;
342
296
  }
343
-
344
297
  const updatedSchemaContent = updateRulesObject(schemaContent, interfaceFields);
345
298
  if (!updatedSchemaContent) {
346
299
  console.error('❌ Could not locate `.rules((rules) => ({}))` block in schema file.');
347
300
  process.exitCode = 1;
348
301
  return;
349
302
  }
350
-
351
303
  if (updatedSchemaContent === schemaContent) {
352
304
  console.log('ℹ️ Rules already include all keys from type.');
353
305
  return;
354
306
  }
355
-
356
307
  await fs.writeFile(schemaPath, updatedSchemaContent, 'utf-8');
357
308
  console.log(`✅ Schema updated from type: ${schemaPath}`);
358
309
  }
@@ -22,9 +22,8 @@ const listSchemaFiles = async (targetPath: string): Promise<string[]> => {
22
22
  };
23
23
 
24
24
  const resolveAliasMap = async (): Promise<Map<string, string>> => {
25
- const { contexts, coreAlias } = await getConfigState();
25
+ const { contexts } = await getConfigState();
26
26
  const map = new Map<string, string>();
27
- map.set(coreAlias, path.join(process.cwd(), 'src', 'core'));
28
27
 
29
28
  for (const context of contexts) {
30
29
  const alias = resolveContextAlias(contexts, context.name);
@@ -2,34 +2,26 @@ import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import prompts from 'prompts';
4
4
  import { selectContext } from './repositoryModuleShared.js';
5
-
6
5
  const isValidIdentifier = (value) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(value);
7
-
8
6
  const toPropertyName = (key) => (isValidIdentifier(key) ? key : `'${String(key).replace(/'/g, "\\'")}'`);
9
-
10
7
  const getIndent = (level) => '\t'.repeat(level);
11
-
12
8
  const normalizeObjectInput = (rawValue) => {
13
9
  let input = String(rawValue ?? '').trim();
14
10
  if (input.endsWith(';')) {
15
11
  input = input.slice(0, -1).trim();
16
12
  }
17
-
18
13
  const openCurly = (input.match(/\{/g) ?? []).length;
19
14
  const closeCurly = (input.match(/\}/g) ?? []).length;
20
15
  if (openCurly > closeCurly) {
21
16
  input += '}'.repeat(openCurly - closeCurly);
22
17
  }
23
-
24
18
  return input;
25
19
  };
26
-
27
20
  const parseObjectInput = (rawValue) => {
28
21
  const input = normalizeObjectInput(rawValue);
29
22
  if (!input.length) {
30
23
  throw new Error('Input is empty');
31
24
  }
32
-
33
25
  try {
34
26
  const parsed = JSON.parse(input);
35
27
  if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
@@ -39,63 +31,49 @@ const parseObjectInput = (rawValue) => {
39
31
  } catch {
40
32
  // fallback to JS object literal
41
33
  }
42
-
43
- // eslint-disable-next-line no-new-func
44
34
  const parsed = new Function(`"use strict"; return (${input});`)();
45
35
  if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
46
36
  throw new Error('Input root must be an object');
47
37
  }
48
38
  return parsed;
49
39
  };
50
-
51
40
  const stringifyType = (value, level = 1) => {
52
41
  if (value === null) return 'null';
53
-
54
42
  const valueType = typeof value;
55
43
  if (valueType === 'string') return 'string';
56
44
  if (valueType === 'number') return Number.isFinite(value) ? 'number' : 'unknown';
57
45
  if (valueType === 'boolean') return 'boolean';
58
46
  if (valueType === 'bigint') return 'bigint';
59
47
  if (valueType === 'undefined') return 'undefined';
60
-
61
48
  if (Array.isArray(value)) {
62
49
  if (!value.length) return 'unknown[]';
63
-
64
50
  const itemTypes = Array.from(new Set(value.map((item) => stringifyType(item, level + 1))));
65
51
  if (itemTypes.length === 1) {
66
- const single = itemTypes[0];
52
+ const single = itemTypes[0] ?? 'unknown';
67
53
  if (single.includes('\n')) return `Array<${single}>`;
68
54
  return `${single}[]`;
69
55
  }
70
-
71
56
  const union = itemTypes.join(' | ');
72
57
  if (union.includes('\n')) return `Array<${union}>`;
73
58
  return `(${union})[]`;
74
59
  }
75
-
76
60
  if (valueType === 'object') {
77
61
  const entries = Object.entries(value);
78
62
  if (!entries.length) return 'Record<string, unknown>';
79
-
80
63
  const lines = entries.map(([entryKey, entryValue]) => {
81
64
  const propertyType = stringifyType(entryValue, level + 1);
82
65
  return `${getIndent(level + 1)}${toPropertyName(entryKey)}: ${propertyType};`;
83
66
  });
84
-
85
67
  return `{\n${lines.join('\n')}\n${getIndent(level)}}`;
86
68
  }
87
-
88
69
  return 'unknown';
89
70
  };
90
-
91
71
  const findInterfaceDeclaration = (content) => {
92
72
  const declarationMatch = content.match(/export\s+interface\s+([A-Za-z0-9_]+)\s*\{/);
93
73
  if (!declarationMatch || declarationMatch.index === undefined) return null;
94
-
95
- const name = declarationMatch[1];
74
+ const name = declarationMatch[1] ?? 'Interface';
96
75
  const openBraceIndex = content.indexOf('{', declarationMatch.index);
97
76
  if (openBraceIndex === -1) return null;
98
-
99
77
  let depth = 0;
100
78
  let closeBraceIndex = -1;
101
79
  for (let index = openBraceIndex; index < content.length; index += 1) {
@@ -109,9 +87,7 @@ const findInterfaceDeclaration = (content) => {
109
87
  }
110
88
  }
111
89
  }
112
-
113
90
  if (closeBraceIndex === -1) return null;
114
-
115
91
  const body = content.slice(openBraceIndex + 1, closeBraceIndex);
116
92
  return {
117
93
  name,
@@ -120,17 +96,16 @@ const findInterfaceDeclaration = (content) => {
120
96
  body
121
97
  };
122
98
  };
123
-
124
99
  const extractExistingRootKeys = (body) => {
125
100
  const keys = new Set();
126
101
  const keyRegex = /^\s*([A-Za-z_$][A-Za-z0-9_$]*)\??\s*:/gm;
127
102
  let match;
128
103
  while ((match = keyRegex.exec(body)) !== null) {
129
- keys.add(match[1]);
104
+ const key = match[1];
105
+ if (key) keys.add(key);
130
106
  }
131
107
  return keys;
132
108
  };
133
-
134
109
  const listDomains = async (contextName) => {
135
110
  const domainRoot = path.join(process.cwd(), 'src', 'app', contextName, 'layers', 'domain');
136
111
  try {
@@ -140,7 +115,6 @@ const listDomains = async (contextName) => {
140
115
  return [];
141
116
  }
142
117
  };
143
-
144
118
  const listModelFiles = async (contextName, domainName) => {
145
119
  const modelRoot = path.join(process.cwd(), 'src', 'app', contextName, 'layers', 'domain', domainName, 'model');
146
120
  try {
@@ -155,21 +129,18 @@ const listModelFiles = async (contextName, domainName) => {
155
129
  return [];
156
130
  }
157
131
  };
158
-
159
132
  export default async function generateTypesJson() {
160
133
  const contextName = await selectContext('Select context for model update:');
161
134
  if (!contextName) {
162
135
  process.exitCode = 1;
163
136
  return;
164
137
  }
165
-
166
138
  const domains = await listDomains(contextName);
167
139
  if (!domains.length) {
168
140
  console.error(`❌ No domains found in context "${contextName}".`);
169
141
  process.exitCode = 1;
170
142
  return;
171
143
  }
172
-
173
144
  const { domainName } = await prompts({
174
145
  type: 'select',
175
146
  name: 'domainName',
@@ -177,19 +148,16 @@ export default async function generateTypesJson() {
177
148
  choices: domains.map((item) => ({ title: item, value: item })),
178
149
  initial: 0
179
150
  });
180
-
181
151
  if (!domainName) {
182
152
  process.exitCode = 1;
183
153
  return;
184
154
  }
185
-
186
155
  const models = await listModelFiles(contextName, String(domainName));
187
156
  if (!models.length) {
188
157
  console.error(`❌ No model files found in domain "${domainName}".`);
189
158
  process.exitCode = 1;
190
159
  return;
191
160
  }
192
-
193
161
  const { modelPath } = await prompts({
194
162
  type: 'select',
195
163
  name: 'modelPath',
@@ -197,12 +165,10 @@ export default async function generateTypesJson() {
197
165
  choices: models.map((item) => ({ title: item.name, value: item.path })),
198
166
  initial: 0
199
167
  });
200
-
201
168
  if (!modelPath) {
202
169
  process.exitCode = 1;
203
170
  return;
204
171
  }
205
-
206
172
  const { rawJson } = await prompts({
207
173
  type: 'text',
208
174
  name: 'rawJson',
@@ -216,12 +182,10 @@ export default async function generateTypesJson() {
216
182
  }
217
183
  }
218
184
  });
219
-
220
185
  if (!rawJson) {
221
186
  process.exitCode = 1;
222
187
  return;
223
188
  }
224
-
225
189
  const parsedJson = parseObjectInput(rawJson);
226
190
  const content = await fs.readFile(String(modelPath), 'utf-8');
227
191
  const interfaceDeclaration = findInterfaceDeclaration(content);
@@ -230,23 +194,18 @@ export default async function generateTypesJson() {
230
194
  process.exitCode = 1;
231
195
  return;
232
196
  }
233
-
234
197
  const existingKeys = extractExistingRootKeys(interfaceDeclaration.body);
235
198
  const generatedLines = Object.entries(parsedJson)
236
199
  .filter(([key]) => !existingKeys.has(key))
237
200
  .map(([key, value]) => `${getIndent(1)}${toPropertyName(key)}: ${stringifyType(value, 1)};`);
238
-
239
201
  if (!generatedLines.length) {
240
202
  console.log('ℹ️ No new keys to add. Model already contains all JSON keys.');
241
203
  return;
242
204
  }
243
-
244
205
  const trimmedBody = interfaceDeclaration.body.trimEnd();
245
206
  const bodyPrefix = trimmedBody.length ? `${trimmedBody}\n` : '';
246
207
  const newBody = `${bodyPrefix}${generatedLines.join('\n')}\n`;
247
-
248
208
  const updatedContent = `${content.slice(0, interfaceDeclaration.openBraceIndex + 1)}${newBody}${content.slice(interfaceDeclaration.closeBraceIndex)}`;
249
209
  await fs.writeFile(String(modelPath), updatedContent, 'utf-8');
250
-
251
210
  console.log(`✅ Model updated: ${modelPath}`);
252
211
  }
@@ -8,14 +8,12 @@ import {
8
8
  resolveRepositoriesPath,
9
9
  selectContext
10
10
  } from './repositoryModuleShared.js';
11
-
12
11
  export default async function generateUseCases() {
13
12
  const contextName = await selectContext('Select context for UseCases:');
14
13
  if (!contextName) {
15
14
  process.exitCode = 1;
16
15
  return;
17
16
  }
18
-
19
17
  const repositoriesPath = resolveRepositoriesPath(contextName);
20
18
  const repositories = await getAvailableTsNames(repositoriesPath);
21
19
  if (!repositories.length) {
@@ -23,7 +21,6 @@ export default async function generateUseCases() {
23
21
  process.exitCode = 1;
24
22
  return;
25
23
  }
26
-
27
24
  const { repositoryName } = await prompts({
28
25
  type: 'select',
29
26
  name: 'repositoryName',
@@ -31,12 +28,10 @@ export default async function generateUseCases() {
31
28
  choices: repositories.map((item) => ({ title: item, value: item })),
32
29
  initial: 0
33
30
  });
34
-
35
31
  if (!repositoryName) {
36
32
  process.exitCode = 1;
37
33
  return;
38
34
  }
39
-
40
35
  const { contexts } = await getConfigState();
41
36
  const contextAlias = resolveContextAlias(contexts, contextName);
42
37
  const domainName = await resolveDomainForRepository({
@@ -44,24 +39,20 @@ export default async function generateUseCases() {
44
39
  contextAlias,
45
40
  repositoryName: String(repositoryName)
46
41
  });
47
-
48
42
  if (!domainName) {
49
43
  console.error('❌ Unable to resolve domain from repository imports.');
50
44
  process.exitCode = 1;
51
45
  return;
52
46
  }
53
-
54
47
  const created = await createUseCasesForRepository({
55
48
  contextName,
56
49
  contextAlias,
57
50
  domainName,
58
51
  repositoryName: String(repositoryName)
59
52
  });
60
-
61
53
  if (!created) {
62
54
  process.exitCode = 1;
63
55
  return;
64
56
  }
65
-
66
57
  console.log(`✅ UseCases generated for ${repositoryName}`);
67
58
  }