@azure-net/cli 1.4.2 → 2.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 (32) hide show
  1. package/bin/azure-net.js +88 -37
  2. package/package.json +1 -1
  3. package/src/commands/generate/generateCrud.js +350 -0
  4. package/src/commands/generate/generateDatasource.js +41 -0
  5. package/src/commands/generate/generateModule.js +23 -0
  6. package/src/commands/generate/generatePresenter.js +113 -0
  7. package/src/commands/generate/generateRepository.js +102 -0
  8. package/src/commands/generate/generateResponse.js +42 -0
  9. package/src/commands/generate/generateSchema.js +95 -0
  10. package/src/commands/generate/generateService.js +93 -0
  11. package/src/commands/generate/index.js +8 -0
  12. package/src/commands/init/index.js +7 -0
  13. package/src/commands/init/initAliases.js +50 -0
  14. package/src/commands/init/initEdges.js +42 -0
  15. package/src/commands/init/initMiddleware.js +43 -0
  16. package/src/commands/init/initSchema.js +19 -0
  17. package/src/commands/init/initStructure.js +79 -0
  18. package/src/commands/init/initTranslations.js +102 -0
  19. package/src/utils/contextUtils.js +53 -0
  20. package/src/utils/fileUtils.js +79 -0
  21. package/src/utils/loadConfig.js +2 -2
  22. package/src/utils/providerUtils.js +107 -0
  23. package/.idea/azure-net-ecosystem-cli.iml +0 -9
  24. package/.idea/modules.xml +0 -8
  25. package/src/commands/generateCrud.js +0 -135
  26. package/src/commands/generateDatasource.js +0 -44
  27. package/src/commands/generateRepo.js +0 -69
  28. package/src/commands/generateRequest.js +0 -95
  29. package/src/commands/generateService.js +0 -77
  30. package/src/commands/generateStructure.js +0 -65
  31. package/src/commands/initAliases.js +0 -101
  32. /package/src/commands/{initLint.js → init/initLint.js} +0 -0
@@ -0,0 +1,102 @@
1
+ import prompts from 'prompts';
2
+ import fs from 'fs/promises';
3
+ import path from 'path';
4
+ import { selectContext, getContextPath, toPascalCase, getAvailableFiles, toCamelCase } from '../../utils/contextUtils.js';
5
+ import { writeIfNotExists, updateIndexTs } from '../../utils/fileUtils.js';
6
+ import { ensureProvider, addToProvider } from '../../utils/providerUtils.js';
7
+
8
+ const repositoryTemplate = `import { {{datasource}} } from '{{datasourceImport}}';
9
+
10
+ export class {{name}}Repository {
11
+ \tconstructor(private {{datasourceVar}}: {{datasource}}) {}
12
+ \t
13
+ \tpublic async example() {
14
+ \t\treturn this.{{datasourceVar}}.createRequest(({ http }) =>
15
+ \t\t\thttp.get('/endpoint')
16
+ \t\t).then(res => res.getData());
17
+ \t}
18
+ }`;
19
+
20
+ export default async function generateRepository() {
21
+ const context = await selectContext('Select context for repository:');
22
+
23
+ if (context === 'core') {
24
+ console.error('❌ Cannot create repository in core. Choose a specific context.');
25
+ return;
26
+ }
27
+
28
+ const { name } = await prompts({
29
+ type: 'text',
30
+ name: 'name',
31
+ message: 'Repository name (without "Repository" suffix):'
32
+ });
33
+
34
+ // Get available datasources
35
+ const contextPath = getContextPath(context);
36
+ const coreDatasources = await getAvailableFiles(
37
+ path.join(process.cwd(), 'src/app/core/Datasource')
38
+ );
39
+ const contextDatasources = await getAvailableFiles(
40
+ path.join(contextPath, 'Infrastructure', 'Http', 'Datasource')
41
+ );
42
+
43
+ const allDatasources = [
44
+ ...coreDatasources.map(d => ({ title: `${d} (core)`, value: { name: d, from: 'core' } })),
45
+ ...contextDatasources.map(d => ({ title: `${d} (${context})`, value: { name: d, from: context } }))
46
+ ];
47
+
48
+ if (allDatasources.length === 0) {
49
+ console.error('❌ No datasources available. Create a datasource first.');
50
+ return;
51
+ }
52
+
53
+ const { datasource } = await prompts({
54
+ type: 'select',
55
+ name: 'datasource',
56
+ message: 'Select datasource:',
57
+ choices: allDatasources
58
+ });
59
+
60
+ const pascalName = toPascalCase(name);
61
+ const contextName = toPascalCase(context);
62
+ const repoPath = path.join(contextPath, 'Infrastructure', 'Http', 'Repositories');
63
+ const filePath = path.join(repoPath, `${pascalName}Repository.ts`);
64
+
65
+ // Generate repository
66
+ const datasourceImport = datasource.from === 'core'
67
+ ? '$core/Datasource'
68
+ : '../Datasource';
69
+
70
+ const content = repositoryTemplate
71
+ .replace(/{{name}}/g, pascalName)
72
+ .replace(/{{datasource}}/g, datasource.name)
73
+ .replace(/{{datasourceImport}}/g, datasourceImport)
74
+ .replace(/{{datasourceVar}}/g, toCamelCase(datasource.name));
75
+
76
+ await writeIfNotExists(filePath, content);
77
+ await updateIndexTs(repoPath);
78
+
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
+ }
91
+
92
+ // Ensure InfrastructureProvider and add repository
93
+ const infraProvider = await ensureProvider(context, 'Infrastructure', { hasDatasource: true });
94
+ await addToProvider(
95
+ infraProvider.path,
96
+ `${pascalName}Repository`,
97
+ '../Http/Repositories',
98
+ `DatasourceProvider.${datasource.name}`
99
+ );
100
+
101
+ console.log(`✅ Repository created at ${filePath}`);
102
+ }
@@ -0,0 +1,42 @@
1
+ import prompts from 'prompts';
2
+ import { selectContext, getContextPath, toPascalCase } from '../../utils/contextUtils.js';
3
+ import { writeIfNotExists, updateIndexTs } from '../../utils/fileUtils.js';
4
+ import path from 'path';
5
+
6
+ const responseTemplate = `import { ResponseBuilder } from '@azure-net/kit';
7
+
8
+ export interface I{{name}}Response<T = unknown> {
9
+ \tdata: T;
10
+ \tsuccess: boolean;
11
+ \tmessage: string;
12
+ }
13
+
14
+ export class {{name}}Response<TData = unknown, TMeta = unknown> extends ResponseBuilder<TData, TMeta, I{{name}}Response<TData>> {
15
+ \toverride unwrapData(data: I{{name}}Response<TData>): TData {
16
+ \t\treturn data.data;
17
+ \t}
18
+ }`;
19
+
20
+ export default async function generateResponse() {
21
+ const context = await selectContext();
22
+
23
+ const { name } = await prompts({
24
+ type: 'text',
25
+ name: 'name',
26
+ message: 'Response name (PascalCase):'
27
+ });
28
+
29
+ const pascalName = toPascalCase(name);
30
+ const contextPath = getContextPath(context);
31
+ const responsePath = context === 'core'
32
+ ? path.join(contextPath, 'Responses')
33
+ : path.join(contextPath, 'Infrastructure', 'Responses');
34
+
35
+ const content = responseTemplate.replace(/{{name}}/g, pascalName);
36
+ const filePath = path.join(responsePath, `${pascalName}Response.ts`);
37
+
38
+ await writeIfNotExists(filePath, content);
39
+ await updateIndexTs(responsePath);
40
+
41
+ console.log(`✅ Response created at ${filePath}`);
42
+ }
@@ -0,0 +1,95 @@
1
+ import prompts from 'prompts';
2
+ import path from 'path';
3
+ import { selectContext, getContextPath, toPascalCase, getAvailableFiles } from '../../utils/contextUtils.js';
4
+ import { writeIfNotExists, updateIndexTs } from '../../utils/fileUtils.js';
5
+
6
+ const schemaWithCoreTemplate = `import { {{coreSchema}} } from '$core/Schema';
7
+ import type { I{{name}}Request } from '${{context}}/Domain/Ports/{{entity}}';
8
+
9
+ export const {{name}}Schema = {{coreSchema}}<I{{name}}Request>()
10
+ \t.rules((rules) => ({
11
+ \t\t// Add validation rules here
12
+ \t}))
13
+ \t.create();`;
14
+
15
+ const schemaWithPackageTemplate = `import { createSchemaFactory } from '@azure-net/kit';
16
+ import { createRules, validationMessagesI18n } from '@azure-net/kit/schema';
17
+ import type { I{{name}}Request } from '${{context}}/Domain/Ports/{{entity}}';
18
+
19
+ const Schema = createSchemaFactory(createRules(validationMessagesI18n));
20
+
21
+ export const {{name}}Schema = Schema<I{{name}}Request>()
22
+ \t.rules((rules) => ({
23
+ \t\t// Add validation rules here
24
+ \t}))
25
+ \t.create();`;
26
+
27
+ export default async function generateSchema() {
28
+ const context = await selectContext('Select context for schema:');
29
+
30
+ if (context === 'core') {
31
+ console.error('❌ Cannot create schema in core. Choose a specific context.');
32
+ return;
33
+ }
34
+
35
+ const { module } = await prompts({
36
+ type: 'text',
37
+ name: 'module',
38
+ message: 'Module name (folder in Delivery):'
39
+ });
40
+
41
+ const { name } = await prompts({
42
+ type: 'text',
43
+ name: 'name',
44
+ message: 'Schema name (without "Schema" suffix):'
45
+ });
46
+
47
+ // Check for core schemas
48
+ const coreSchemas = await getAvailableFiles(
49
+ path.join(process.cwd(), 'src/app/core/Schema')
50
+ );
51
+
52
+ const choices = [
53
+ { title: 'Use createSchemaFactory from package', value: 'package' },
54
+ ...coreSchemas.map(s => ({ title: `Use ${s} from core`, value: s }))
55
+ ];
56
+
57
+ const { schemaType } = await prompts({
58
+ type: 'select',
59
+ name: 'schemaType',
60
+ message: 'Select schema factory:',
61
+ choices
62
+ });
63
+
64
+ const pascalName = toPascalCase(name);
65
+ const moduleName = toPascalCase(module);
66
+ const contextPath = getContextPath(context);
67
+ const schemaPath = path.join(contextPath, 'Delivery', moduleName, 'Schema');
68
+ const filePath = path.join(schemaPath, `${pascalName}Schema.ts`);
69
+
70
+ const content = schemaType === 'package'
71
+ ? schemaWithPackageTemplate
72
+ .replace(/{{name}}/g, pascalName)
73
+ .replace(/{{context}}/g, context)
74
+ .replace(/{{entity}}/g, moduleName)
75
+ : schemaWithCoreTemplate
76
+ .replace(/{{name}}/g, pascalName)
77
+ .replace(/{{context}}/g, context)
78
+ .replace(/{{entity}}/g, moduleName)
79
+ .replace(/{{coreSchema}}/g, schemaType);
80
+
81
+ await writeIfNotExists(filePath, content);
82
+ await updateIndexTs(schemaPath);
83
+
84
+ // Update module index
85
+ const moduleIndexPath = path.join(contextPath, 'Delivery', moduleName, 'index.ts');
86
+ if (await fs.access(moduleIndexPath).then(() => true).catch(() => false)) {
87
+ let indexContent = await fs.readFile(moduleIndexPath, 'utf-8');
88
+ if (!indexContent.includes(`export * from './Schema'`)) {
89
+ indexContent += `\nexport * from './Schema';`;
90
+ await fs.writeFile(moduleIndexPath, indexContent, 'utf-8');
91
+ }
92
+ }
93
+
94
+ console.log(`✅ Schema created at ${filePath}`);
95
+ }
@@ -0,0 +1,93 @@
1
+ import prompts from 'prompts';
2
+ import fs from 'fs/promises';
3
+ import path from 'path';
4
+ import { selectContext, getContextPath, toPascalCase, getAvailableFiles } from '../../utils/contextUtils.js';
5
+ import { writeIfNotExists, updateIndexTs } from '../../utils/fileUtils.js';
6
+ import { ensureProvider, addToProvider } from '../../utils/providerUtils.js';
7
+
8
+ const serviceTemplate = `import { ClassMirror } from '@azure-net/kit';
9
+ import { {{repository}} } from '../../Infrastructure/Repositories/index.js';
10
+
11
+ export class {{name}}Service extends ClassMirror<{{repository}}> {
12
+ \tconstructor(private {{repositoryVar}}: {{repository}}) {
13
+ \t\tsuper({{repositoryVar}});
14
+ \t}
15
+ \t
16
+ \tdeclare example: {{repository}}['example'];
17
+ }`;
18
+
19
+ const serviceWithoutRepoTemplate = `export class {{name}}Service {
20
+ \tconstructor() {}
21
+ \t
22
+ \tpublic async example() {
23
+ \t\t// Implement service logic
24
+ \t\treturn {};
25
+ \t}
26
+ }`;
27
+
28
+ export default async function generateService() {
29
+ const context = await selectContext('Select context for service:');
30
+
31
+ if (context === 'core') {
32
+ console.error('❌ Cannot create service in core. Choose a specific context.');
33
+ return;
34
+ }
35
+
36
+ const { name } = await prompts({
37
+ type: 'text',
38
+ name: 'name',
39
+ message: 'Service name (without "Service" suffix):'
40
+ });
41
+
42
+ // Get available repositories
43
+ const contextPath = getContextPath(context);
44
+ const repositories = await getAvailableFiles(
45
+ path.join(contextPath, 'Infrastructure', 'Repositories')
46
+ );
47
+
48
+ const choices = [
49
+ { title: 'Without repository', value: null },
50
+ ...repositories.map(r => ({ title: `${r}Repository`, value: `${r}Repository` }))
51
+ ];
52
+
53
+ const { repository } = await prompts({
54
+ type: 'select',
55
+ name: 'repository',
56
+ message: 'Select repository:',
57
+ choices
58
+ });
59
+
60
+ const pascalName = toPascalCase(name);
61
+ const servicePath = path.join(contextPath, 'Application', 'Services');
62
+ const filePath = path.join(servicePath, `${pascalName}Service.ts`);
63
+
64
+ // Generate service
65
+ const content = repository
66
+ ? serviceTemplate
67
+ .replace(/{{name}}/g, pascalName)
68
+ .replace(/{{repository}}/g, repository)
69
+ .replace(/{{repositoryVar}}/g, repository.charAt(0).toLowerCase() + repository.slice(1))
70
+ : serviceWithoutRepoTemplate.replace(/{{name}}/g, pascalName);
71
+
72
+ await writeIfNotExists(filePath, content);
73
+ await updateIndexTs(servicePath);
74
+
75
+ // Ensure ApplicationProvider exists and add service
76
+ const appProvider = await ensureProvider(context, 'Application', { infrastructure: true });
77
+ await addToProvider(
78
+ appProvider.path,
79
+ `${pascalName}Service`,
80
+ '../Services/index.js'
81
+ );
82
+
83
+ // Add repository dependency if selected
84
+ if (repository) {
85
+ let providerContent = await fs.readFile(appProvider.path, 'utf-8');
86
+ const serviceFactory = `${pascalName}Service: () => new ${pascalName}Service()`;
87
+ const serviceWithRepo = `${pascalName}Service: () => new ${pascalName}Service(InfrastructureProvider.${repository})`;
88
+ providerContent = providerContent.replace(serviceFactory, serviceWithRepo);
89
+ await fs.writeFile(appProvider.path, providerContent, 'utf-8');
90
+ }
91
+
92
+ console.log(`✅ Service created at ${filePath}`);
93
+ }
@@ -0,0 +1,8 @@
1
+ export { default as generateDatasource } from './generateDatasource.js';
2
+ export { default as generateResponse } from './generateResponse.js';
3
+ export { default as generateRepository } from './generateRepository.js';
4
+ export { default as generateService } from './generateService.js';
5
+ export { default as generateSchema } from './generateSchema.js';
6
+ export { default as generatePresenter } from './generatePresenter.js';
7
+ export { default as generateModule } from './generateModule.js';
8
+ export { default as generateCrud } from './generateCrud.js';
@@ -0,0 +1,7 @@
1
+ export { default as initStructure } from './initStructure.js';
2
+ export { default as initAliases } from './initAliases.js';
3
+ export { default as initMiddleware } from './initMiddleware.js';
4
+ export { default as initEdges } from './initEdges.js';
5
+ export { default as initTranslations } from './initTranslations.js';
6
+ export { default as initSchema } from './initSchema.js';
7
+ export { default as initLint } from './initLint.js';
@@ -0,0 +1,50 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ import { loadUserConfig } from '../../utils/loadConfig.js';
4
+ import { execSync } from 'child_process';
5
+
6
+ const svelteConfigPath = path.resolve('svelte.config.js');
7
+
8
+ function generateAliases(config) {
9
+ const contexts = config.contexts || ['app'];
10
+
11
+ return Object.fromEntries([
12
+ ...contexts.map(c => [`$${c}`, `./src/app/contexts/${c}`]),
13
+ ['$core', './src/app/core'],
14
+ ['$lib', './src/lib']
15
+ ]);
16
+ }
17
+
18
+ function serializeObjectLiteral(obj) {
19
+ return Object.entries(obj)
20
+ .map(([key, value]) => `\t\t\t'${key}': '${value}'`)
21
+ .join(',\n');
22
+ }
23
+
24
+ export default async function initAliases() {
25
+ const config = await loadUserConfig();
26
+ const newAliases = generateAliases(config);
27
+
28
+ let content = await fs.readFile(svelteConfigPath, 'utf-8');
29
+
30
+ const aliasRegex = /alias:\s*{([\s\S]*?)}/m;
31
+ const aliasMatch = content.match(aliasRegex);
32
+
33
+ const newAliasBlock = `alias: {\n${serializeObjectLiteral(newAliases)}\n\t\t}`;
34
+
35
+ if (aliasMatch) {
36
+ content = content.replace(aliasRegex, newAliasBlock);
37
+ } else {
38
+ const kitRegex = /kit:\s*{/;
39
+ content = content.replace(kitRegex, `kit: {\n\t\t${newAliasBlock},`);
40
+ }
41
+
42
+ await fs.writeFile(svelteConfigPath, content, 'utf-8');
43
+ console.log('✅ Aliases updated in svelte.config.js');
44
+
45
+ try {
46
+ execSync('npm run format', { stdio: 'inherit' });
47
+ } catch {
48
+ console.warn('⚠️ Failed to run format');
49
+ }
50
+ }
@@ -0,0 +1,42 @@
1
+ import { injectIntoFile, writeIfNotExists } from '../../utils/fileUtils.js';
2
+ import path from 'path';
3
+
4
+ const hooksServerPath = path.join(process.cwd(), 'src/hooks.server.ts');
5
+
6
+ const hooksTemplate = `import { dev } from '$app/environment';
7
+ import { edgesHandle } from '@azure-net/kit/edges/server';
8
+ import { type Handle } from '@sveltejs/kit';
9
+
10
+ export const handle: Handle = async ({ event, resolve }) => {
11
+ \treturn edgesHandle(
12
+ \t\tevent,
13
+ \t\tasync ({ edgesEvent, serialize }) => {
14
+ \t\t\treturn resolve(edgesEvent, {
15
+ \t\t\t\ttransformPageChunk: ({ html }) => serialize(html)
16
+ \t\t\t});
17
+ \t\t},
18
+ \t\tdev
19
+ \t);
20
+ };`;
21
+
22
+ export default async function initEdges() {
23
+ const created = await writeIfNotExists(hooksServerPath, hooksTemplate);
24
+
25
+ if (!created) {
26
+ const importStatement = `import { edgesHandle } from '@azure-net/kit/edges/server';`;
27
+ await injectIntoFile(hooksServerPath, 'import {', importStatement, 'before');
28
+
29
+ const handleCode = `\treturn edgesHandle(
30
+ \t\tevent,
31
+ \t\tasync ({ edgesEvent, serialize }) => {`;
32
+
33
+ await injectIntoFile(
34
+ hooksServerPath,
35
+ 'export const handle: Handle = async ({ event, resolve }) => {',
36
+ handleCode,
37
+ 'after'
38
+ );
39
+ }
40
+
41
+ console.log('✅ Edges-svelte initialized');
42
+ }
@@ -0,0 +1,43 @@
1
+ import { writeIfNotExists, injectIntoFile } from '../../utils/fileUtils.js';
2
+ import path from 'path';
3
+
4
+ const middlewarePath = path.join(process.cwd(), 'src/app/core/Middleware/MiddlewareManager.ts');
5
+ const hooksServerPath = path.join(process.cwd(), 'src/hooks.server.ts');
6
+ const layoutPath = path.join(process.cwd(), 'src/routes/+layout.svelte');
7
+
8
+ const middlewareTemplate = `import { createMiddlewareManager } from '@azure-net/kit';
9
+
10
+ export const { clientMiddleware, serverMiddleware } = createMiddlewareManager([]);`;
11
+
12
+ export default async function initMiddleware() {
13
+ await writeIfNotExists(middlewarePath, middlewareTemplate);
14
+ await writeIfNotExists(
15
+ path.join(process.cwd(), 'src/app/core/Middleware/index.ts'),
16
+ `export * from './MiddlewareManager';`
17
+ );
18
+
19
+ // Add to hooks.server.ts
20
+ await injectIntoFile(
21
+ hooksServerPath,
22
+ 'import',
23
+ `import { serverMiddleware } from '$core';`,
24
+ 'before'
25
+ );
26
+
27
+ await injectIntoFile(
28
+ hooksServerPath,
29
+ 'async ({ edgesEvent, serialize }) => {',
30
+ '\t\t\tawait serverMiddleware();',
31
+ 'after'
32
+ );
33
+
34
+ // Add to +layout.svelte
35
+ await injectIntoFile(
36
+ layoutPath,
37
+ '<script',
38
+ `\timport { clientMiddleware } from '$core';\n\tclientMiddleware();`,
39
+ 'after'
40
+ );
41
+
42
+ console.log('✅ Middleware initialized');
43
+ }
@@ -0,0 +1,19 @@
1
+ import { writeIfNotExists } from '../../utils/fileUtils.js';
2
+ import path from 'path';
3
+
4
+ const schemaPath = path.join(process.cwd(), 'src/app/core/Schemas/Schema.ts');
5
+
6
+ const schemaTemplate = `import { createSchemaFactory } from '@azure-net/kit';
7
+ import { createRules, validationMessagesI18n } from '@azure-net/kit/schema';
8
+
9
+ export const Schema = createSchemaFactory(createRules(validationMessagesI18n));`;
10
+
11
+ export default async function initSchema() {
12
+ await writeIfNotExists(schemaPath, schemaTemplate);
13
+ await writeIfNotExists(
14
+ path.join(process.cwd(), 'src/app/core/Schemas/index.ts'),
15
+ `export * from './Schema';`
16
+ );
17
+
18
+ console.log('✅ Schema factory initialized');
19
+ }
@@ -0,0 +1,79 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ import { loadUserConfig } from '../../utils/loadConfig.js';
4
+
5
+ const APP_ROOT = path.join(process.cwd(), 'src', 'app');
6
+ const CONTEXTS_PATH = path.join(APP_ROOT, 'contexts');
7
+ const CORE_PATH = path.join(APP_ROOT, 'core');
8
+
9
+ async function createDirIfNotExists(dirPath) {
10
+ try {
11
+ await fs.mkdir(dirPath, { recursive: true });
12
+ console.log(`📁 Created: ${dirPath}`);
13
+ } catch (e) {
14
+ console.error(`❌ Failed to create ${dirPath}:`, e.message);
15
+ }
16
+ }
17
+
18
+ async function createIndexFile(dirPath, exportPatterns = []) {
19
+ const indexPath = path.join(dirPath, 'index.ts');
20
+ if (exportPatterns.length > 0) {
21
+ const content = exportPatterns.map(pattern => `export * from '${pattern}';`).join('\n') + '\n';
22
+ await fs.writeFile(indexPath, content, 'utf-8');
23
+ }
24
+ }
25
+
26
+ async function createBaseStructure(root) {
27
+ // Domain
28
+ const domainPath = path.join(root, 'Domain');
29
+ await createDirIfNotExists(path.join(domainPath, 'Entities'));
30
+ await createDirIfNotExists(path.join(domainPath, 'Ports'));
31
+
32
+ // Infrastructure
33
+ const infraPath = path.join(root, 'Infrastructure');
34
+ await createDirIfNotExists(path.join(infraPath, 'Http', 'Repositories'));
35
+ await createDirIfNotExists(path.join(infraPath, 'Http', 'Datasource'));
36
+ await createDirIfNotExists(path.join(infraPath, 'Providers'));
37
+
38
+ // Application
39
+ const appPath = path.join(root, 'Application');
40
+ await createDirIfNotExists(path.join(appPath, 'Services'));
41
+ await createDirIfNotExists(path.join(appPath, 'Providers'));
42
+
43
+ // Delivery - organized by modules, not by type
44
+ const deliveryPath = path.join(root, 'Delivery');
45
+ await createDirIfNotExists(deliveryPath);
46
+ }
47
+
48
+ export default async function initStructure() {
49
+ const config = await loadUserConfig();
50
+ const contexts = config.contexts || ['app'];
51
+
52
+ console.log('📦 Generating architecture...');
53
+
54
+ // Create contexts
55
+ for (const context of contexts) {
56
+ const contextPath = path.join(CONTEXTS_PATH, context);
57
+ await createBaseStructure(contextPath);
58
+ }
59
+
60
+ // Create core structure
61
+ await createDirIfNotExists(CORE_PATH);
62
+ await createDirIfNotExists(path.join(CORE_PATH, 'Datasource'));
63
+ await createDirIfNotExists(path.join(CORE_PATH, 'Response'));
64
+ await createDirIfNotExists(path.join(CORE_PATH, 'Schema'));
65
+ await createDirIfNotExists(path.join(CORE_PATH, 'Middleware'));
66
+ await createDirIfNotExists(path.join(CORE_PATH, 'Presenter'));
67
+ await createDirIfNotExists(path.join(CORE_PATH, 'Translation'));
68
+
69
+ // Create core index.ts that exports all subdirectories
70
+ await createIndexFile(CORE_PATH, [
71
+ './Schema',
72
+ './Datasource',
73
+ './Response',
74
+ './Middleware',
75
+ './Translation'
76
+ ]);
77
+
78
+ console.log('✅ Structure initialization complete!');
79
+ }