@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
@@ -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
  }