@azure-net/cli 1.4.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/azure-net.js +83 -32
- package/package.json +1 -1
- package/src/commands/generate/generateCrud.js +323 -0
- package/src/commands/generate/generateDatasource.js +36 -0
- package/src/commands/generate/generateModule.js +23 -0
- package/src/commands/generate/generatePresenter.js +113 -0
- package/src/commands/generate/generateRepository.js +97 -0
- package/src/commands/generate/generateResponse.js +42 -0
- package/src/commands/generate/generateSchema.js +70 -0
- package/src/commands/generate/generateService.js +93 -0
- package/src/commands/generate/index.js +8 -0
- package/src/commands/init/index.js +6 -0
- package/src/commands/init/initAliases.js +50 -0
- package/src/commands/init/initEdges.js +42 -0
- package/src/commands/init/initMiddleware.js +58 -0
- package/src/commands/init/initSchema.js +19 -0
- package/src/commands/init/initStructure.js +68 -0
- package/src/commands/init/initTranslations.js +97 -0
- package/src/templates/domain/request/ClassRequest.ejs +8 -0
- package/src/utils/contextUtils.js +53 -0
- package/src/utils/fileUtils.js +60 -0
- package/src/utils/loadConfig.js +2 -2
- package/src/utils/providerUtils.js +78 -0
- package/.idea/azure-net-ecosystem-cli.iml +0 -9
- package/.idea/modules.xml +0 -8
- package/src/commands/generateCrud.js +0 -135
- package/src/commands/generateDatasource.js +0 -44
- package/src/commands/generateRepo.js +0 -69
- package/src/commands/generateService.js +0 -77
- package/src/commands/generateStructure.js +0 -65
- package/src/commands/initAliases.js +0 -101
- package/src/commands/initLint.js +0 -138
|
@@ -0,0 +1,97 @@
|
|
|
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 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/Datasources')
|
|
38
|
+
);
|
|
39
|
+
const contextDatasources = await getAvailableFiles(
|
|
40
|
+
path.join(contextPath, 'Infrastructure', 'Datasources')
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const allDatasources = [
|
|
44
|
+
...coreDatasources.map(d => ({ title: `${d}Datasource (core)`, value: { name: `${d}Datasource`, from: 'core' } })),
|
|
45
|
+
...contextDatasources.map(d => ({ title: `${d}Datasource (${context})`, value: { name: `${d}Datasource`, 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 repoPath = path.join(contextPath, 'Infrastructure', 'Repositories');
|
|
62
|
+
const filePath = path.join(repoPath, `${pascalName}Repository.ts`);
|
|
63
|
+
|
|
64
|
+
// Generate repository
|
|
65
|
+
const datasourceImport = datasource.from === 'core'
|
|
66
|
+
? '$core/Datasources/index.js'
|
|
67
|
+
: '../Datasources/index.js';
|
|
68
|
+
|
|
69
|
+
const content = repositoryTemplate
|
|
70
|
+
.replace(/{{name}}/g, pascalName)
|
|
71
|
+
.replace(/{{datasource}}/g, datasource.name)
|
|
72
|
+
.replace(/{{datasourceImport}}/g, datasourceImport)
|
|
73
|
+
.replace(/{{datasourceVar}}/g, toPascalCase(datasource.name).charAt(0).toLowerCase() + toPascalCase(datasource.name).slice(1));
|
|
74
|
+
|
|
75
|
+
await writeIfNotExists(filePath, content);
|
|
76
|
+
await updateIndexTs(repoPath);
|
|
77
|
+
|
|
78
|
+
// Ensure DatasourceProvider exists
|
|
79
|
+
const datasourceProvider = await ensureProvider(context, 'Infrastructure', { datasource: datasource.name });
|
|
80
|
+
|
|
81
|
+
// Ensure InfrastructureProvider exists and add repository
|
|
82
|
+
const infraProvider = await ensureProvider(context, 'Infrastructure', { datasource: datasource.name });
|
|
83
|
+
await addToProvider(
|
|
84
|
+
infraProvider.path,
|
|
85
|
+
`${pascalName}Repository`,
|
|
86
|
+
'../Repositories/index.js'
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
// Add datasource dependency to repository in provider
|
|
90
|
+
let providerContent = await fs.readFile(infraProvider.path, 'utf-8');
|
|
91
|
+
const repoFactory = `${pascalName}Repository: () => new ${pascalName}Repository()`;
|
|
92
|
+
const repoWithDatasource = `${pascalName}Repository: () => new ${pascalName}Repository(DatasourceProvider.${datasource.name})`;
|
|
93
|
+
providerContent = providerContent.replace(repoFactory, repoWithDatasource);
|
|
94
|
+
await fs.writeFile(infraProvider.path, providerContent, 'utf-8');
|
|
95
|
+
|
|
96
|
+
console.log(`✅ Repository created at ${filePath}`);
|
|
97
|
+
}
|
|
@@ -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,70 @@
|
|
|
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/Schemas/index.js';
|
|
7
|
+
import type { I{{name}}Request } from '../../Domain/Ports/{{name}}/index.js';
|
|
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 { schema } from '@azure-net/kit';
|
|
16
|
+
import type { I{{name}}Request } from '../../Domain/Ports/{{name}}/index.js';
|
|
17
|
+
|
|
18
|
+
export const {{name}}Schema = schema<I{{name}}Request>()
|
|
19
|
+
\t.rules((rules) => ({
|
|
20
|
+
\t\t// Add validation rules here
|
|
21
|
+
\t}))
|
|
22
|
+
\t.create();`;
|
|
23
|
+
|
|
24
|
+
export default async function generateSchema() {
|
|
25
|
+
const context = await selectContext('Select context for schema:');
|
|
26
|
+
|
|
27
|
+
if (context === 'core') {
|
|
28
|
+
console.error('❌ Cannot create schema in core. Choose a specific context.');
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const { name } = await prompts({
|
|
33
|
+
type: 'text',
|
|
34
|
+
name: 'name',
|
|
35
|
+
message: 'Schema name (without "Schema" suffix):'
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Check for core schemas
|
|
39
|
+
const coreSchemas = await getAvailableFiles(
|
|
40
|
+
path.join(process.cwd(), 'src/app/core/Schemas')
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const choices = [
|
|
44
|
+
{ title: 'Use schema from package', value: 'package' },
|
|
45
|
+
...coreSchemas.map(s => ({ title: `Use ${s} from core`, value: s }))
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
const { schemaType } = await prompts({
|
|
49
|
+
type: 'select',
|
|
50
|
+
name: 'schemaType',
|
|
51
|
+
message: 'Select schema factory:',
|
|
52
|
+
choices
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const pascalName = toPascalCase(name);
|
|
56
|
+
const contextPath = getContextPath(context);
|
|
57
|
+
const schemaPath = path.join(contextPath, 'Delivery', 'Schemas');
|
|
58
|
+
const filePath = path.join(schemaPath, `${pascalName}Schema.ts`);
|
|
59
|
+
|
|
60
|
+
const content = schemaType === 'package'
|
|
61
|
+
? schemaWithPackageTemplate.replace(/{{name}}/g, pascalName)
|
|
62
|
+
: schemaWithCoreTemplate
|
|
63
|
+
.replace(/{{name}}/g, pascalName)
|
|
64
|
+
.replace(/{{coreSchema}}/g, schemaType);
|
|
65
|
+
|
|
66
|
+
await writeIfNotExists(filePath, content);
|
|
67
|
+
await updateIndexTs(schemaPath);
|
|
68
|
+
|
|
69
|
+
console.log(`✅ Schema created at ${filePath}`);
|
|
70
|
+
}
|
|
@@ -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,6 @@
|
|
|
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';
|
|
@@ -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,58 @@
|
|
|
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, type IMiddleware } from '@azure-net/kit';
|
|
9
|
+
|
|
10
|
+
const AuthMiddleware: IMiddleware = async ({ next, page, event, isServer, cookies }) => {
|
|
11
|
+
\tconst user = isServer ? event?.locals?.user : page?.data?.user;
|
|
12
|
+
\tif (isServer && !user && cookies.get('token') && event) {
|
|
13
|
+
\t\t// Add auth logic here
|
|
14
|
+
\t}
|
|
15
|
+
\tnext();
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const GuardMiddleware: IMiddleware = async ({ next, page, event, isServer, to }) => {
|
|
19
|
+
\tconst user = isServer ? event?.locals?.user : page?.data?.user;
|
|
20
|
+
\tif (!user && !to.pathname.startsWith('/login')) {
|
|
21
|
+
\t\tnext('/login');
|
|
22
|
+
\t}
|
|
23
|
+
\tif (user && to.pathname.startsWith('/login')) {
|
|
24
|
+
\t\tnext('/');
|
|
25
|
+
\t}
|
|
26
|
+
\tnext();
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const { clientMiddleware, serverMiddleware } = createMiddlewareManager([AuthMiddleware, GuardMiddleware]);`;
|
|
30
|
+
|
|
31
|
+
export default async function initMiddleware() {
|
|
32
|
+
await writeIfNotExists(middlewarePath, middlewareTemplate);
|
|
33
|
+
|
|
34
|
+
// Add to hooks.server.ts
|
|
35
|
+
await injectIntoFile(
|
|
36
|
+
hooksServerPath,
|
|
37
|
+
`import { serverMiddleware } from '$core/Middleware/index.js';`,
|
|
38
|
+
'import',
|
|
39
|
+
'before'
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
await injectIntoFile(
|
|
43
|
+
hooksServerPath,
|
|
44
|
+
'async ({ edgesEvent, serialize }) => {',
|
|
45
|
+
'\t\t\tawait serverMiddleware();',
|
|
46
|
+
'after'
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
// Add to +layout.svelte
|
|
50
|
+
await injectIntoFile(
|
|
51
|
+
layoutPath,
|
|
52
|
+
'<script',
|
|
53
|
+
`\timport { clientMiddleware } from '$core/Middleware/index.js';\n\tclientMiddleware();`,
|
|
54
|
+
'after'
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
console.log('✅ Middleware initialized');
|
|
58
|
+
}
|
|
@@ -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/schema';
|
|
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.js';`
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
console.log('✅ Schema factory initialized');
|
|
19
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { loadUserConfig } from '../../utils/loadConfig.js';
|
|
4
|
+
|
|
5
|
+
const BASE_STRUCTURE = ['Domain', 'Infrastructure', 'Application', 'Delivery'];
|
|
6
|
+
const APP_ROOT = path.join(process.cwd(), 'src', 'app');
|
|
7
|
+
const CONTEXTS_PATH = path.join(APP_ROOT, 'contexts');
|
|
8
|
+
const CORE_PATH = path.join(APP_ROOT, 'core');
|
|
9
|
+
|
|
10
|
+
async function createDirIfNotExists(dirPath) {
|
|
11
|
+
try {
|
|
12
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
13
|
+
console.log(`📁 Created: ${dirPath}`);
|
|
14
|
+
} catch (e) {
|
|
15
|
+
console.error(`❌ Failed to create ${dirPath}:`, e.message);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async function createBaseStructure(root) {
|
|
20
|
+
for (const section of BASE_STRUCTURE) {
|
|
21
|
+
const sectionPath = path.join(root, section);
|
|
22
|
+
await createDirIfNotExists(sectionPath);
|
|
23
|
+
|
|
24
|
+
if (section === 'Infrastructure') {
|
|
25
|
+
await createDirIfNotExists(path.join(sectionPath, 'Repositories'));
|
|
26
|
+
await createDirIfNotExists(path.join(sectionPath, 'Datasources'));
|
|
27
|
+
await createDirIfNotExists(path.join(sectionPath, 'Providers'));
|
|
28
|
+
}
|
|
29
|
+
if (section === 'Application') {
|
|
30
|
+
await createDirIfNotExists(path.join(sectionPath, 'Services'));
|
|
31
|
+
await createDirIfNotExists(path.join(sectionPath, 'Providers'));
|
|
32
|
+
}
|
|
33
|
+
if (section === 'Domain') {
|
|
34
|
+
await createDirIfNotExists(path.join(sectionPath, 'Entities'));
|
|
35
|
+
await createDirIfNotExists(path.join(sectionPath, 'Ports'));
|
|
36
|
+
}
|
|
37
|
+
if (section === 'Delivery') {
|
|
38
|
+
await createDirIfNotExists(path.join(sectionPath, 'Presenters'));
|
|
39
|
+
await createDirIfNotExists(path.join(sectionPath, 'Schemas'));
|
|
40
|
+
await createDirIfNotExists(path.join(sectionPath, 'Actions'));
|
|
41
|
+
await createDirIfNotExists(path.join(sectionPath, 'Stores'));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export default async function initStructure() {
|
|
47
|
+
const config = await loadUserConfig();
|
|
48
|
+
const contexts = config.contexts || ['app'];
|
|
49
|
+
|
|
50
|
+
console.log('📦 Generating architecture...');
|
|
51
|
+
|
|
52
|
+
// Create contexts
|
|
53
|
+
for (const context of contexts) {
|
|
54
|
+
const contextPath = path.join(CONTEXTS_PATH, context);
|
|
55
|
+
await createBaseStructure(contextPath);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Create core structure
|
|
59
|
+
await createDirIfNotExists(CORE_PATH);
|
|
60
|
+
await createDirIfNotExists(path.join(CORE_PATH, 'Datasources'));
|
|
61
|
+
await createDirIfNotExists(path.join(CORE_PATH, 'Responses'));
|
|
62
|
+
await createDirIfNotExists(path.join(CORE_PATH, 'Schemas'));
|
|
63
|
+
await createDirIfNotExists(path.join(CORE_PATH, 'Middleware'));
|
|
64
|
+
await createDirIfNotExists(path.join(CORE_PATH, 'Presenters'));
|
|
65
|
+
await createDirIfNotExists(path.join(CORE_PATH, 'Translations'));
|
|
66
|
+
|
|
67
|
+
console.log('✅ Structure initialization complete!');
|
|
68
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { writeIfNotExists, updateIndexTs, injectIntoFile } from '../../utils/fileUtils.js';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
const translationsPath = path.join(process.cwd(), 'src/app/core/Translations');
|
|
5
|
+
const layoutServerPath = path.join(process.cwd(), 'src/routes/+layout.server.ts');
|
|
6
|
+
const layoutTsPath = path.join(process.cwd(), 'src/routes/+layout.ts');
|
|
7
|
+
|
|
8
|
+
const translationProviderTemplate = `import { messages } from './Locales/index.js';
|
|
9
|
+
import { createTranslations } from '@azure-net/kit/i18n';
|
|
10
|
+
|
|
11
|
+
export const Translation = createTranslations({
|
|
12
|
+
\tmessages,
|
|
13
|
+
\tinitLang: 'en',
|
|
14
|
+
\tinitLangFromAcceptLanguage: true,
|
|
15
|
+
\tcookieName: 'lang'
|
|
16
|
+
});`;
|
|
17
|
+
|
|
18
|
+
const enLocaleTemplate = `export default {
|
|
19
|
+
\tapp: {
|
|
20
|
+
\t\ttitle: 'Application'
|
|
21
|
+
\t}
|
|
22
|
+
};`;
|
|
23
|
+
|
|
24
|
+
const ruLocaleTemplate = `export default {
|
|
25
|
+
\tapp: {
|
|
26
|
+
\t\ttitle: 'Приложение'
|
|
27
|
+
\t}
|
|
28
|
+
};`;
|
|
29
|
+
|
|
30
|
+
const localesIndexTemplate = `export const messages = {
|
|
31
|
+
\ten: () => import('./en.js').then((res) => res.default),
|
|
32
|
+
\tru: () => import('./ru.js').then((res) => res.default)
|
|
33
|
+
};`;
|
|
34
|
+
|
|
35
|
+
export default async function initTranslations() {
|
|
36
|
+
// Create translation files
|
|
37
|
+
await writeIfNotExists(
|
|
38
|
+
path.join(translationsPath, 'index.ts'),
|
|
39
|
+
translationProviderTemplate
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
await writeIfNotExists(
|
|
43
|
+
path.join(translationsPath, 'Locales', 'en.ts'),
|
|
44
|
+
enLocaleTemplate
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
await writeIfNotExists(
|
|
48
|
+
path.join(translationsPath, 'Locales', 'ru.ts'),
|
|
49
|
+
ruLocaleTemplate
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
await writeIfNotExists(
|
|
53
|
+
path.join(translationsPath, 'Locales', 'index.ts'),
|
|
54
|
+
localesIndexTemplate
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
await updateIndexTs(translationsPath);
|
|
58
|
+
|
|
59
|
+
// Add to hooks.server.ts
|
|
60
|
+
await injectIntoFile(
|
|
61
|
+
path.join(process.cwd(), 'src/hooks.server.ts'),
|
|
62
|
+
'import',
|
|
63
|
+
`import { Translation } from '$core/Translations/index.js';`,
|
|
64
|
+
'before'
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
await injectIntoFile(
|
|
68
|
+
path.join(process.cwd(), 'src/hooks.server.ts'),
|
|
69
|
+
'await serverMiddleware();',
|
|
70
|
+
`\t\t\tconst { preloadTranslation, applyHtmlLocaleAttr } = Translation();\n\t\t\tawait preloadTranslation(edgesEvent);`,
|
|
71
|
+
'after'
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
// Add to layout files
|
|
75
|
+
await injectIntoFile(
|
|
76
|
+
layoutServerPath,
|
|
77
|
+
'export const load',
|
|
78
|
+
`\treturn { lang: locals.lang, user: locals.user };`,
|
|
79
|
+
'after'
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
await injectIntoFile(
|
|
83
|
+
layoutTsPath,
|
|
84
|
+
'import',
|
|
85
|
+
`import { Translation } from '$core/Translations/index.js';`,
|
|
86
|
+
'before'
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
await injectIntoFile(
|
|
90
|
+
layoutTsPath,
|
|
91
|
+
'export const load',
|
|
92
|
+
`\tconst { syncTranslation } = Translation();\n\tif (browser) {\n\t\tawait syncTranslation({ lang: data.lang }, false);\n\t}`,
|
|
93
|
+
'after'
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
console.log('✅ Translations initialized');
|
|
97
|
+
}
|