@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 +31 -1
- package/package.json +1 -1
- package/src/commands/generate/generateComponent.js +53 -0
- package/src/commands/generate/generateCrudBase.js +1 -1
- package/src/commands/generate/generateCrudPresenter.js +2 -2
- package/src/commands/generate/generateDatasource.js +2 -2
- package/src/commands/generate/generateDesignComponent.js +53 -0
- package/src/commands/generate/generateModuleBase.js +152 -0
- package/src/commands/generate/generateModulePresenter.js +110 -0
- package/src/commands/generate/generatePresenter.js +1 -1
- package/src/commands/generate/generateRepository.js +1 -1
- package/src/commands/generate/generateResponse.js +1 -1
- package/src/commands/generate/generateSchema.js +1 -1
- package/src/commands/generate/generateWidget.js +53 -0
- package/src/commands/generate/index.js +6 -1
- package/src/commands/init/initAliases.js +3 -4
- package/src/commands/init/initMiddleware.js +2 -2
- package/src/commands/init/initPresenter.js +2 -2
- package/src/commands/init/initSchema.js +2 -2
- package/src/commands/init/initStructure.js +6 -10
- package/src/commands/init/initTranslations.js +1 -1
- package/src/commands/init/migrateStructure.js +71 -11
- package/src/utils/contextUtils.js +3 -3
- package/src/utils/fileUtils.js +1 -1
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
|
@@ -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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
22
|
+
? path.join(process.cwd(), 'src/core')
|
|
23
23
|
: getContextPath(context);
|
|
24
24
|
|
|
25
25
|
const responsePath = 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 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
|
|
14
|
-
[`$${c}/ui`, `./src/app
|
|
13
|
+
[`$${c}`, `./src/app/${c}/layers`],
|
|
14
|
+
[`$${c}/ui`, `./src/app/${c}/ui`]
|
|
15
15
|
]),
|
|
16
|
-
['$
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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
|
|
7
|
-
const
|
|
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(
|
|
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
|
|
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/
|
|
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
|
|
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
|
|
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
|
-
|
|
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(
|
|
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
|
-
//
|
|
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(
|
|
117
|
+
await fs.mkdir(uiPath, { recursive: true });
|
|
64
118
|
console.log(`ā
Created: ${layersPath}`);
|
|
65
|
-
console.log(`ā
Created: ${
|
|
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
|
|
7
|
-
const CORE_PATH = path.join(process.cwd(), 'src/
|
|
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(
|
|
29
|
+
: path.join(APP_PATH, context, 'layers');
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
export async function getAvailableFiles(dir, pattern = '.ts') {
|
package/src/utils/fileUtils.js
CHANGED
|
@@ -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/
|
|
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 = [];
|