@azure-net/cli 2.0.4 → 2.0.5

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-net/cli",
3
- "version": "2.0.4",
3
+ "version": "2.0.5",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "azure-net": "bin/azure-net.js"
@@ -3,9 +3,9 @@ import fs from 'fs/promises';
3
3
  import path from 'path';
4
4
  import { selectContext, getContextPath, toPascalCase, toCamelCase, getAvailableFiles } from '../../utils/contextUtils.js';
5
5
  import { writeIfNotExists, updateIndexTs, ensureIndexExports } from '../../utils/fileUtils.js';
6
- import { ensureProvider, addToProvider } from '../../utils/providerUtils.js';
6
+ import { ensureProvider, addToProvider, ensureDatasourceProvider } from '../../utils/providerUtils.js';
7
7
 
8
- // Templates for CRUD generation
8
+ // Templates remain the same as before...
9
9
  const entityTemplate = `export interface I{{name}} {
10
10
  \tid: number;
11
11
  \t// Add entity fields here
@@ -114,7 +114,6 @@ export const Update{{name}}Schema = {{schemaFactory}}<I{{name}}UpdateRequest>()
114
114
  \t}))
115
115
  \t.create();`;
116
116
 
117
- // Presenter template with core factory (includes async helpers)
118
117
  const presenterWithCoreTemplate = `import { {{presenterFactory}} } from '\$core/Presenter';
119
118
  import { ApplicationProvider } from '\${{context}}/Application';
120
119
  import { Create{{name}}Schema, Update{{name}}Schema } from './Schema';
@@ -145,7 +144,6 @@ export const {{name}}Presenter = {{presenterFactory}}('{{name}}Presenter', ({ cr
145
144
  \treturn { collection, resource, create, update, remove };
146
145
  });`;
147
146
 
148
- // Presenter template without async helpers
149
147
  const presenterWithoutCoreTemplate = `import { createPresenter } from '@azure-net/kit';
150
148
  import { ApplicationProvider } from '\${{context}}/Application';
151
149
  import { Create{{name}}Schema, Update{{name}}Schema } from './Schema';
@@ -308,7 +306,6 @@ export default async function generateCrud() {
308
306
  : '$core/Schema';
309
307
 
310
308
  if (schemaType === 'package') {
311
- // Add the import for createSchemaFactory and rules
312
309
  const schemaImportFull = `import { createSchemaFactory } from '@azure-net/kit';
313
310
  import { createRules, validationMessagesI18n } from '@azure-net/kit/schema';
314
311
 
@@ -352,7 +349,7 @@ const Schema = createSchemaFactory(createRules(validationMessagesI18n));`;
352
349
  }
353
350
  await updateIndexTs(schemaPath);
354
351
 
355
- // 6. Create Presenter - use correct template based on type
352
+ // 6. Create Presenter
356
353
  const presenterTemplate = presenterType === 'package'
357
354
  ? presenterWithoutCoreTemplate
358
355
  : presenterWithCoreTemplate;
@@ -375,24 +372,14 @@ const Schema = createSchemaFactory(createRules(validationMessagesI18n));`;
375
372
 
376
373
  // 7. Setup Providers
377
374
  // Ensure DatasourceProvider
378
- const datasourceProviderPath = path.join(contextPath, 'Infrastructure/Providers/DatasourceProvider.ts');
379
- if (!(await fs.access(datasourceProviderPath).then(() => true).catch(() => false))) {
380
- const datasourceProviderContent = `import { createBoundaryProvider } from '@azure-net/kit';
381
- import { ${datasource.name} } from '${datasource.from === 'core' ? '$core/Datasource' : '../Http/Datasource'}';
382
-
383
- export const DatasourceProvider = createBoundaryProvider('${contextName}DatasourceProvider', () => ({
384
- \t${datasource.name}: () => DatasourceProvider.${datasource.name}
385
- }));`;
386
- await writeIfNotExists(datasourceProviderPath, datasourceProviderContent);
387
- await updateIndexTs(path.dirname(datasourceProviderPath));
388
- }
375
+ await ensureDatasourceProvider(context, datasource.name, datasource.from === 'core');
389
376
 
390
377
  // Ensure InfrastructureProvider
391
- const infraProvider = await ensureProvider(context, 'Infrastructure', {});
378
+ const infraProvider = await ensureProvider(context, 'Infrastructure', { hasDatasource: true });
392
379
  await addToProvider(
393
380
  infraProvider.path,
394
381
  `${pascalName}Repository`,
395
- '$' + context + '/Infrastructure/Http/Repositories',
382
+ `\$${context}/Infrastructure/Http/Repositories`,
396
383
  `DatasourceProvider.${datasource.name}`
397
384
  );
398
385
 
@@ -401,7 +388,7 @@ export const DatasourceProvider = createBoundaryProvider('${contextName}Datasour
401
388
  await addToProvider(
402
389
  appProvider.path,
403
390
  `${pascalName}Service`,
404
- '$' + context + '/Application/Services',
391
+ `\$${context}/Application/Services`,
405
392
  `InfrastructureProvider.${pascalName}Repository`
406
393
  );
407
394
 
@@ -1,15 +1,21 @@
1
1
  import prompts from 'prompts';
2
2
  import path from 'path';
3
- import { selectContext, getContextPath, toPascalCase, getAvailableFiles, toCamelCase } from '../../utils/contextUtils.js';
3
+ import fs from 'fs/promises';
4
+ import { selectContext, getContextPath, toPascalCase, getAvailableFiles } from '../../utils/contextUtils.js';
4
5
  import { writeIfNotExists, updateIndexTs } from '../../utils/fileUtils.js';
5
- import { ensureProvider, addToProvider } from '../../utils/providerUtils.js';
6
6
 
7
7
  const datasourceWithResponseTemplate = `import { BaseHttpDatasource, type CreateRequestCallbackType } from '@azure-net/kit/infra';
8
8
  import { {{responseClass}}, type {{responseInterface}} } from '{{responseImport}}';
9
+ import { HttpService } from '@azure-net/kit/infra';
9
10
 
10
11
  export class {{name}}Datasource extends BaseHttpDatasource {
11
- \tconstructor(private http: HttpService) {
12
- \t\tsuper({ http });
12
+ \tconstructor(config?: { baseUrl?: string; [key: string]: unknown }) {
13
+ \t\tsuper({
14
+ \t\t\thttp: new HttpService({
15
+ \t\t\t\tbaseUrl: config?.baseUrl || 'https://api.example.com',
16
+ \t\t\t\t...config
17
+ \t\t\t})
18
+ \t\t});
13
19
  \t}
14
20
 
15
21
  \tasync createRequest<T>(callback: CreateRequestCallbackType<{{responseInterface}}<T>>) {
@@ -17,14 +23,6 @@ export class {{name}}Datasource extends BaseHttpDatasource {
17
23
  \t}
18
24
  }`;
19
25
 
20
- const datasourceWithoutResponseTemplate = `import { BaseHttpDatasource } from '@azure-net/kit/infra';
21
-
22
- export class {{name}}Datasource extends BaseHttpDatasource {
23
- \tconstructor(private http: HttpService) {
24
- \t\tsuper({ http });
25
- \t}
26
- }`;
27
-
28
26
  export default async function generateDatasource() {
29
27
  const context = await selectContext();
30
28
 
@@ -35,7 +33,6 @@ export default async function generateDatasource() {
35
33
  });
36
34
 
37
35
  const pascalName = toPascalCase(name);
38
- const camelName = toCamelCase(name);
39
36
  const contextPath = getContextPath(context);
40
37
 
41
38
  // Get available responses
@@ -70,17 +67,17 @@ export default async function generateDatasource() {
70
67
  choices: allResponses
71
68
  });
72
69
 
73
- // Determine interface name - typically IBackendApiDataSourceResponse or similar
70
+ // Determine interface name
74
71
  const responseInterface = `I${response.name.replace('Response', '')}Response`;
75
72
 
76
73
  const datasourcePath = context === 'core'
77
74
  ? path.join(contextPath, 'Datasource')
78
- : path.join(contextPath, 'Infrastructure', 'Http', 'Datasource');
75
+ : path.join(contextPath, 'Infrastructure/Http/Datasource');
79
76
 
80
77
  const responseImport = response.from === 'core'
81
- ? '$core/Response'
78
+ ? context === 'core' ? '../Response' : '$core/Response'
82
79
  : context === 'core'
83
- ? '../Response'
80
+ ? `../contexts/${context}/Infrastructure/Response`
84
81
  : '../../Response';
85
82
 
86
83
  const content = datasourceWithResponseTemplate
@@ -93,63 +90,6 @@ export default async function generateDatasource() {
93
90
  await writeIfNotExists(filePath, content);
94
91
  await updateIndexTs(datasourcePath);
95
92
 
96
- // If not in core, ensure DatasourceProvider exists
97
- if (context !== 'core') {
98
- const contextName = toPascalCase(context);
99
- const providerPath = path.join(contextPath, 'Infrastructure/Providers/DatasourceProvider.ts');
100
-
101
- if (!(await fs.access(providerPath).then(() => true).catch(() => false))) {
102
- const providerContent = `import { createBoundaryProvider } from '@azure-net/kit';
103
- import { HttpService } from '@azure-net/kit/infra';
104
- import { ${pascalName}Datasource } from '../Http/Datasource';
105
-
106
- export const DatasourceProvider = createBoundaryProvider('${contextName}DatasourceProvider', () => ({
107
- \t${pascalName}Datasource: () => new ${pascalName}Datasource(
108
- \t\tnew HttpService({ baseUrl: 'https://api.example.com' })
109
- \t)
110
- }));`;
111
- await writeIfNotExists(providerPath, providerContent);
112
- await updateIndexTs(path.dirname(providerPath));
113
- } else {
114
- // Add datasource to existing provider
115
- await addDatasourceToProvider(providerPath, pascalName);
116
- }
117
- }
118
-
119
93
  console.log(`✅ Datasource created at ${filePath}`);
120
- }
121
-
122
- async function addDatasourceToProvider(providerPath, datasourceName) {
123
- let content = await fs.readFile(providerPath, 'utf-8');
124
-
125
- // Add import if not exists
126
- if (!content.includes(`${datasourceName}Datasource`)) {
127
- const importStatement = `import { ${datasourceName}Datasource } from '../Http/Datasource';`;
128
- const lastImportIndex = content.lastIndexOf('import ');
129
- const endOfImportLine = content.indexOf('\n', lastImportIndex);
130
- content = content.slice(0, endOfImportLine + 1) + importStatement + '\n' + content.slice(endOfImportLine + 1);
131
- }
132
-
133
- // Add factory method
134
- const factoryLine = `\t${datasourceName}Datasource: () => new ${datasourceName}Datasource(
135
- \t\tnew HttpService({ baseUrl: 'https://api.example.com' })
136
- \t)`;
137
-
138
- if (!content.includes(`${datasourceName}Datasource:`)) {
139
- const returnIndex = content.indexOf('=> ({');
140
- const endOfReturn = content.indexOf('})', returnIndex);
141
- const beforeEnd = content.lastIndexOf('\n', endOfReturn);
142
-
143
- // Check if there are existing entries
144
- const servicesSection = content.substring(returnIndex, endOfReturn);
145
- const hasServices = servicesSection.includes(':');
146
-
147
- if (hasServices) {
148
- content = content.slice(0, beforeEnd) + ',\n' + factoryLine + content.slice(beforeEnd);
149
- } else {
150
- content = content.slice(0, beforeEnd + 1) + factoryLine + content.slice(beforeEnd);
151
- }
152
- }
153
-
154
- await fs.writeFile(providerPath, content, 'utf-8');
94
+ console.log(`\n💡 Remember to configure the datasource in DatasourceProvider when using it in repositories.`);
155
95
  }
@@ -3,7 +3,7 @@ import fs from 'fs/promises';
3
3
  import path from 'path';
4
4
  import { selectContext, getContextPath, toPascalCase, getAvailableFiles, toCamelCase } from '../../utils/contextUtils.js';
5
5
  import { writeIfNotExists, updateIndexTs } from '../../utils/fileUtils.js';
6
- import { ensureProvider, addToProvider } from '../../utils/providerUtils.js';
6
+ import { ensureProvider, addToProvider, ensureDatasourceProvider } from '../../utils/providerUtils.js';
7
7
 
8
8
  const repositoryTemplate = `import { {{datasource}} } from '{{datasourceImport}}';
9
9
 
@@ -37,7 +37,7 @@ export default async function generateRepository() {
37
37
  path.join(process.cwd(), 'src/app/core/Datasource')
38
38
  );
39
39
  const contextDatasources = await getAvailableFiles(
40
- path.join(contextPath, 'Infrastructure', 'Http', 'Datasource')
40
+ path.join(contextPath, 'Infrastructure/Http/Datasource')
41
41
  );
42
42
 
43
43
  const allDatasources = [
@@ -59,7 +59,7 @@ export default async function generateRepository() {
59
59
 
60
60
  const pascalName = toPascalCase(name);
61
61
  const contextName = toPascalCase(context);
62
- const repoPath = path.join(contextPath, 'Infrastructure', 'Http', 'Repositories');
62
+ const repoPath = path.join(contextPath, 'Infrastructure/Http/Repositories');
63
63
  const filePath = path.join(repoPath, `${pascalName}Repository.ts`);
64
64
 
65
65
  // Generate repository
@@ -77,24 +77,14 @@ export default async function generateRepository() {
77
77
  await updateIndexTs(repoPath);
78
78
 
79
79
  // Ensure DatasourceProvider exists
80
- const datasourceProviderPath = path.join(contextPath, 'Infrastructure', 'Providers', 'DatasourceProvider.ts');
81
- if (!(await fs.access(datasourceProviderPath).then(() => true).catch(() => false))) {
82
- const datasourceProviderContent = `import { createBoundaryProvider } from '@azure-net/kit';
83
- import { ${datasource.name} } from '${datasource.from === 'core' ? '$core/Datasource' : '../Http/Datasource'}';
84
-
85
- export const DatasourceProvider = createBoundaryProvider('${contextName}DatasourceProvider', () => ({
86
- \t${datasource.name}: () => new ${datasource.name}()
87
- }));`;
88
- await writeIfNotExists(datasourceProviderPath, datasourceProviderContent);
89
- await updateIndexTs(path.dirname(datasourceProviderPath));
90
- }
80
+ await ensureDatasourceProvider(context, datasource.name, datasource.from === 'core');
91
81
 
92
82
  // Ensure InfrastructureProvider and add repository
93
83
  const infraProvider = await ensureProvider(context, 'Infrastructure', { hasDatasource: true });
94
84
  await addToProvider(
95
85
  infraProvider.path,
96
86
  `${pascalName}Repository`,
97
- '../Http/Repositories',
87
+ `\$${context}/Infrastructure/Http/Repositories`,
98
88
  `DatasourceProvider.${datasource.name}`
99
89
  );
100
90
 
@@ -35,7 +35,6 @@ function generateProviderContent(context, layer, dependencies) {
35
35
 
36
36
  let imports = [`import { createBoundaryProvider } from '@azure-net/kit';`];
37
37
  let deps = [];
38
- let depParams = '';
39
38
 
40
39
  if (dependencies.hasDatasource && layer === 'Infrastructure') {
41
40
  imports.push(`import { DatasourceProvider } from './DatasourceProvider';`);
@@ -47,10 +46,7 @@ function generateProviderContent(context, layer, dependencies) {
47
46
  deps.push('InfrastructureProvider');
48
47
  }
49
48
 
50
- if (deps.length > 0) {
51
- depParams = `{ ${deps.join(', ')} }`;
52
- }
53
-
49
+ const depParams = deps.length > 0 ? `{ ${deps.join(', ')} }` : '';
54
50
  const dependsOnStr = deps.length > 0
55
51
  ? `,\n\t{ dependsOn: { ${deps.join(', ')} } }`
56
52
  : '';
@@ -59,7 +55,7 @@ function generateProviderContent(context, layer, dependencies) {
59
55
 
60
56
  export const ${varName} = createBoundaryProvider(
61
57
  \t'${boundaryName}',
62
- \t(${depParams ? depParams : ''}) => ({
58
+ \t(${depParams}) => ({
63
59
  \t\t// Services will be added here
64
60
  \t})${dependsOnStr}
65
61
  );`;
@@ -68,17 +64,69 @@ export const ${varName} = createBoundaryProvider(
68
64
  export async function addToProvider(providerPath, serviceName, importPath, dependency = null) {
69
65
  let content = await fs.readFile(providerPath, 'utf-8');
70
66
 
71
- // Use alias import path instead of relative
72
- const aliasImportPath = importPath.startsWith('$') ? importPath : importPath.startsWith('../')
73
- ? importPath // Keep relative if it's internal to the same layer
74
- : importPath;
75
-
76
- // Add import if not exists
77
- const importStatement = `import { ${serviceName} } from '${aliasImportPath}';`;
78
- if (!content.includes(serviceName)) {
79
- const lastImportIndex = content.lastIndexOf('import ');
80
- const endOfImportLine = content.indexOf('\n', lastImportIndex);
81
- content = content.slice(0, endOfImportLine + 1) + importStatement + '\n' + content.slice(endOfImportLine + 1);
67
+ // Parse existing imports to group them
68
+ const importRegex = /^import\s+{([^}]+)}\s+from\s+['"]([^'"]+)['"]/gm;
69
+ const imports = new Map();
70
+ let match;
71
+
72
+ while ((match = importRegex.exec(content)) !== null) {
73
+ const [fullMatch, importedItems, fromPath] = match;
74
+ if (!imports.has(fromPath)) {
75
+ imports.set(fromPath, new Set());
76
+ }
77
+ importedItems.split(',').forEach(item => {
78
+ imports.get(fromPath).add(item.trim());
79
+ });
80
+ }
81
+
82
+ // Add new import to the map
83
+ if (!Array.from(imports.values()).some(set => set.has(serviceName))) {
84
+ if (!imports.has(importPath)) {
85
+ imports.set(importPath, new Set());
86
+ }
87
+ imports.get(importPath).add(serviceName);
88
+ }
89
+
90
+ // Rebuild import section
91
+ const newImports = [`import { createBoundaryProvider } from '@azure-net/kit';`];
92
+
93
+ // Add DatasourceProvider import if exists
94
+ if (content.includes('DatasourceProvider') && !content.includes("import { DatasourceProvider }")) {
95
+ newImports.push(`import { DatasourceProvider } from './DatasourceProvider';`);
96
+ }
97
+
98
+ // Add other imports
99
+ for (const [fromPath, items] of imports) {
100
+ if (fromPath !== '@azure-net/kit' && !fromPath.includes('DatasourceProvider')) {
101
+ const itemsStr = Array.from(items).join(', ');
102
+ newImports.push(`import { ${itemsStr} } from '${fromPath}';`);
103
+ }
104
+ }
105
+
106
+ // Find where imports end and provider starts
107
+ const providerStartIndex = content.indexOf('export const');
108
+ const beforeProvider = content.substring(0, providerStartIndex);
109
+ const afterProvider = content.substring(providerStartIndex);
110
+
111
+ // Check if DatasourceProvider dependency needs to be added
112
+ let updatedAfterProvider = afterProvider;
113
+ if (dependency && dependency.includes('DatasourceProvider')) {
114
+ // Check if provider already has dependencies
115
+ if (!afterProvider.includes('({ DatasourceProvider })')) {
116
+ // Add DatasourceProvider to function params
117
+ updatedAfterProvider = updatedAfterProvider.replace(
118
+ /createBoundaryProvider\(\s*'[^']+',\s*\(\)/,
119
+ `createBoundaryProvider(\n\t'$1',\n\t({ DatasourceProvider })`
120
+ );
121
+
122
+ // Add dependsOn if not exists
123
+ if (!updatedAfterProvider.includes('dependsOn')) {
124
+ updatedAfterProvider = updatedAfterProvider.replace(
125
+ /\)\s*\);$/,
126
+ `),\n\t{ dependsOn: { DatasourceProvider } }\n);`
127
+ );
128
+ }
129
+ }
82
130
  }
83
131
 
84
132
  // Add factory method with dependency
@@ -86,27 +134,121 @@ export async function addToProvider(providerPath, serviceName, importPath, depen
86
134
  ? `\t\t${serviceName}: () => new ${serviceName}(${dependency})`
87
135
  : `\t\t${serviceName}: () => new ${serviceName}()`;
88
136
 
89
- if (!content.includes(`${serviceName}:`)) {
137
+ if (!updatedAfterProvider.includes(`${serviceName}:`)) {
90
138
  // Find the position to insert
91
- const returnIndex = content.indexOf('=> ({');
92
- const endOfReturn = content.indexOf('\t})', returnIndex);
139
+ const returnIndex = updatedAfterProvider.indexOf('=> ({');
140
+ const endOfReturn = updatedAfterProvider.indexOf('\t})', returnIndex);
93
141
 
94
142
  // Check if there are existing services
95
- const servicesSection = content.substring(returnIndex, endOfReturn);
96
- const hasServices = servicesSection.includes(':');
143
+ const servicesSection = updatedAfterProvider.substring(returnIndex, endOfReturn);
144
+ const hasServices = servicesSection.includes(':') && !servicesSection.includes('// Services will be added here');
97
145
 
98
146
  if (hasServices) {
99
147
  // Add comma before new service
100
- const beforeEnd = content.lastIndexOf('\n', endOfReturn);
101
- content = content.slice(0, beforeEnd) + ',\n' + factoryLine + content.slice(beforeEnd);
148
+ const beforeEnd = updatedAfterProvider.lastIndexOf('\n', endOfReturn);
149
+ updatedAfterProvider = updatedAfterProvider.slice(0, beforeEnd) + ',\n' + factoryLine + updatedAfterProvider.slice(beforeEnd);
102
150
  } else {
103
151
  // First service, replace comment
104
- content = content.replace(
152
+ updatedAfterProvider = updatedAfterProvider.replace(
105
153
  '// Services will be added here',
106
154
  factoryLine
107
155
  );
108
156
  }
109
157
  }
110
158
 
111
- await fs.writeFile(providerPath, content, 'utf-8');
159
+ // Combine everything
160
+ const finalContent = newImports.join('\n') + '\n\n' + updatedAfterProvider;
161
+ await fs.writeFile(providerPath, finalContent, 'utf-8');
162
+ }
163
+
164
+ export async function ensureDatasourceProvider(context, datasourceName, isFromCore = true) {
165
+ const contextName = toPascalCase(context);
166
+ const contextPath = path.join(process.cwd(), 'src/app/contexts', context);
167
+ const providerPath = path.join(contextPath, 'Infrastructure/Providers/DatasourceProvider.ts');
168
+
169
+ try {
170
+ await fs.access(providerPath);
171
+ // Provider exists, add datasource if needed
172
+ await addDatasourceToProvider(providerPath, datasourceName, isFromCore);
173
+ } catch {
174
+ // Create new DatasourceProvider
175
+ const content = `import { createBoundaryProvider } from '@azure-net/kit';
176
+ import { ${datasourceName} } from '${isFromCore ? '$core' : '../Http/Datasource'}';
177
+
178
+ export const DatasourceProvider = createBoundaryProvider('${contextName}DatasourceProvider', () => ({
179
+ \t${datasourceName}: () => new ${datasourceName}({})
180
+ }));`;
181
+
182
+ await writeIfNotExists(providerPath, content);
183
+ await updateIndexTs(path.dirname(providerPath));
184
+ }
185
+ }
186
+
187
+ async function addDatasourceToProvider(providerPath, datasourceName, isFromCore = true) {
188
+ let content = await fs.readFile(providerPath, 'utf-8');
189
+
190
+ // Check if datasource already exists
191
+ if (content.includes(`${datasourceName}:`)) {
192
+ return;
193
+ }
194
+
195
+ // Parse existing imports to group them
196
+ const importRegex = /^import\s+{([^}]+)}\s+from\s+['"]([^'"]+)['"]/gm;
197
+ const imports = new Map();
198
+ let match;
199
+
200
+ while ((match = importRegex.exec(content)) !== null) {
201
+ const [fullMatch, importedItems, fromPath] = match;
202
+ if (!imports.has(fromPath)) {
203
+ imports.set(fromPath, new Set());
204
+ }
205
+ importedItems.split(',').forEach(item => {
206
+ imports.get(fromPath).add(item.trim());
207
+ });
208
+ }
209
+
210
+ // Add datasource to imports
211
+ const importPath = isFromCore ? '$core' : '../Http/Datasource';
212
+ if (!imports.has(importPath)) {
213
+ imports.set(importPath, new Set());
214
+ }
215
+ imports.get(importPath).add(datasourceName);
216
+
217
+ // Rebuild import section
218
+ const newImports = [`import { createBoundaryProvider } from '@azure-net/kit';`];
219
+ for (const [fromPath, items] of imports) {
220
+ if (fromPath !== '@azure-net/kit') {
221
+ const itemsStr = Array.from(items).join(', ');
222
+ newImports.push(`import { ${itemsStr} } from '${fromPath}';`);
223
+ }
224
+ }
225
+
226
+ // Find provider content
227
+ const providerStartIndex = content.indexOf('export const');
228
+ const afterProvider = content.substring(providerStartIndex);
229
+
230
+ // Add factory method
231
+ const factoryLine = `\t${datasourceName}: () => new ${datasourceName}({})`;
232
+
233
+ const returnIndex = afterProvider.indexOf('=> ({');
234
+ const endOfReturn = afterProvider.indexOf('})', returnIndex);
235
+
236
+ // Check if there are existing services
237
+ const servicesSection = afterProvider.substring(returnIndex, endOfReturn);
238
+ const hasServices = servicesSection.includes(':');
239
+
240
+ let updatedAfterProvider = afterProvider;
241
+ if (hasServices) {
242
+ // Add comma before new service
243
+ const beforeEnd = updatedAfterProvider.lastIndexOf('\n', endOfReturn);
244
+ updatedAfterProvider = updatedAfterProvider.slice(0, beforeEnd) + ',\n' + factoryLine + updatedAfterProvider.slice(beforeEnd);
245
+ } else {
246
+ // First service
247
+ const insertPoint = returnIndex + '=> ({\n'.length;
248
+ updatedAfterProvider = updatedAfterProvider.slice(0, insertPoint) + factoryLine + '\n' + updatedAfterProvider.slice(insertPoint);
249
+ }
250
+
251
+ // Combine everything
252
+ const finalContent = newImports.join('\n') + '\n\n' + updatedAfterProvider;
253
+ await fs.writeFile(providerPath, finalContent, 'utf-8');
112
254
  }