@azure-net/cli 5.0.0-1 → 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 (71) hide show
  1. package/bin/azure-net.js +12 -45
  2. package/bin/azure-net.ts +13 -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 +2 -1
  9. package/src/checks/checkInternal.ts +2 -0
  10. package/src/checks/checkLayerBoundaries.js +50 -54
  11. package/src/checks/checkLayerBoundaries.ts +55 -58
  12. package/src/checks/checkLayerImports.js +136 -0
  13. package/src/checks/checkLayerImports.ts +185 -0
  14. package/src/checks/checkPresenterNames.js +1 -37
  15. package/src/checks/checkPresenterNames.ts +1 -6
  16. package/src/checks/checkProject.js +0 -6
  17. package/src/checks/checkProviderGraph.js +1 -38
  18. package/src/checks/checkProviderNames.js +0 -28
  19. package/src/checks/index.js +1 -1
  20. package/src/checks/index.ts +1 -0
  21. package/src/generate/layers/generateRepository.js +4 -19
  22. package/src/generate/layers/generateRepositoryMethod.js +0 -12
  23. package/src/generate/layers/generateUseCases.js +0 -6
  24. package/src/generate/layers/repositoryShared.js +41 -104
  25. package/src/generate/layers/repositoryShared.ts +17 -12
  26. package/src/generate/module/generateDomain.js +0 -25
  27. package/src/generate/module/generateModule.js +0 -10
  28. package/src/generate/module/generateModulePreset.js +10 -51
  29. package/src/generate/module/generateModulePreset.ts +9 -8
  30. package/src/generate/module/generatePresenter.js +29 -76
  31. package/src/generate/module/generatePresenter.ts +15 -10
  32. package/src/generate/module/generateRepository.js +0 -17
  33. package/src/generate/module/generateSchemaFromType.js +9 -58
  34. package/src/generate/module/generateSchemaFromType.ts +1 -2
  35. package/src/generate/module/generateTypesJson.js +4 -45
  36. package/src/generate/module/generateUseCases.js +0 -9
  37. package/src/generate/module/repositoryModuleShared.js +21 -98
  38. package/src/generate/module/repositoryModuleShared.ts +14 -10
  39. package/src/generate/ui/generateComponent.js +0 -16
  40. package/src/generate/ui/generateDesignComponent.js +0 -12
  41. package/src/generate/ui/generateWidget.js +0 -12
  42. package/src/init/initAliases.js +42 -64
  43. package/src/init/initAliases.ts +47 -42
  44. package/src/init/initEdges.js +0 -15
  45. package/src/init/initStructure.js +48 -21
  46. package/src/init/initStructure.ts +51 -3
  47. package/src/install/installFresh.js +0 -16
  48. package/src/plugins/addLint.js +11 -46
  49. package/src/scaffolds/createCoreSchema.js +6 -40
  50. package/src/scaffolds/createCoreSchema.ts +6 -18
  51. package/src/scaffolds/createDatasource.js +26 -61
  52. package/src/scaffolds/createDatasource.ts +26 -40
  53. package/src/scaffolds/createDatasourceProvider.js +19 -56
  54. package/src/scaffolds/createDatasourceProvider.ts +20 -34
  55. package/src/scaffolds/createPresenterFactory.js +5 -34
  56. package/src/scaffolds/createPresenterFactory.ts +5 -17
  57. package/src/scaffolds/createProgram.js +1 -5
  58. package/src/scaffolds/createResponse.js +3 -11
  59. package/src/scaffolds/createResponse.ts +3 -1
  60. package/src/scaffolds/createSchemaRule.js +3 -8
  61. package/src/scaffolds/createSchemaRule.ts +3 -1
  62. package/src/scaffolds/createTranslationManager.js +3 -14
  63. package/src/scaffolds/createTranslationManager.ts +3 -1
  64. package/src/utils/contextUtils.js +5 -20
  65. package/src/utils/contextUtils.ts +2 -3
  66. package/src/utils/fileUtils.js +3 -38
  67. package/src/utils/fileUtils.ts +0 -26
  68. package/src/utils/loadConfig.js +1 -14
  69. package/src/utils/loadConfig.ts +1 -3
  70. package/src/utils/sharedFoundation.js +48 -0
  71. package/src/utils/sharedFoundation.ts +70 -0
@@ -1,20 +1,15 @@
1
1
  import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
-
4
3
  const TARGET_EXTENSIONS = new Set(['.ts', '.js', '.svelte']);
5
4
  const IGNORED_DIRS = new Set(['node_modules', 'dist', '.svelte-kit', '.git']);
6
-
7
5
  const CREATE_FACTORY_PATTERN = '(?:export\\s+)?(?:const|let|var)\\s+([A-Za-z_$][A-Za-z0-9_$]*)\\s*=\\s*createPresenterFactory\\s*\\(';
8
6
  const IMPORT_FROM_PRESENTER_PATTERN = 'import\\s*\\{([^}]+)\\}\\s*from\\s*[\'"]([^\'"]+)[\'"]';
9
7
  const PRESENTER_CALL_PATTERN = '\\b([A-Za-z_$][A-Za-z0-9_$]*)\\s*\\(\\s*([\'"`])([^\'"`]*)\\2';
10
-
11
8
  const toPosixPath = (value) => value.split(path.sep).join('/');
12
-
13
9
  const isPresenterImportPath = (importPath) => {
14
10
  const normalized = importPath.replace(/\\/g, '/');
15
11
  return /(^|\/)presenter(\/|$)/.test(normalized);
16
12
  };
17
-
18
13
  const parseImportLocals = (rawImports) => {
19
14
  const locals = [];
20
15
  for (const segment of rawImports.split(',')) {
@@ -25,7 +20,6 @@ const parseImportLocals = (rawImports) => {
25
20
  locals.push(aliasMatch[2]);
26
21
  continue;
27
22
  }
28
-
29
23
  const directMatch = item.match(/^([A-Za-z_$][A-Za-z0-9_$]*)$/);
30
24
  if (directMatch?.[1]) {
31
25
  locals.push(directMatch[1]);
@@ -33,22 +27,18 @@ const parseImportLocals = (rawImports) => {
33
27
  }
34
28
  return locals;
35
29
  };
36
-
37
30
  const listSourceFiles = async (rootDir) => {
38
31
  const result = [];
39
32
  const stack = [rootDir];
40
-
41
33
  while (stack.length) {
42
34
  const current = stack.pop();
43
35
  if (!current) continue;
44
-
45
36
  let entries = [];
46
37
  try {
47
38
  entries = await fs.readdir(current, { withFileTypes: true });
48
39
  } catch {
49
40
  continue;
50
41
  }
51
-
52
42
  for (const entry of entries) {
53
43
  if (entry.isDirectory()) {
54
44
  if (!IGNORED_DIRS.has(entry.name)) {
@@ -56,7 +46,6 @@ const listSourceFiles = async (rootDir) => {
56
46
  }
57
47
  continue;
58
48
  }
59
-
60
49
  if (!entry.isFile()) continue;
61
50
  const fullPath = path.join(current, entry.name);
62
51
  const extension = path.extname(fullPath);
@@ -64,10 +53,8 @@ const listSourceFiles = async (rootDir) => {
64
53
  result.push(fullPath);
65
54
  }
66
55
  }
67
-
68
56
  return result;
69
57
  };
70
-
71
58
  const getLineByIndex = (content, index) => {
72
59
  let line = 1;
73
60
  for (let i = 0; i < index; i += 1) {
@@ -75,7 +62,6 @@ const getLineByIndex = (content, index) => {
75
62
  }
76
63
  return line;
77
64
  };
78
-
79
65
  const extractFactoryNamesFromContent = (content) => {
80
66
  const createFactoryRegex = new RegExp(CREATE_FACTORY_PATTERN, 'g');
81
67
  const names = [];
@@ -86,7 +72,6 @@ const extractFactoryNamesFromContent = (content) => {
86
72
  }
87
73
  return names;
88
74
  };
89
-
90
75
  const extractImportedPresenterFactories = (content) => {
91
76
  const importFromPresenterRegex = new RegExp(IMPORT_FROM_PRESENTER_PATTERN, 'g');
92
77
  const names = [];
@@ -100,12 +85,10 @@ const extractImportedPresenterFactories = (content) => {
100
85
  }
101
86
  return names;
102
87
  };
103
-
104
88
  const collectPresenterOccurrences = (content, filePath, knownFactories) => {
105
89
  const presenterCallRegex = new RegExp(PRESENTER_CALL_PATTERN, 'g');
106
90
  const occurrences = [];
107
91
  const availableCallees = new Set(['createPresenter']);
108
-
109
92
  for (const name of extractFactoryNamesFromContent(content)) {
110
93
  availableCallees.add(name);
111
94
  }
@@ -115,7 +98,6 @@ const collectPresenterOccurrences = (content, filePath, knownFactories) => {
115
98
  for (const name of knownFactories) {
116
99
  availableCallees.add(name);
117
100
  }
118
-
119
101
  let match;
120
102
  while ((match = presenterCallRegex.exec(content)) !== null) {
121
103
  const callee = match[1];
@@ -124,7 +106,6 @@ const collectPresenterOccurrences = (content, filePath, knownFactories) => {
124
106
  if (!callee || !presenterId) continue;
125
107
  if (!availableCallees.has(callee)) continue;
126
108
  if (quote === '`' && presenterId.includes('${')) continue;
127
-
128
109
  occurrences.push({
129
110
  id: presenterId,
130
111
  file: filePath,
@@ -132,10 +113,8 @@ const collectPresenterOccurrences = (content, filePath, knownFactories) => {
132
113
  callee
133
114
  });
134
115
  }
135
-
136
116
  return occurrences;
137
117
  };
138
-
139
118
  export default async function checkPresenterNames() {
140
119
  const srcPath = path.join(process.cwd(), 'src');
141
120
  try {
@@ -145,51 +124,37 @@ export default async function checkPresenterNames() {
145
124
  process.exitCode = 1;
146
125
  return;
147
126
  }
148
-
149
127
  const files = await listSourceFiles(srcPath);
150
128
  const fileContents = new Map();
151
-
152
129
  for (const filePath of files) {
153
- // eslint-disable-next-line no-await-in-loop
154
130
  const content = await fs.readFile(filePath, 'utf-8');
155
131
  fileContents.set(filePath, content);
156
132
  }
157
-
158
133
  const globalFactoryNames = new Set();
159
- for (const [filePath, content] of fileContents.entries()) {
134
+ for (const content of fileContents.values()) {
160
135
  for (const name of extractFactoryNamesFromContent(content)) {
161
136
  globalFactoryNames.add(name);
162
137
  }
163
- if (filePath.endsWith(path.join('core', 'presenter', 'index.ts')) || filePath.endsWith(path.join('core', 'presenter', 'index.js'))) {
164
- for (const name of extractImportedPresenterFactories(content)) {
165
- globalFactoryNames.add(name);
166
- }
167
- }
168
138
  }
169
-
170
139
  const occurrences = [];
171
140
  for (const [filePath, content] of fileContents.entries()) {
172
141
  occurrences.push(...collectPresenterOccurrences(content, filePath, globalFactoryNames));
173
142
  }
174
-
175
143
  if (!occurrences.length) {
176
144
  console.log('✅ No presenter declarations found.');
177
145
  return;
178
146
  }
179
-
180
147
  const grouped = new Map();
181
148
  for (const occurrence of occurrences) {
182
149
  const list = grouped.get(occurrence.id) ?? [];
183
150
  list.push(occurrence);
184
151
  grouped.set(occurrence.id, list);
185
152
  }
186
-
187
153
  const duplicated = Array.from(grouped.entries()).filter(([, list]) => list.length > 1);
188
154
  if (!duplicated.length) {
189
155
  console.log(`✅ Presenter names are unique (${occurrences.length} found).`);
190
156
  return;
191
157
  }
192
-
193
158
  console.error('❌ Duplicate presenter names found:');
194
159
  for (const [presenterId, list] of duplicated) {
195
160
  console.error(`\n- "${presenterId}"`);
@@ -197,6 +162,5 @@ export default async function checkPresenterNames() {
197
162
  console.error(` • ${toPosixPath(path.relative(process.cwd(), item.file))}:${item.line} (${item.callee})`);
198
163
  }
199
164
  }
200
-
201
165
  process.exitCode = 1;
202
166
  }
@@ -162,15 +162,10 @@ export default async function checkPresenterNames(): Promise<void> {
162
162
  }
163
163
 
164
164
  const globalFactoryNames = new Set<string>();
165
- for (const [filePath, content] of fileContents.entries()) {
165
+ for (const content of fileContents.values()) {
166
166
  for (const name of extractFactoryNamesFromContent(content)) {
167
167
  globalFactoryNames.add(name);
168
168
  }
169
- if (filePath.endsWith(path.join('core', 'presenter', 'index.ts')) || filePath.endsWith(path.join('core', 'presenter', 'index.js'))) {
170
- for (const name of extractImportedPresenterFactories(content)) {
171
- globalFactoryNames.add(name);
172
- }
173
- }
174
169
  }
175
170
 
176
171
  const occurrences: PresenterOccurrence[] = [];
@@ -1,15 +1,12 @@
1
1
  import { execSync } from 'node:child_process';
2
2
  import { loadUserConfig } from '../utils/loadConfig.js';
3
3
  import checkInternal from './checkInternal.js';
4
-
5
4
  const isPackageManager = (value) => typeof value === 'string' && ['pnpm', 'npm', 'yarn', 'bun'].includes(value);
6
-
7
5
  const runScript = (manager, script) => {
8
6
  const command = `${manager} run ${script}`;
9
7
  console.log(`\n▶ Running: ${command}`);
10
8
  execSync(command, { stdio: 'inherit' });
11
9
  };
12
-
13
10
  const runInternalChecks = async () => {
14
11
  console.log('\n▶ Running: azure-net check internal');
15
12
  process.exitCode = 0;
@@ -18,17 +15,14 @@ const runInternalChecks = async () => {
18
15
  throw new Error('azure-net check internal failed');
19
16
  }
20
17
  };
21
-
22
18
  export default async function checkProject() {
23
19
  const config = await loadUserConfig();
24
20
  const manager = config.packageManager;
25
-
26
21
  if (!isPackageManager(manager)) {
27
22
  console.error('❌ packageManager is missing or invalid in azure-net.config.ts/js. Use one of: bun, pnpm, npm, yarn');
28
23
  process.exitCode = 1;
29
24
  return;
30
25
  }
31
-
32
26
  try {
33
27
  runScript(manager, 'format');
34
28
  await runInternalChecks();
@@ -1,11 +1,8 @@
1
1
  import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
-
4
3
  const TARGET_EXTENSIONS = new Set(['.ts', '.js']);
5
4
  const IGNORED_DIRS = new Set(['node_modules', 'dist', '.svelte-kit', '.git']);
6
-
7
5
  const toPosixPath = (value) => value.split(path.sep).join('/');
8
-
9
6
  const getLineByIndex = (content, index) => {
10
7
  let line = 1;
11
8
  for (let i = 0; i < index; i += 1) {
@@ -13,38 +10,31 @@ const getLineByIndex = (content, index) => {
13
10
  }
14
11
  return line;
15
12
  };
16
-
17
13
  const listSourceFiles = async (rootDir) => {
18
14
  const files = [];
19
15
  const stack = [rootDir];
20
-
21
16
  while (stack.length) {
22
17
  const current = stack.pop();
23
18
  if (!current) continue;
24
-
25
19
  let entries = [];
26
20
  try {
27
21
  entries = await fs.readdir(current, { withFileTypes: true });
28
22
  } catch {
29
23
  continue;
30
24
  }
31
-
32
25
  for (const entry of entries) {
33
26
  if (entry.isDirectory()) {
34
27
  if (!IGNORED_DIRS.has(entry.name)) stack.push(path.join(current, entry.name));
35
28
  continue;
36
29
  }
37
-
38
30
  if (!entry.isFile()) continue;
39
31
  const filePath = path.join(current, entry.name);
40
32
  if (!TARGET_EXTENSIONS.has(path.extname(filePath))) continue;
41
33
  files.push(filePath);
42
34
  }
43
35
  }
44
-
45
36
  return files;
46
37
  };
47
-
48
38
  const findMatchingBracket = (content, startIndex, openChar, closeChar) => {
49
39
  let depth = 0;
50
40
  for (let i = startIndex; i < content.length; i += 1) {
@@ -57,11 +47,9 @@ const findMatchingBracket = (content, startIndex, openChar, closeChar) => {
57
47
  }
58
48
  return -1;
59
49
  };
60
-
61
50
  const extractDependsOn = (configBlock) => {
62
51
  const dependsOnMatch = configBlock.match(/dependsOn\s*:\s*\{([\s\S]*?)\}/m);
63
52
  if (!dependsOnMatch?.[1]) return [];
64
-
65
53
  const block = dependsOnMatch[1];
66
54
  const deps = new Set();
67
55
  const keyRegex = /([A-Za-z_$][A-Za-z0-9_$]*)\s*:/g;
@@ -72,20 +60,16 @@ const extractDependsOn = (configBlock) => {
72
60
  }
73
61
  return [...deps];
74
62
  };
75
-
76
63
  const parseProviderGraphFromFile = (content, filePath) => {
77
64
  const nodes = [];
78
65
  const token = 'createBoundaryProvider(';
79
66
  let fromIndex = 0;
80
-
81
67
  while (fromIndex < content.length) {
82
68
  const start = content.indexOf(token, fromIndex);
83
69
  if (start === -1) break;
84
-
85
70
  const openParenIndex = start + token.length - 1;
86
71
  const closeParenIndex = findMatchingBracket(content, openParenIndex, '(', ')');
87
72
  if (closeParenIndex === -1) break;
88
-
89
73
  const fullCall = content.slice(openParenIndex + 1, closeParenIndex);
90
74
  const idMatch = fullCall.match(/^\s*(['"`])([^'"`]+)\1\s*,/m);
91
75
  const providerName = idMatch?.[2];
@@ -96,7 +80,6 @@ const parseProviderGraphFromFile = (content, filePath) => {
96
80
  const absoluteObjectEnd = findMatchingBracket(content, absoluteObjectStart, '{', '}');
97
81
  const configBlock =
98
82
  absoluteObjectEnd !== -1 ? content.slice(absoluteObjectStart, absoluteObjectEnd + 1) : fullCall.slice(objectStartInCall);
99
-
100
83
  nodes.push({
101
84
  name: providerName,
102
85
  file: filePath,
@@ -112,24 +95,19 @@ const parseProviderGraphFromFile = (content, filePath) => {
112
95
  });
113
96
  }
114
97
  }
115
-
116
98
  fromIndex = closeParenIndex + 1;
117
99
  }
118
-
119
100
  return nodes;
120
101
  };
121
-
122
102
  const findCycles = (graph) => {
123
103
  const cycles = [];
124
104
  const visited = new Set();
125
105
  const inStack = new Set();
126
106
  const stack = [];
127
-
128
107
  const dfs = (node) => {
129
108
  visited.add(node);
130
109
  inStack.add(node);
131
110
  stack.push(node);
132
-
133
111
  const neighbors = graph.get(node) ?? [];
134
112
  for (const next of neighbors) {
135
113
  if (!graph.has(next)) continue;
@@ -142,18 +120,14 @@ const findCycles = (graph) => {
142
120
  if (idx !== -1) cycles.push([...stack.slice(idx), next]);
143
121
  }
144
122
  }
145
-
146
123
  stack.pop();
147
124
  inStack.delete(node);
148
125
  };
149
-
150
126
  for (const node of graph.keys()) {
151
127
  if (!visited.has(node)) dfs(node);
152
128
  }
153
-
154
129
  return cycles;
155
130
  };
156
-
157
131
  export default async function checkProviderGraph() {
158
132
  const srcPath = path.join(process.cwd(), 'src');
159
133
  try {
@@ -163,40 +137,32 @@ export default async function checkProviderGraph() {
163
137
  process.exitCode = 1;
164
138
  return;
165
139
  }
166
-
167
140
  const files = await listSourceFiles(srcPath);
168
141
  const providers = [];
169
-
170
142
  for (const filePath of files) {
171
143
  const content = await fs.readFile(filePath, 'utf-8');
172
144
  providers.push(...parseProviderGraphFromFile(content, filePath));
173
145
  }
174
-
175
146
  if (!providers.length) {
176
147
  console.log('✅ No createBoundaryProvider declarations found.');
177
148
  return;
178
149
  }
179
-
180
150
  const graph = new Map();
181
151
  const issues = [];
182
152
  const byName = new Map();
183
-
184
153
  for (const provider of providers) {
185
154
  if (byName.has(provider.name)) {
186
155
  const existing = byName.get(provider.name);
187
156
  issues.push({
188
157
  file: provider.file,
189
158
  line: provider.line,
190
- message: `Provider graph ambiguity: duplicate provider id "${provider.name}" (first declared at ${toPosixPath(
191
- path.relative(process.cwd(), existing.file)
192
- )}:${existing.line})`
159
+ message: `Provider graph ambiguity: duplicate provider id "${provider.name}" (first declared at ${toPosixPath(path.relative(process.cwd(), existing.file))}:${existing.line})`
193
160
  });
194
161
  continue;
195
162
  }
196
163
  byName.set(provider.name, provider);
197
164
  graph.set(provider.name, provider.dependsOn);
198
165
  }
199
-
200
166
  const cycles = findCycles(graph);
201
167
  for (const cycle of cycles) {
202
168
  const firstNode = byName.get(cycle[0] ?? '');
@@ -206,16 +172,13 @@ export default async function checkProviderGraph() {
206
172
  message: `Circular provider dependency detected: ${cycle.join(' -> ')}`
207
173
  });
208
174
  }
209
-
210
175
  if (!issues.length) {
211
176
  console.log(`✅ Provider graph check passed (${providers.length} providers).`);
212
177
  return;
213
178
  }
214
-
215
179
  console.error('❌ Provider graph check failed:');
216
180
  for (const issue of issues) {
217
181
  console.error(`• ${toPosixPath(path.relative(process.cwd(), issue.file))}:${issue.line} — ${issue.message}`);
218
182
  }
219
-
220
183
  process.exitCode = 1;
221
184
  }
@@ -1,47 +1,38 @@
1
1
  import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
-
4
3
  const TARGET_EXTENSIONS = new Set(['.ts', '.js', '.svelte']);
5
4
  const IGNORED_DIRS = new Set(['node_modules', 'dist', '.svelte-kit', '.git']);
6
5
  const IMPORT_PATTERN = 'import\\s*\\{([^}]+)\\}\\s*from\\s*[\'"]([^\'"]+)[\'"]';
7
6
  const CALL_PATTERN = '\\b([A-Za-z_$][A-Za-z0-9_$]*)\\s*\\(\\s*([\'"`])([^\'"`]*)\\2';
8
-
9
7
  const toPosixPath = (value) => value.split(path.sep).join('/');
10
-
11
8
  const parseImportAliases = (rawImports, importName) => {
12
9
  const aliases = [];
13
10
  for (const segment of rawImports.split(',')) {
14
11
  const item = segment.trim();
15
12
  if (!item.length) continue;
16
-
17
13
  const aliasMatch = item.match(/^([A-Za-z_$][A-Za-z0-9_$]*)\s+as\s+([A-Za-z_$][A-Za-z0-9_$]*)$/);
18
14
  if (aliasMatch?.[1] === importName && aliasMatch[2]) {
19
15
  aliases.push(aliasMatch[2]);
20
16
  continue;
21
17
  }
22
-
23
18
  if (item === importName) {
24
19
  aliases.push(importName);
25
20
  }
26
21
  }
27
22
  return aliases;
28
23
  };
29
-
30
24
  const listSourceFiles = async (rootDir) => {
31
25
  const files = [];
32
26
  const stack = [rootDir];
33
-
34
27
  while (stack.length) {
35
28
  const current = stack.pop();
36
29
  if (!current) continue;
37
-
38
30
  let entries = [];
39
31
  try {
40
32
  entries = await fs.readdir(current, { withFileTypes: true });
41
33
  } catch {
42
34
  continue;
43
35
  }
44
-
45
36
  for (const entry of entries) {
46
37
  if (entry.isDirectory()) {
47
38
  if (!IGNORED_DIRS.has(entry.name)) {
@@ -49,17 +40,14 @@ const listSourceFiles = async (rootDir) => {
49
40
  }
50
41
  continue;
51
42
  }
52
-
53
43
  if (!entry.isFile()) continue;
54
44
  const filepath = path.join(current, entry.name);
55
45
  if (!TARGET_EXTENSIONS.has(path.extname(filepath))) continue;
56
46
  files.push(filepath);
57
47
  }
58
48
  }
59
-
60
49
  return files;
61
50
  };
62
-
63
51
  const getLineByIndex = (content, index) => {
64
52
  let line = 1;
65
53
  for (let i = 0; i < index; i += 1) {
@@ -67,12 +55,10 @@ const getLineByIndex = (content, index) => {
67
55
  }
68
56
  return line;
69
57
  };
70
-
71
58
  const extractBoundaryFactoryAliases = (content) => {
72
59
  const importRegex = new RegExp(IMPORT_PATTERN, 'g');
73
60
  const aliases = new Set(['createBoundaryProvider']);
74
61
  let match;
75
-
76
62
  while ((match = importRegex.exec(content)) !== null) {
77
63
  const rawImports = match[1];
78
64
  if (!rawImports) continue;
@@ -80,25 +66,20 @@ const extractBoundaryFactoryAliases = (content) => {
80
66
  aliases.add(alias);
81
67
  }
82
68
  }
83
-
84
69
  return aliases;
85
70
  };
86
-
87
71
  const collectProviderOccurrences = (content, filepath) => {
88
72
  const aliases = extractBoundaryFactoryAliases(content);
89
73
  const callRegex = new RegExp(CALL_PATTERN, 'g');
90
74
  const occurrences = [];
91
75
  let match;
92
-
93
76
  while ((match = callRegex.exec(content)) !== null) {
94
77
  const callee = match[1];
95
78
  const quote = match[2];
96
79
  const providerId = match[3];
97
-
98
80
  if (!callee || !providerId) continue;
99
81
  if (!aliases.has(callee)) continue;
100
82
  if (quote === '`' && providerId.includes('${')) continue;
101
-
102
83
  occurrences.push({
103
84
  id: providerId,
104
85
  file: filepath,
@@ -106,10 +87,8 @@ const collectProviderOccurrences = (content, filepath) => {
106
87
  callee
107
88
  });
108
89
  }
109
-
110
90
  return occurrences;
111
91
  };
112
-
113
92
  export default async function checkProviderNames() {
114
93
  const srcPath = path.join(process.cwd(), 'src');
115
94
  try {
@@ -119,33 +98,27 @@ export default async function checkProviderNames() {
119
98
  process.exitCode = 1;
120
99
  return;
121
100
  }
122
-
123
101
  const files = await listSourceFiles(srcPath);
124
102
  const occurrences = [];
125
-
126
103
  for (const filepath of files) {
127
104
  const content = await fs.readFile(filepath, 'utf-8');
128
105
  occurrences.push(...collectProviderOccurrences(content, filepath));
129
106
  }
130
-
131
107
  if (!occurrences.length) {
132
108
  console.log('✅ No providers declarations found.');
133
109
  return;
134
110
  }
135
-
136
111
  const grouped = new Map();
137
112
  for (const occurrence of occurrences) {
138
113
  const list = grouped.get(occurrence.id) ?? [];
139
114
  list.push(occurrence);
140
115
  grouped.set(occurrence.id, list);
141
116
  }
142
-
143
117
  const duplicated = Array.from(grouped.entries()).filter(([, list]) => list.length > 1);
144
118
  if (!duplicated.length) {
145
119
  console.log(`✅ Provider names are unique (${occurrences.length} found).`);
146
120
  return;
147
121
  }
148
-
149
122
  console.error('❌ Duplicate provider names found:');
150
123
  for (const [providerId, list] of duplicated) {
151
124
  console.error(`\n- "${providerId}"`);
@@ -153,6 +126,5 @@ export default async function checkProviderNames() {
153
126
  console.error(` • ${toPosixPath(path.relative(process.cwd(), item.file))}:${item.line} (${item.callee})`);
154
127
  }
155
128
  }
156
-
157
129
  process.exitCode = 1;
158
130
  }
@@ -4,8 +4,8 @@ export { default as checkProviderGraph } from './checkProviderGraph.js';
4
4
  export { default as checkDomain } from './checkDomain.js';
5
5
  export { default as checkImports } from './checkImports.js';
6
6
  export { default as checkHooks } from './checkHooks.js';
7
+ export { default as checkLayerImports } from './checkLayerImports.js';
7
8
  export { default as checkLayerBoundaries } from './checkLayerBoundaries.js';
8
9
  export { default as checkFoldersStructure } from './checkFoldersStructure.js';
9
10
  export { default as checkInternal } from './checkInternal.js';
10
11
  export { default as checkProject } from './checkProject.js';
11
- //# sourceMappingURL=index.js.map
@@ -4,6 +4,7 @@ export { default as checkProviderGraph } from './checkProviderGraph.js';
4
4
  export { default as checkDomain } from './checkDomain.js';
5
5
  export { default as checkImports } from './checkImports.js';
6
6
  export { default as checkHooks } from './checkHooks.js';
7
+ export { default as checkLayerImports } from './checkLayerImports.js';
7
8
  export { default as checkLayerBoundaries } from './checkLayerBoundaries.js';
8
9
  export { default as checkFoldersStructure } from './checkFoldersStructure.js';
9
10
  export { default as checkInternal } from './checkInternal.js';