@azure-net/cli 2.3.6 → 2.3.62

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/bin/azure-net.js CHANGED
@@ -21,7 +21,12 @@ import {
21
21
  generatePresenter,
22
22
  generateModule,
23
23
  generateCrudBase,
24
- generateCrudPresenter
24
+ generateCrudPresenter,
25
+ generateModuleBase,
26
+ generateModulePresenter,
27
+ generateComponent,
28
+ generateWidget,
29
+ generateDesignComponent
25
30
  } from '../src/commands/generate/index.js';
26
31
 
27
32
  const program = new Command();
@@ -130,4 +135,29 @@ program
130
135
  .description('Generate CRUD presenter for existing service')
131
136
  .action(generateCrudPresenter);
132
137
 
138
+ program
139
+ .command('make:module-base')
140
+ .description('Generate repository and service for a module')
141
+ .action(generateModuleBase);
142
+
143
+ program
144
+ .command('make:module-presenter')
145
+ .description('Generate presenter for existing service')
146
+ .action(generateModulePresenter);
147
+
148
+ program
149
+ .command('make:component')
150
+ .description('Generate UI component')
151
+ .action(generateComponent);
152
+
153
+ program
154
+ .command('make:widget')
155
+ .description('Generate UI widget')
156
+ .action(generateWidget);
157
+
158
+ program
159
+ .command('make:design-component')
160
+ .description('Generate design system component')
161
+ .action(generateDesignComponent);
162
+
133
163
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-net/cli",
3
- "version": "2.3.6",
3
+ "version": "2.3.62",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "azure-net": "bin/azure-net.js"
@@ -0,0 +1,53 @@
1
+ import prompts from 'prompts';
2
+ import path from 'path';
3
+ import { selectContext } from '../../utils/contextUtils.js';
4
+ import { writeIfNotExists } from '../../utils/fileUtils.js';
5
+
6
+ const componentTemplate = `<script lang="ts">
7
+ \timport './style.scss';
8
+ </script>
9
+
10
+ {{componentName}}
11
+ `;
12
+
13
+ const styleTemplate = `// Add your styles here
14
+ `;
15
+
16
+ export default async function generateComponent() {
17
+ const context = await selectContext('Select context for component:');
18
+
19
+ const { componentPath } = await prompts({
20
+ type: 'text',
21
+ name: 'componentPath',
22
+ message: 'Component path (e.g. reviews/modals/ReviewModal):',
23
+ validate: value => value.length > 0 ? true : 'Path cannot be empty'
24
+ });
25
+
26
+ // Parse the path
27
+ const normalizedPath = componentPath.replace(/\\/g, '/');
28
+ const pathParts = normalizedPath.split('/');
29
+ const componentName = pathParts[pathParts.length - 1];
30
+
31
+ // Build the full path: src/app/{context}/ui/components/{path}
32
+ const contextUiPath = path.join(process.cwd(), 'src/app', context, 'ui/components');
33
+ const fullComponentPath = path.join(contextUiPath, normalizedPath);
34
+
35
+ console.log(`\nšŸš€ Generating component: ${componentName}...\n`);
36
+
37
+ // Create Component.svelte
38
+ await writeIfNotExists(
39
+ path.join(fullComponentPath, 'Component.svelte'),
40
+ componentTemplate.replace(/{{componentName}}/g, componentName)
41
+ );
42
+
43
+ // Create style.scss
44
+ await writeIfNotExists(
45
+ path.join(fullComponentPath, 'style.scss'),
46
+ styleTemplate
47
+ );
48
+
49
+ console.log(`āœ… Component created at: ${fullComponentPath}`);
50
+ console.log(`\nšŸ’” Files created:`);
51
+ console.log(` - Component.svelte`);
52
+ console.log(` - style.scss`);
53
+ }
@@ -116,7 +116,7 @@ export default async function generateCrudBase() {
116
116
  // Get available datasources
117
117
  const contextPath = getContextPath(context);
118
118
  const coreDatasources = await getAvailableFiles(
119
- path.join(process.cwd(), 'src/app/core/datasources')
119
+ path.join(process.cwd(), 'src/core/datasources')
120
120
  );
121
121
  const contextDatasources = await getAvailableFiles(
122
122
  path.join(contextPath, 'infrastructure/http/datasources')
@@ -114,7 +114,7 @@ export default async function generateCrudPresenter() {
114
114
 
115
115
  // Get schema factory
116
116
  const coreSchemas = await getAvailableFiles(
117
- path.join(process.cwd(), 'src/app/core/schemas')
117
+ path.join(process.cwd(), 'src/core/schemas')
118
118
  );
119
119
 
120
120
  const { schemaType } = await prompts({
@@ -129,7 +129,7 @@ export default async function generateCrudPresenter() {
129
129
 
130
130
  // Get presenter factory
131
131
  const corePresenters = await getAvailableFiles(
132
- path.join(process.cwd(), 'src/app/core/presenters')
132
+ path.join(process.cwd(), 'src/core/presenters')
133
133
  );
134
134
 
135
135
  const { presenterType } = await prompts({
@@ -23,12 +23,12 @@ export default async function generateDatasource() {
23
23
 
24
24
  const pascalName = toPascalCase(name);
25
25
  const contextPath = context === 'core'
26
- ? path.join(process.cwd(), 'src/app/core')
26
+ ? path.join(process.cwd(), 'src/core')
27
27
  : getContextPath(context);
28
28
 
29
29
  // Get available responses
30
30
  const coreResponses = await getAvailableFiles(
31
- path.join(process.cwd(), 'src/app/core/responses')
31
+ path.join(process.cwd(), 'src/core/responses')
32
32
  );
33
33
 
34
34
  const contextResponses = context !== 'core'
@@ -0,0 +1,53 @@
1
+ import prompts from 'prompts';
2
+ import path from 'path';
3
+ import { selectContext } from '../../utils/contextUtils.js';
4
+ import { writeIfNotExists } from '../../utils/fileUtils.js';
5
+
6
+ const designComponentTemplate = `<script lang="ts">
7
+ \timport './style.scss';
8
+ </script>
9
+
10
+ {{componentName}}
11
+ `;
12
+
13
+ const styleTemplate = `// Add your styles here
14
+ `;
15
+
16
+ export default async function generateDesignComponent() {
17
+ const context = await selectContext('Select context for design component:');
18
+
19
+ const { componentPath } = await prompts({
20
+ type: 'text',
21
+ name: 'componentPath',
22
+ message: 'Design component path (e.g. Button/Themes/PrimaryButton):',
23
+ validate: value => value.length > 0 ? true : 'Path cannot be empty'
24
+ });
25
+
26
+ // Parse the path
27
+ const normalizedPath = componentPath.replace(/\\/g, '/');
28
+ const pathParts = normalizedPath.split('/');
29
+ const componentName = pathParts[pathParts.length - 1];
30
+
31
+ // Build the full path: src/app/{context}/ui/design/{path}
32
+ const contextUiPath = path.join(process.cwd(), 'src/app', context, 'ui/design');
33
+ const fullComponentPath = path.join(contextUiPath, normalizedPath);
34
+
35
+ console.log(`\nšŸš€ Generating design component: ${componentName}...\n`);
36
+
37
+ // Create Component.svelte
38
+ await writeIfNotExists(
39
+ path.join(fullComponentPath, 'Component.svelte'),
40
+ designComponentTemplate.replace(/{{componentName}}/g, componentName)
41
+ );
42
+
43
+ // Create style.scss
44
+ await writeIfNotExists(
45
+ path.join(fullComponentPath, 'style.scss'),
46
+ styleTemplate
47
+ );
48
+
49
+ console.log(`āœ… Design component created at: ${fullComponentPath}`);
50
+ console.log(`\nšŸ’” Files created:`);
51
+ console.log(` - Component.svelte`);
52
+ console.log(` - style.scss`);
53
+ }
@@ -0,0 +1,152 @@
1
+ import prompts from 'prompts';
2
+ import path from 'path';
3
+ import {
4
+ selectContext,
5
+ getContextPath,
6
+ toPascalCase,
7
+ toCamelCase,
8
+ getAvailableFiles,
9
+ toKebabCase
10
+ } from '../../utils/contextUtils.js';
11
+ import { writeIfNotExists, updateIndexTs, updateCoreIndex } from '../../utils/fileUtils.js';
12
+
13
+ const entityTemplate = `export interface I{{name}} {
14
+ \tid: number;
15
+ \t// Add entity fields here
16
+ \tcreated_at: string;
17
+ \tupdated_at: string;
18
+ }`;
19
+
20
+ const repositoryTemplate = `import { {{datasource}} } from '{{datasourceImport}}';
21
+
22
+ export class {{name}}Repository {
23
+ \tprivate endpoint = '{{endpoint}}';
24
+ \t
25
+ \tconstructor(private {{datasourceVar}}: {{datasource}}) {}
26
+ \t
27
+ \tpublic async example() {
28
+ \t\treturn this.{{datasourceVar}}.createRequest(({ http }) =>
29
+ \t\t\thttp.get(this.endpoint)
30
+ \t\t).then(res => res.getData());
31
+ \t}
32
+ }`;
33
+
34
+ const serviceTemplate = `import { ClassMirror } from '@azure-net/kit';
35
+ import { {{name}}Repository } from '\${{context}}/infrastructure/http/repositories';
36
+
37
+ export class {{name}}Service extends ClassMirror<{{name}}Repository> {
38
+ \tconstructor(private {{camelName}}Repository: {{name}}Repository) {
39
+ \t\tsuper({{camelName}}Repository);
40
+ \t}
41
+ \t
42
+ \tdeclare example: {{name}}Repository['example'];
43
+ }`;
44
+
45
+ export default async function generateModuleBase() {
46
+ const context = await selectContext('Select context for module base:');
47
+
48
+ const { name } = await prompts({
49
+ type: 'text',
50
+ name: 'name',
51
+ message: 'Module name (PascalCase):'
52
+ });
53
+
54
+ const { endpoint } = await prompts({
55
+ type: 'text',
56
+ name: 'endpoint',
57
+ message: 'API endpoint (e.g. /api/users):'
58
+ });
59
+
60
+ const { needEntity } = await prompts({
61
+ type: 'confirm',
62
+ name: 'needEntity',
63
+ message: 'Create domain entity?',
64
+ initial: true
65
+ });
66
+
67
+ // Get available datasources
68
+ const contextPath = getContextPath(context);
69
+ const coreDatasources = await getAvailableFiles(
70
+ path.join(process.cwd(), 'src/core/datasources')
71
+ );
72
+ const contextDatasources = await getAvailableFiles(
73
+ path.join(contextPath, 'infrastructure/http/datasources')
74
+ );
75
+
76
+ const allDatasources = [
77
+ ...coreDatasources.map(d => ({ title: `${d} (core)`, value: { name: d, from: 'core' } })),
78
+ ...contextDatasources.map(d => ({ title: `${d} (${context})`, value: { name: d, from: context } }))
79
+ ];
80
+
81
+ const { datasource } = await prompts({
82
+ type: 'select',
83
+ name: 'datasource',
84
+ message: 'Select datasource:',
85
+ choices: allDatasources
86
+ });
87
+
88
+ const pascalName = toPascalCase(name);
89
+ const camelName = toCamelCase(name);
90
+ const entityLower = toKebabCase(pascalName);
91
+
92
+ console.log('\nšŸš€ Generating module base (repository & service)...\n');
93
+
94
+ // 1. Create Domain entity if needed
95
+ if (needEntity) {
96
+ const domainPath = path.join(contextPath, 'domain', entityLower);
97
+ const modelPath = path.join(domainPath, 'model');
98
+
99
+ await writeIfNotExists(
100
+ path.join(modelPath, `I${pascalName}.ts`),
101
+ entityTemplate.replace(/{{name}}/g, pascalName)
102
+ );
103
+
104
+ await writeIfNotExists(
105
+ path.join(modelPath, 'index.ts'),
106
+ `export * from './I${pascalName}';`
107
+ );
108
+
109
+ await writeIfNotExists(
110
+ path.join(domainPath, 'index.ts'),
111
+ `export * from './model';`
112
+ );
113
+
114
+ console.log(`āœ… Domain entity I${pascalName} created`);
115
+ }
116
+
117
+ // 2. Create Repository
118
+ const repoPath = path.join(contextPath, 'infrastructure/http/repositories');
119
+ const datasourceImport = datasource.from === 'core'
120
+ ? '$core/datasources'
121
+ : `\$${context}/infrastructure/http/datasources`;
122
+
123
+ await writeIfNotExists(
124
+ path.join(repoPath, `${pascalName}Repository.ts`),
125
+ repositoryTemplate
126
+ .replace(/{{name}}/g, pascalName)
127
+ .replace(/{{endpoint}}/g, endpoint)
128
+ .replace(/{{datasource}}/g, datasource.name)
129
+ .replace(/{{datasourceImport}}/g, datasourceImport)
130
+ .replace(/{{datasourceVar}}/g, toCamelCase(datasource.name))
131
+ );
132
+ await updateIndexTs(repoPath);
133
+
134
+ // 3. Create Service
135
+ const servicePath = path.join(contextPath, 'application/services');
136
+ await writeIfNotExists(
137
+ path.join(servicePath, `${pascalName}Service.ts`),
138
+ serviceTemplate
139
+ .replace(/{{name}}/g, pascalName)
140
+ .replace(/{{camelName}}/g, camelName)
141
+ .replace(/{{context}}/g, context)
142
+ );
143
+ await updateIndexTs(servicePath);
144
+
145
+ // Update core index
146
+ await updateCoreIndex();
147
+
148
+ console.log(`\nāœ… Module base for ${pascalName} created successfully!`);
149
+ console.log(`\nšŸ’” Remember to:`);
150
+ console.log(` 1. Add ${pascalName}Repository to InfrastructureProvider`);
151
+ console.log(` 2. Add ${pascalName}Service to ApplicationProvider`);
152
+ }
@@ -0,0 +1,110 @@
1
+ import prompts from 'prompts';
2
+ import path from 'path';
3
+ import {
4
+ selectContext,
5
+ getContextPath,
6
+ toPascalCase,
7
+ getAvailableFiles,
8
+ getApplicationProviderServices,
9
+ toKebabCase
10
+ } from '../../utils/contextUtils.js';
11
+ import { updateIndexTs, writeIfNotExists, updateCoreIndex } from '../../utils/fileUtils.js';
12
+
13
+ const presenterWithCoreTemplate = `import { {{presenterFactory}} } from '$core/presenters';
14
+ import { ApplicationProvider } from '\${{context}}/application';
15
+
16
+ export const {{name}}Presenter = {{presenterFactory}}('{{name}}Presenter', ({ createAsyncResource, createAsyncAction }) => {
17
+ \tconst { {{serviceName}} } = ApplicationProvider();
18
+ \t
19
+ \t// Add your presenter methods here
20
+ \t
21
+ \treturn {};
22
+ });`;
23
+
24
+ const presenterWithoutCoreTemplate = `import { createPresenter } from '@azure-net/kit';
25
+ import { ApplicationProvider } from '\${{context}}/application';
26
+
27
+ export const {{name}}Presenter = createPresenter('{{name}}Presenter', () => {
28
+ \tconst { {{serviceName}} } = ApplicationProvider();
29
+ \t
30
+ \t// Add your presenter methods here
31
+ \t
32
+ \treturn {};
33
+ });`;
34
+
35
+ export default async function generateModulePresenter() {
36
+ const context = await selectContext('Select context for module presenter:');
37
+
38
+ // Get available services from ApplicationProvider
39
+ const services = await getApplicationProviderServices(context);
40
+
41
+ if (services.length === 0) {
42
+ console.error('āŒ No services found in ApplicationProvider. Add services manually first.');
43
+ return;
44
+ }
45
+
46
+ const { service } = await prompts({
47
+ type: 'select',
48
+ name: 'service',
49
+ message: 'Select service for presenter:',
50
+ choices: services.map(s => ({ title: s, value: s }))
51
+ });
52
+
53
+ const { moduleName } = await prompts({
54
+ type: 'text',
55
+ name: 'moduleName',
56
+ message: 'Module name for presenter (will create folder in delivery):'
57
+ });
58
+
59
+ // Extract entity name from service name
60
+ const pascalName = toPascalCase(moduleName);
61
+ const entityLower = toKebabCase(pascalName);
62
+
63
+ // Get presenter factory
64
+ const corePresenters = await getAvailableFiles(
65
+ path.join(process.cwd(), 'src/core/presenters')
66
+ );
67
+
68
+ const { presenterType } = await prompts({
69
+ type: 'select',
70
+ name: 'presenterType',
71
+ message: 'Select presenter factory:',
72
+ choices: [
73
+ { title: 'Use createPresenter from package', value: 'package' },
74
+ ...corePresenters.map(p => ({ title: `Use ${p} from core`, value: p }))
75
+ ]
76
+ });
77
+
78
+ const contextPath = getContextPath(context);
79
+ const deliveryModulePath = path.join(contextPath, 'delivery', entityLower);
80
+
81
+ console.log('\nšŸš€ Generating module presenter...\n');
82
+
83
+ // Create Presenter
84
+ const presenterTemplate = presenterType === 'package'
85
+ ? presenterWithoutCoreTemplate
86
+ : presenterWithCoreTemplate;
87
+
88
+ const presenterFactory = presenterType === 'package' ? 'createPresenter' : presenterType;
89
+
90
+ await writeIfNotExists(
91
+ path.join(deliveryModulePath, `${pascalName}Presenter.ts`),
92
+ presenterTemplate
93
+ .replace(/{{name}}/g, pascalName)
94
+ .replace(/{{context}}/g, context)
95
+ .replace(/{{serviceName}}/g, service)
96
+ .replace(/{{presenterFactory}}/g, presenterFactory)
97
+ );
98
+
99
+ // Create module index
100
+ await writeIfNotExists(
101
+ path.join(deliveryModulePath, 'index.ts'),
102
+ `export * from './${pascalName}Presenter';`
103
+ );
104
+
105
+ // Update core index
106
+ await updateCoreIndex();
107
+
108
+ console.log(`āœ… Module presenter for ${pascalName} created successfully!`);
109
+ console.log(`\nšŸ’” Remember to add presenter methods using the ${service}.`);
110
+ }
@@ -42,7 +42,7 @@ export default async function generatePresenter() {
42
42
 
43
43
  // Check for core presenters
44
44
  const corePresenters = await getAvailableFiles(
45
- path.join(process.cwd(), 'src/app/core/presenters')
45
+ path.join(process.cwd(), 'src/core/presenters')
46
46
  );
47
47
 
48
48
  const presenterChoices = [
@@ -27,7 +27,7 @@ export default async function generateRepository() {
27
27
  // Get available datasources
28
28
  const contextPath = getContextPath(context);
29
29
  const coreDatasources = await getAvailableFiles(
30
- path.join(process.cwd(), 'src/app/core/datasources')
30
+ path.join(process.cwd(), 'src/core/datasources')
31
31
  );
32
32
  const contextDatasources = await getAvailableFiles(
33
33
  path.join(contextPath, 'infrastructure/http/datasources')
@@ -19,7 +19,7 @@ export default async function generateResponse() {
19
19
 
20
20
  const pascalName = toPascalCase(name);
21
21
  const contextPath = context === 'core'
22
- ? path.join(process.cwd(), 'src/app/core')
22
+ ? path.join(process.cwd(), 'src/core')
23
23
  : getContextPath(context);
24
24
 
25
25
  const responsePath = context === 'core'
@@ -45,7 +45,7 @@ export default async function generateSchema() {
45
45
 
46
46
  // Check for core schemas
47
47
  const coreSchemas = await getAvailableFiles(
48
- path.join(process.cwd(), 'src/app/core/schemas')
48
+ path.join(process.cwd(), 'src/core/schemas')
49
49
  );
50
50
 
51
51
  const choices = [
@@ -0,0 +1,53 @@
1
+ import prompts from 'prompts';
2
+ import path from 'path';
3
+ import { selectContext } from '../../utils/contextUtils.js';
4
+ import { writeIfNotExists } from '../../utils/fileUtils.js';
5
+
6
+ const widgetTemplate = `<script lang="ts">
7
+ \timport './style.scss';
8
+ </script>
9
+
10
+ {{widgetName}}
11
+ `;
12
+
13
+ const styleTemplate = `// Add your styles here
14
+ `;
15
+
16
+ export default async function generateWidget() {
17
+ const context = await selectContext('Select context for widget:');
18
+
19
+ const { widgetPath } = await prompts({
20
+ type: 'text',
21
+ name: 'widgetPath',
22
+ message: 'Widget path (e.g. modals/ConfirmModal):',
23
+ validate: value => value.length > 0 ? true : 'Path cannot be empty'
24
+ });
25
+
26
+ // Parse the path
27
+ const normalizedPath = widgetPath.replace(/\\/g, '/');
28
+ const pathParts = normalizedPath.split('/');
29
+ const widgetName = pathParts[pathParts.length - 1];
30
+
31
+ // Build the full path: src/app/{context}/ui/widgets/{path}
32
+ const contextUiPath = path.join(process.cwd(), 'src/app', context, 'ui/widgets');
33
+ const fullWidgetPath = path.join(contextUiPath, normalizedPath);
34
+
35
+ console.log(`\nšŸš€ Generating widget: ${widgetName}...\n`);
36
+
37
+ // Create Component.svelte
38
+ await writeIfNotExists(
39
+ path.join(fullWidgetPath, 'Component.svelte'),
40
+ widgetTemplate.replace(/{{widgetName}}/g, widgetName)
41
+ );
42
+
43
+ // Create style.scss
44
+ await writeIfNotExists(
45
+ path.join(fullWidgetPath, 'style.scss'),
46
+ styleTemplate
47
+ );
48
+
49
+ console.log(`āœ… Widget created at: ${fullWidgetPath}`);
50
+ console.log(`\nšŸ’” Files created:`);
51
+ console.log(` - Component.svelte`);
52
+ console.log(` - style.scss`);
53
+ }
@@ -6,4 +6,9 @@ export { default as generateSchema } from './generateSchema.js';
6
6
  export { default as generatePresenter } from './generatePresenter.js';
7
7
  export { default as generateModule } from './generateModule.js';
8
8
  export { default as generateCrudBase } from './generateCrudBase.js';
9
- export { default as generateCrudPresenter } from './generateCrudPresenter.js';
9
+ export { default as generateCrudPresenter } from './generateCrudPresenter.js';
10
+ export { default as generateModuleBase } from './generateModuleBase.js';
11
+ export { default as generateModulePresenter } from './generateModulePresenter.js';
12
+ export { default as generateComponent } from './generateComponent.js';
13
+ export { default as generateWidget } from './generateWidget.js';
14
+ export { default as generateDesignComponent } from './generateDesignComponent.js';
@@ -10,11 +10,10 @@ function generateAliases(config) {
10
10
 
11
11
  return Object.fromEntries([
12
12
  ...contexts.flatMap(c => [
13
- [`$${c}`, `./src/app/contexts/${c}/layers`],
14
- [`$${c}/ui`, `./src/app/contexts/${c}/ui`]
13
+ [`$${c}`, `./src/app/${c}/layers`],
14
+ [`$${c}/ui`, `./src/app/${c}/ui`]
15
15
  ]),
16
- ['$shared', './src/app/shared'],
17
- ['$core', './src/app/core']
16
+ ['$core', './src/core']
18
17
  ]);
19
18
  }
20
19
 
@@ -1,7 +1,7 @@
1
1
  import { writeIfNotExists, updateCoreIndex } from '../../utils/fileUtils.js';
2
2
  import path from 'path';
3
3
 
4
- const middlewarePath = path.join(process.cwd(), 'src/app/core/middleware/MiddlewareManager.ts');
4
+ const middlewarePath = path.join(process.cwd(), 'src/core/middleware/MiddlewareManager.ts');
5
5
 
6
6
  const middlewareTemplate = `import { createMiddlewareManager } from '@azure-net/kit';
7
7
 
@@ -10,7 +10,7 @@ export const { clientMiddleware, serverMiddleware } = createMiddlewareManager([]
10
10
  export default async function initMiddleware() {
11
11
  await writeIfNotExists(middlewarePath, middlewareTemplate);
12
12
  await writeIfNotExists(
13
- path.join(process.cwd(), 'src/app/core/middleware/index.ts'),
13
+ path.join(process.cwd(), 'src/core/middleware/index.ts'),
14
14
  `export * from './MiddlewareManager';`
15
15
  );
16
16
 
@@ -1,7 +1,7 @@
1
1
  import {updateCoreIndex, writeIfNotExists} from '../../utils/fileUtils.js';
2
2
  import path from 'path';
3
3
 
4
- const presenterPath = path.join(process.cwd(), 'src/app/core/presenters/AppPresenter.ts');
4
+ const presenterPath = path.join(process.cwd(), 'src/core/presenters/AppPresenter.ts');
5
5
 
6
6
  const presenterTemplate = `import { createPresenterFactory } from '@azure-net/kit/edges';
7
7
  import { createAsyncHelpers, createErrorParser } from '@azure-net/kit';
@@ -14,7 +14,7 @@ export const AppPresenter = createPresenterFactory({ ...AsyncHelpers, handleErro
14
14
  export default async function initPresenter() {
15
15
  await writeIfNotExists(presenterPath, presenterTemplate);
16
16
  await writeIfNotExists(
17
- path.join(process.cwd(), 'src/app/core/presenters/index.ts'),
17
+ path.join(process.cwd(), 'src/core/presenters/index.ts'),
18
18
  `export * from './AppPresenter';`
19
19
  );
20
20
 
@@ -1,7 +1,7 @@
1
1
  import { writeIfNotExists, updateCoreIndex } from '../../utils/fileUtils.js';
2
2
  import path from 'path';
3
3
 
4
- const schemaPath = path.join(process.cwd(), 'src/app/core/schemas/Schema.ts');
4
+ const schemaPath = path.join(process.cwd(), 'src/core/schemas/Schema.ts');
5
5
 
6
6
  const schemaTemplate = `import { createSchemaFactory } from '@azure-net/kit';
7
7
  import { createRules, validationMessagesI18n } from '@azure-net/kit/schema';
@@ -11,7 +11,7 @@ export const Schema = createSchemaFactory(createRules(validationMessagesI18n));`
11
11
  export default async function initSchema() {
12
12
  await writeIfNotExists(schemaPath, schemaTemplate);
13
13
  await writeIfNotExists(
14
- path.join(process.cwd(), 'src/app/core/schemas/index.ts'),
14
+ path.join(process.cwd(), 'src/core/schemas/index.ts'),
15
15
  `export * from './Schema';`
16
16
  );
17
17
 
@@ -3,10 +3,8 @@ import path from 'path';
3
3
  import { loadUserConfig } from '../../utils/loadConfig.js';
4
4
  import { updateCoreIndex } from '../../utils/fileUtils.js';
5
5
 
6
- const APP_ROOT = path.join(process.cwd(), 'src', 'app');
7
- const CONTEXTS_PATH = path.join(APP_ROOT, 'contexts');
8
- const SHARED_PATH = path.join(APP_ROOT, 'shared');
9
- const CORE_PATH = path.join(APP_ROOT, 'core');
6
+ const APP_PATH = path.join(process.cwd(), 'src', 'app');
7
+ const CORE_PATH = path.join(process.cwd(), 'src', 'core');
10
8
 
11
9
  async function createDirIfNotExists(dirPath) {
12
10
  try {
@@ -118,17 +116,14 @@ export default async function initStructure() {
118
116
 
119
117
  console.log('šŸ“¦ Generating architecture...');
120
118
 
121
- // Create contexts
119
+ // Create contexts directly in src/app
122
120
  for (const context of contexts) {
123
- const contextPath = path.join(CONTEXTS_PATH, context);
121
+ const contextPath = path.join(APP_PATH, context);
124
122
  const contextName = context.charAt(0).toUpperCase() + context.slice(1);
125
123
  await createBaseStructure(contextPath, contextName, context);
126
124
  }
127
125
 
128
- // Create empty shared folder
129
- await createDirIfNotExists(SHARED_PATH);
130
-
131
- // Create core structure with all functionality
126
+ // Create core structure with all functionality (in src/core, not src/app/core)
132
127
  await createDirIfNotExists(CORE_PATH);
133
128
  await createDirIfNotExists(path.join(CORE_PATH, 'datasources'));
134
129
  await createDirIfNotExists(path.join(CORE_PATH, 'responses'));
@@ -136,6 +131,7 @@ export default async function initStructure() {
136
131
  await createDirIfNotExists(path.join(CORE_PATH, 'middleware'));
137
132
  await createDirIfNotExists(path.join(CORE_PATH, 'presenters'));
138
133
  await createDirIfNotExists(path.join(CORE_PATH, 'translations'));
134
+ await createDirIfNotExists(path.join(CORE_PATH, 'providers'));
139
135
 
140
136
  // Update core index
141
137
  await updateCoreIndex();
@@ -1,7 +1,7 @@
1
1
  import { writeIfNotExists, updateCoreIndex } from '../../utils/fileUtils.js';
2
2
  import path from 'path';
3
3
 
4
- const translationsPath = path.join(process.cwd(), 'src/app/core/translations');
4
+ const translationsPath = path.join(process.cwd(), 'src/core/translations');
5
5
 
6
6
  const translationProviderTemplate = `import { messages } from './locales';
7
7
  import { createTranslations } from '@azure-net/kit/i18n';
@@ -2,7 +2,10 @@ import fs from 'fs/promises';
2
2
  import path from 'path';
3
3
  import { loadUserConfig } from '../../utils/loadConfig.js';
4
4
 
5
- const CONTEXTS_PATH = path.join(process.cwd(), 'src/app/contexts');
5
+ const APP_PATH = path.join(process.cwd(), 'src/app');
6
+ const OLD_CONTEXTS_PATH = path.join(APP_PATH, 'contexts');
7
+ const OLD_CORE_PATH = path.join(APP_PATH, 'core');
8
+ const NEW_CORE_PATH = path.join(process.cwd(), 'src/core');
6
9
 
7
10
  async function directoryExists(dirPath) {
8
11
  try {
@@ -33,36 +36,87 @@ async function moveDirectory(source, destination) {
33
36
  }
34
37
  }
35
38
 
39
+ async function removeEmptyDir(dirPath) {
40
+ try {
41
+ await fs.rmdir(dirPath);
42
+ console.log(`šŸ—‘ļø Removed empty directory: ${dirPath}`);
43
+ } catch {
44
+ // Directory not empty or doesn't exist
45
+ }
46
+ }
47
+
36
48
  export default async function migrateStructure() {
37
49
  const config = await loadUserConfig();
38
50
  const contexts = config.contexts || ['app'];
39
51
 
40
52
  console.log('šŸ”„ Starting structure migration...\n');
41
- console.log('This will reorganize existing contexts to use layers and ui folders.\n');
53
+ console.log('This will reorganize existing structure to the new format:\n');
54
+ console.log(' - src/app/contexts/{context} -> src/app/{context}');
55
+ console.log(' - src/app/core -> src/core');
56
+ console.log(' - Ensure layers and ui folders exist\n');
57
+
58
+ // Step 1: Migrate core from src/app/core to src/core
59
+ if (await directoryExists(OLD_CORE_PATH)) {
60
+ console.log('šŸ“¦ Migrating core...');
61
+
62
+ // Check if new core already exists
63
+ if (await directoryExists(NEW_CORE_PATH)) {
64
+ console.log('āš ļø Core already exists at src/core, skipping core migration...');
65
+ } else {
66
+ await moveDirectory(OLD_CORE_PATH, NEW_CORE_PATH);
67
+ }
68
+ }
42
69
 
70
+ // Step 2: Migrate contexts
43
71
  for (const context of contexts) {
44
- const contextPath = path.join(CONTEXTS_PATH, context);
72
+ console.log(`\nšŸ“ Migrating context: ${context}`);
73
+
74
+ const oldContextPath = path.join(OLD_CONTEXTS_PATH, context);
75
+ const newContextPath = path.join(APP_PATH, context);
76
+
77
+ // Check if context exists in old location (src/app/contexts/{context})
78
+ if (await directoryExists(oldContextPath)) {
79
+ // Check if new location already exists
80
+ if (await directoryExists(newContextPath)) {
81
+ console.log(`āš ļø Context '${context}' already exists at src/app/${context}, skipping...`);
82
+ continue;
83
+ }
84
+
85
+ // Move from contexts/{context} to app/{context}
86
+ await moveDirectory(oldContextPath, newContextPath);
87
+ }
88
+
89
+ // Now ensure the context has layers and ui structure
90
+ const contextPath = newContextPath;
45
91
 
46
- // Check if context exists
47
92
  if (!(await directoryExists(contextPath))) {
48
93
  console.log(`āš ļø Context '${context}' does not exist, skipping...`);
49
94
  continue;
50
95
  }
51
96
 
52
- console.log(`\nšŸ“ Migrating context: ${context}`);
53
-
54
- // Check if already migrated (has layers folder)
55
97
  const layersPath = path.join(contextPath, 'layers');
98
+ const uiPath = path.join(contextPath, 'ui');
99
+
100
+ // Check if already has layers structure
56
101
  if (await directoryExists(layersPath)) {
57
- console.log(`āš ļø Context '${context}' already migrated, skipping...`);
102
+ console.log(`āœ“ Context '${context}' already has layers structure`);
103
+
104
+ // Just ensure ui folder exists
105
+ if (!(await directoryExists(uiPath))) {
106
+ await fs.mkdir(uiPath, { recursive: true });
107
+ console.log(`āœ… Created: ${uiPath}`);
108
+ }
109
+
58
110
  continue;
59
111
  }
60
112
 
61
- // Create layers and ui folders
113
+ // Need to create layers structure
114
+ console.log(`šŸ“¦ Creating layers structure for '${context}'...`);
115
+
62
116
  await fs.mkdir(layersPath, { recursive: true });
63
- await fs.mkdir(path.join(contextPath, 'ui'), { recursive: true });
117
+ await fs.mkdir(uiPath, { recursive: true });
64
118
  console.log(`āœ… Created: ${layersPath}`);
65
- console.log(`āœ… Created: ${path.join(contextPath, 'ui')}`);
119
+ console.log(`āœ… Created: ${uiPath}`);
66
120
 
67
121
  // Move existing layer folders to layers directory
68
122
  const layerFolders = ['domain', 'infrastructure', 'application', 'delivery'];
@@ -77,8 +131,14 @@ export default async function migrateStructure() {
77
131
  console.log(`āœ… Context '${context}' migration completed!`);
78
132
  }
79
133
 
134
+ // Step 3: Clean up old contexts folder if empty
135
+ if (await directoryExists(OLD_CONTEXTS_PATH)) {
136
+ await removeEmptyDir(OLD_CONTEXTS_PATH);
137
+ }
138
+
80
139
  console.log('\nāœ… Structure migration complete!');
81
140
  console.log('\nšŸ’” Next steps:');
82
141
  console.log(' 1. Run "azure-net init:aliases" to update path aliases');
83
142
  console.log(' 2. Verify all imports are working correctly');
143
+ console.log(' 3. Update any hardcoded paths in your code');
84
144
  }
@@ -3,8 +3,8 @@ import path from 'path';
3
3
  import prompts from 'prompts';
4
4
  import { loadUserConfig } from './loadConfig.js';
5
5
 
6
- const CONTEXTS_PATH = path.join(process.cwd(), 'src/app/contexts');
7
- const CORE_PATH = path.join(process.cwd(), 'src/app/core');
6
+ const APP_PATH = path.join(process.cwd(), 'src/app');
7
+ const CORE_PATH = path.join(process.cwd(), 'src/core');
8
8
 
9
9
  export async function selectContext(message = 'Select context:') {
10
10
  const config = await loadUserConfig();
@@ -26,7 +26,7 @@ export async function selectContext(message = 'Select context:') {
26
26
  export function getContextPath(context) {
27
27
  return context === 'core'
28
28
  ? CORE_PATH
29
- : path.join(CONTEXTS_PATH, context, 'layers');
29
+ : path.join(APP_PATH, context, 'layers');
30
30
  }
31
31
 
32
32
  export async function getAvailableFiles(dir, pattern = '.ts') {
@@ -29,7 +29,7 @@ export async function updateIndexTs(dir, filePattern = '.ts', ignore = ['index.t
29
29
  }
30
30
 
31
31
  export async function updateCoreIndex() {
32
- const corePath = path.join(process.cwd(), 'src/app/core');
32
+ const corePath = path.join(process.cwd(), 'src/core');
33
33
  try {
34
34
  const dirs = await fs.readdir(corePath, { withFileTypes: true });
35
35
  const validDirs = [];