@azure-net/cli 1.3.0 → 1.3.2
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
|
@@ -5,6 +5,7 @@ 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
7
|
import initStructure from '../src/commands/generateStructure.js';
|
|
8
|
+
import initAliases from '../src/commands/initAliases.js';
|
|
8
9
|
|
|
9
10
|
const program = new Command();
|
|
10
11
|
|
|
@@ -32,4 +33,9 @@ program
|
|
|
32
33
|
.description('Generate base folder structure based on config')
|
|
33
34
|
.action(initStructure);
|
|
34
35
|
|
|
36
|
+
program
|
|
37
|
+
.command('init:aliases')
|
|
38
|
+
.description('Generate alias mappings for modules or default architecture')
|
|
39
|
+
.action(initAliases);
|
|
40
|
+
|
|
35
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,98 @@
|
|
|
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
|
+
/** Файл конфигурации */
|
|
7
|
+
const svelteConfigPath = path.resolve('svelte.config.js');
|
|
8
|
+
|
|
9
|
+
function generateAliases(config) {
|
|
10
|
+
const hasModules = Array.isArray(config.modules) && config.modules.length > 0;
|
|
11
|
+
|
|
12
|
+
if (hasModules) {
|
|
13
|
+
return Object.fromEntries(
|
|
14
|
+
config.modules.map(m => [`$${m}`, `./src/app/context/${m}`])
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
'$domain': './src/app/context/domain',
|
|
20
|
+
'$infra': './src/app/context/infra',
|
|
21
|
+
'$application': './src/app/context/application',
|
|
22
|
+
'$presentation': './src/app/context/presentation',
|
|
23
|
+
'$services': './src/app/context/application/services'
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function parseObjectLiteral(text) {
|
|
28
|
+
const obj = {};
|
|
29
|
+
const entries = text.split(/,(?![^{]*})/).filter(Boolean);
|
|
30
|
+
for (const entry of entries) {
|
|
31
|
+
const [key, value] = entry.split(':').map(s => s.trim());
|
|
32
|
+
if (key && value) {
|
|
33
|
+
obj[key.replace(/^['"]|['"]$/g, '')] = value.replace(/^['"]|['"]$/g, '');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return obj;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function serializeObjectLiteral(obj) {
|
|
40
|
+
return Object.entries(obj)
|
|
41
|
+
.map(([key, value]) => `\t\t\t'${key}': '${value}'`)
|
|
42
|
+
.join(',\n');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function insertAliasBlock(content, aliasBlock) {
|
|
46
|
+
const kitRegex = /kit:\s*{([\s\S]*?)}/m;
|
|
47
|
+
const match = content.match(kitRegex);
|
|
48
|
+
|
|
49
|
+
if (!match) {
|
|
50
|
+
throw new Error('❌ Cannot find `kit: {}` block in svelte.config.js');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const existingKit = match[0];
|
|
54
|
+
const newKit = existingKit.includes('alias:')
|
|
55
|
+
? existingKit.replace(/alias:\s*{([\s\S]*?)}/m, aliasBlock)
|
|
56
|
+
: existingKit.replace(/{/, `{\n\t\t${aliasBlock},`);
|
|
57
|
+
|
|
58
|
+
return content.replace(kitRegex, newKit);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async function updateAliases() {
|
|
62
|
+
const config = await loadUserConfig();
|
|
63
|
+
const newAliases = generateAliases(config);
|
|
64
|
+
|
|
65
|
+
let content = await fs.readFile(svelteConfigPath, 'utf-8');
|
|
66
|
+
|
|
67
|
+
// если alias уже есть
|
|
68
|
+
const aliasRegex = /alias:\s*{([\s\S]*?)}/m;
|
|
69
|
+
const aliasMatch = content.match(aliasRegex);
|
|
70
|
+
|
|
71
|
+
let updatedAliases = {};
|
|
72
|
+
|
|
73
|
+
if (aliasMatch) {
|
|
74
|
+
const existingAliases = parseObjectLiteral(aliasMatch[1]);
|
|
75
|
+
updatedAliases = { ...existingAliases, ...newAliases };
|
|
76
|
+
} else {
|
|
77
|
+
updatedAliases = { ...newAliases };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const newAliasBlock = `alias: {\n${serializeObjectLiteral(updatedAliases)}\n\t\t}`;
|
|
81
|
+
|
|
82
|
+
content = aliasMatch
|
|
83
|
+
? content.replace(aliasRegex, newAliasBlock)
|
|
84
|
+
: insertAliasBlock(content, newAliasBlock);
|
|
85
|
+
|
|
86
|
+
await fs.writeFile(svelteConfigPath, content, 'utf-8');
|
|
87
|
+
console.log('✅ Aliases updated in svelte.config.js');
|
|
88
|
+
|
|
89
|
+
// Run formatter
|
|
90
|
+
try {
|
|
91
|
+
execSync('npm run format', { stdio: 'inherit' });
|
|
92
|
+
console.log('✅ Ran npm run format');
|
|
93
|
+
} catch {
|
|
94
|
+
console.warn('⚠️ Failed to run format. Make sure you have a format script in package.json');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
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