@azure-net/cli 1.2.10 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/azure-net.js
CHANGED
|
@@ -4,6 +4,8 @@ import { Command } from 'commander';
|
|
|
4
4
|
import generateRepository from '../src/commands/generateCrudRepo.js';
|
|
5
5
|
import generateCrud from '../src/commands/generateCrud.js';
|
|
6
6
|
import initLint from '../src/commands/initLint.js';
|
|
7
|
+
import initStructure from '../src/commands/generateStructure.js';
|
|
8
|
+
import initAliases from '../src/commands/initAliases.js';
|
|
7
9
|
|
|
8
10
|
const program = new Command();
|
|
9
11
|
|
|
@@ -26,4 +28,14 @@ program
|
|
|
26
28
|
.description('Setup linting and commit tools')
|
|
27
29
|
.action(initLint)
|
|
28
30
|
|
|
31
|
+
program
|
|
32
|
+
.command('init:structure')
|
|
33
|
+
.description('Generate base folder structure based on config')
|
|
34
|
+
.action(initStructure);
|
|
35
|
+
|
|
36
|
+
program
|
|
37
|
+
.command('init:aliases')
|
|
38
|
+
.description('Generate alias mappings for modules or default architecture')
|
|
39
|
+
.action(initAliases);
|
|
40
|
+
|
|
29
41
|
program.parse();
|
package/package.json
CHANGED
|
@@ -17,98 +17,83 @@ async function writeIfNotExists(filepath, content) {
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
async function updateIndexTs(dir, filePattern = '.ts', ignore = ['index.ts']) {
|
|
21
|
+
const files = (await fs.readdir(dir)).filter(f => f.endsWith(filePattern) && !ignore.includes(f));
|
|
22
|
+
const content = files.map(f => `export * from './${f.replace('.ts', '')}';`).join('\n') + '\n';
|
|
23
|
+
await fs.writeFile(path.join(dir, 'index.ts'), content, 'utf-8');
|
|
24
|
+
}
|
|
25
|
+
|
|
20
26
|
export default async function generateCrud() {
|
|
21
27
|
const config = await loadUserConfig();
|
|
22
28
|
|
|
23
29
|
const answers = await prompts([
|
|
30
|
+
config.modules?.length
|
|
31
|
+
? {
|
|
32
|
+
type: 'select',
|
|
33
|
+
name: 'module',
|
|
34
|
+
message: 'Select target module:',
|
|
35
|
+
choices: config.modules.map(m => ({ title: m, value: m }))
|
|
36
|
+
}
|
|
37
|
+
: null,
|
|
24
38
|
{ type: 'text', name: 'className', message: 'Class name (PascalCase):' },
|
|
25
39
|
{ type: 'text', name: 'endpoint', message: 'API endpoint:' },
|
|
26
40
|
{ type: 'text', name: 'datasource', message: 'Datasource name:', initial: 'BaseDatasource' }
|
|
27
|
-
]);
|
|
41
|
+
].filter(Boolean));
|
|
28
42
|
|
|
29
43
|
const rawName = answers.className.trim();
|
|
30
44
|
const capital = rawName[0].toUpperCase() + rawName.slice(1);
|
|
31
45
|
const lower = rawName[0].toLowerCase() + rawName.slice(1);
|
|
32
46
|
const endpoint = answers.endpoint.trim();
|
|
33
47
|
const datasource = answers.datasource.trim();
|
|
48
|
+
const selectedModule = answers.module;
|
|
34
49
|
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
const repoPath = path.join(process.cwd(), config.output.repo);
|
|
50
|
+
const baseArch = path.join(process.cwd(), 'src/app/context');
|
|
51
|
+
const basePath = selectedModule ? path.join(baseArch, selectedModule) : baseArch;
|
|
38
52
|
|
|
39
|
-
|
|
53
|
+
const domainPath = path.join(basePath, 'domain', lower);
|
|
54
|
+
const serviceDir = path.join(basePath, 'application', 'services');
|
|
55
|
+
const repoPath = path.join(basePath, 'infra', 'repo');
|
|
56
|
+
|
|
57
|
+
// === 1) Abstracts
|
|
40
58
|
const abstractsDir = path.join(domainPath, 'abstracts');
|
|
41
59
|
for (const file of ['Class', 'ClassCreateRequest', 'ClassUpdateRequest']) {
|
|
42
60
|
const tpl = await fs.readFile(path.join(__dirname, `../templates/domain/abstracts/${file}.ejs`), 'utf-8');
|
|
43
61
|
const result = ejs.render(tpl, { className: capital });
|
|
44
62
|
await writeIfNotExists(path.join(abstractsDir, `${capital}${file.replace('Class', '')}.ts`), result);
|
|
45
63
|
}
|
|
46
|
-
await
|
|
47
|
-
path.join(abstractsDir, `index.ts`),
|
|
48
|
-
[
|
|
49
|
-
`export * from './${capital}';`,
|
|
50
|
-
`export * from './${capital}CreateRequest';`,
|
|
51
|
-
`export * from './${capital}UpdateRequest';`
|
|
52
|
-
].join('\n')
|
|
53
|
-
);
|
|
64
|
+
await updateIndexTs(abstractsDir);
|
|
54
65
|
|
|
55
|
-
// 2) Request
|
|
66
|
+
// === 2) Request
|
|
56
67
|
const requestDir = path.join(domainPath, 'request');
|
|
57
68
|
for (const file of ['ClassCreateRequest', 'ClassUpdateRequest']) {
|
|
58
69
|
const tpl = await fs.readFile(path.join(__dirname, `../templates/domain/request/${file}.ejs`), 'utf-8');
|
|
59
70
|
const result = ejs.render(tpl, { className: capital });
|
|
60
71
|
await writeIfNotExists(path.join(requestDir, `${capital}${file.replace('Class', '')}.ts`), result);
|
|
61
72
|
}
|
|
62
|
-
await
|
|
63
|
-
path.join(requestDir, `index.ts`),
|
|
64
|
-
[
|
|
65
|
-
`export * from './${capital}CreateRequest';`,
|
|
66
|
-
`export * from './${capital}UpdateRequest';`
|
|
67
|
-
].join('\n')
|
|
68
|
-
);
|
|
73
|
+
await updateIndexTs(requestDir);
|
|
69
74
|
|
|
70
|
-
// === 3) Services
|
|
71
|
-
const serviceDir = path.join(domainPath, 'services');
|
|
75
|
+
// === 3) Services
|
|
72
76
|
const serviceTpl = await fs.readFile(path.join(__dirname, '../templates/domain/services/ClassService.ejs'), 'utf-8');
|
|
73
|
-
const serviceResult = ejs.render(serviceTpl, {
|
|
74
|
-
className: capital,
|
|
75
|
-
domainName: lower
|
|
76
|
-
});
|
|
77
|
+
const serviceResult = ejs.render(serviceTpl, { className: capital, domainName: lower });
|
|
77
78
|
await writeIfNotExists(path.join(serviceDir, `${capital}Service.ts`), serviceResult);
|
|
79
|
+
await updateIndexTs(serviceDir);
|
|
78
80
|
|
|
79
|
-
//
|
|
80
|
-
await writeIfNotExists(
|
|
81
|
-
path.join(serviceDir, 'index.ts'),
|
|
82
|
-
`export * from './${capital}Service';\n`
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
// === 4) Domain Index ===
|
|
81
|
+
// === 4) Domain Index
|
|
86
82
|
await writeIfNotExists(
|
|
87
83
|
path.join(domainPath, 'index.ts'),
|
|
88
|
-
[
|
|
89
|
-
`export * from './abstracts';`,
|
|
90
|
-
`export * from './request';`,
|
|
91
|
-
`export * from './services';`
|
|
92
|
-
].join('\n')
|
|
84
|
+
[`export * from './abstracts';`, `export * from './request';`].join('\n') + '\n'
|
|
93
85
|
);
|
|
94
86
|
|
|
95
|
-
// === 5)
|
|
87
|
+
// === 5) Repo
|
|
96
88
|
const repoTpl = await fs.readFile(path.join(__dirname, '../templates/data/repo/ClassRepo.ejs'), 'utf-8');
|
|
97
89
|
const repoResult = ejs.render(repoTpl, {
|
|
98
90
|
className: capital,
|
|
99
91
|
endpoint,
|
|
100
92
|
domainName: lower,
|
|
101
|
-
datasource
|
|
93
|
+
datasource
|
|
102
94
|
});
|
|
103
95
|
await writeIfNotExists(path.join(repoPath, `${capital}Repo.ts`), repoResult);
|
|
96
|
+
await updateIndexTs(repoPath);
|
|
104
97
|
|
|
105
|
-
|
|
106
|
-
const files = await fs.readdir(repoPath);
|
|
107
|
-
const exports = files
|
|
108
|
-
.filter(f => f.endsWith('Repo.ts') && f !== 'index.ts')
|
|
109
|
-
.map(f => `export * from './${f.replace('.ts', '')}';`)
|
|
110
|
-
.join('\n');
|
|
111
|
-
await fs.writeFile(path.join(repoPath, 'index.ts'), exports, 'utf-8');
|
|
112
|
-
|
|
113
|
-
console.log(`✅ CRUD for ${capital} generated successfully!`);
|
|
98
|
+
console.log(`✅ CRUD for ${capital} generated in ${selectedModule || 'monolith'} structure`);
|
|
114
99
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { loadUserConfig } from '../utils/loadConfig.js';
|
|
4
|
+
|
|
5
|
+
const BASE_STRUCTURE = ['domain', 'infra', 'application', 'presentation'];
|
|
6
|
+
const APP_ROOT = path.join(process.cwd(), 'src', 'app');
|
|
7
|
+
const ARCHITECTURE_PATH = path.join(APP_ROOT, 'architecture');
|
|
8
|
+
|
|
9
|
+
async function createDirIfNotExists(dirPath) {
|
|
10
|
+
try {
|
|
11
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
12
|
+
console.log(`📁 Created: ${dirPath}`);
|
|
13
|
+
} catch (e) {
|
|
14
|
+
console.error(`❌ Failed to create ${dirPath}:`, e.message);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async function createBaseStructure(root) {
|
|
19
|
+
for (const section of BASE_STRUCTURE) {
|
|
20
|
+
const sectionPath = path.join(root, section);
|
|
21
|
+
await createDirIfNotExists(sectionPath);
|
|
22
|
+
|
|
23
|
+
if (section === 'infra') {
|
|
24
|
+
await createDirIfNotExists(path.join(sectionPath, 'repo'));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (section === 'application') {
|
|
28
|
+
await createDirIfNotExists(path.join(sectionPath, 'services'));
|
|
29
|
+
await createDirIfNotExists(path.join(sectionPath, 'orchestrators'));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default async function initStructure() {
|
|
35
|
+
const config = await loadUserConfig();
|
|
36
|
+
const modules = config.modules;
|
|
37
|
+
|
|
38
|
+
if (!modules || modules.length === 0) {
|
|
39
|
+
// Без модулей
|
|
40
|
+
console.log('📦 Generating monolithic architecture...');
|
|
41
|
+
await createBaseStructure(ARCHITECTURE_PATH);
|
|
42
|
+
} else {
|
|
43
|
+
// С модулями
|
|
44
|
+
console.log('📦 Generating modular architecture...');
|
|
45
|
+
for (const mod of modules) {
|
|
46
|
+
const modRoot = path.join(ARCHITECTURE_PATH, mod);
|
|
47
|
+
await createBaseStructure(modRoot);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// shared и ui вне modules
|
|
52
|
+
await createDirIfNotExists(path.join(APP_ROOT, 'shared'));
|
|
53
|
+
await createDirIfNotExists(path.join(APP_ROOT, 'ui'));
|
|
54
|
+
|
|
55
|
+
console.log('✅ Structure initialization complete!');
|
|
56
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { loadUserConfig } from '../utils/loadConfig.js';
|
|
4
|
+
|
|
5
|
+
/** Файл конфигурации */
|
|
6
|
+
const svelteConfigPath = path.resolve('svelte.config.js');
|
|
7
|
+
|
|
8
|
+
function generateAliases(config) {
|
|
9
|
+
const hasModules = Array.isArray(config.modules) && config.modules.length > 0;
|
|
10
|
+
|
|
11
|
+
if (hasModules) {
|
|
12
|
+
return Object.fromEntries(
|
|
13
|
+
config.modules.map(m => [`$${m}`, `./src/app/context/${m}`])
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
'$domain': './src/app/context/domain',
|
|
19
|
+
'$infra': './src/app/context/infra',
|
|
20
|
+
'$application': './src/app/context/application',
|
|
21
|
+
'$presentation': './src/app/context/presentation',
|
|
22
|
+
'$services': './src/app/context/application/services'
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function parseObjectLiteral(text) {
|
|
27
|
+
const obj = {};
|
|
28
|
+
const entries = text.split(/,(?![^{]*})/).filter(Boolean);
|
|
29
|
+
for (const entry of entries) {
|
|
30
|
+
const [key, value] = entry.split(':').map(s => s.trim());
|
|
31
|
+
if (key && value) {
|
|
32
|
+
obj[key.replace(/^['"]|['"]$/g, '')] = value.replace(/^['"]|['"]$/g, '');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return obj;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function serializeObjectLiteral(obj) {
|
|
39
|
+
return Object.entries(obj)
|
|
40
|
+
.map(([key, value]) => `\t\t\t'${key}': '${value}'`)
|
|
41
|
+
.join(',\n');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function updateAliases() {
|
|
45
|
+
const config = await loadUserConfig();
|
|
46
|
+
const newAliases = generateAliases(config);
|
|
47
|
+
|
|
48
|
+
let content = await fs.readFile(svelteConfigPath, 'utf-8');
|
|
49
|
+
|
|
50
|
+
const aliasRegex = /alias:\s*{([\s\S]*?)}/m;
|
|
51
|
+
const match = content.match(aliasRegex);
|
|
52
|
+
|
|
53
|
+
if (!match) {
|
|
54
|
+
console.error('❌ No `alias` field found in svelte.config.js');
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// существующие алиасы
|
|
59
|
+
const existingAliases = parseObjectLiteral(match[1]);
|
|
60
|
+
|
|
61
|
+
// объединение
|
|
62
|
+
const updatedAliases = { ...existingAliases, ...newAliases };
|
|
63
|
+
|
|
64
|
+
// замена в контенте
|
|
65
|
+
const newAliasBlock = `alias: {\n${serializeObjectLiteral(updatedAliases)}\n\t\t}`;
|
|
66
|
+
content = content.replace(aliasRegex, newAliasBlock);
|
|
67
|
+
|
|
68
|
+
await fs.writeFile(svelteConfigPath, content, 'utf-8');
|
|
69
|
+
console.log('✅ Aliases updated in svelte.config.js');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export default updateAliases;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BaseService } from '@azure-net/kit';
|
|
2
2
|
import { <%= className %>Repo } from '$data/repo';
|
|
3
|
-
import type { <%= className %>CreateRequest, <%= className %>UpdateRequest } from '$domain/<%= domainName
|
|
3
|
+
import type { <%= className %>CreateRequest, <%= className %>UpdateRequest } from '$domain/<%= domainName %>';
|
|
4
4
|
|
|
5
5
|
export class <%= className %>Service extends BaseService {
|
|
6
6
|
constructor(private <%= domainName %>Repo = new <%= className %>Repo()) {
|
package/src/utils/loadConfig.js
CHANGED