@azure-net/cli 1.4.2 → 2.0.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 +88 -37
- package/package.json +1 -1
- package/src/commands/generate/generateCrud.js +350 -0
- package/src/commands/generate/generateDatasource.js +41 -0
- package/src/commands/generate/generateModule.js +23 -0
- package/src/commands/generate/generatePresenter.js +113 -0
- package/src/commands/generate/generateRepository.js +102 -0
- package/src/commands/generate/generateResponse.js +42 -0
- package/src/commands/generate/generateSchema.js +95 -0
- package/src/commands/generate/generateService.js +93 -0
- package/src/commands/generate/index.js +8 -0
- package/src/commands/init/index.js +7 -0
- package/src/commands/init/initAliases.js +50 -0
- package/src/commands/init/initEdges.js +42 -0
- package/src/commands/init/initMiddleware.js +43 -0
- package/src/commands/init/initSchema.js +19 -0
- package/src/commands/init/initStructure.js +79 -0
- package/src/commands/init/initTranslations.js +102 -0
- package/src/utils/contextUtils.js +53 -0
- package/src/utils/fileUtils.js +79 -0
- package/src/utils/loadConfig.js +2 -2
- package/src/utils/providerUtils.js +107 -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/generateRequest.js +0 -95
- 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 → init/initLint.js} +0 -0
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import prompts from 'prompts';
|
|
2
|
-
import fs from 'fs/promises';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import ejs from 'ejs';
|
|
5
|
-
import { loadUserConfig } from '../utils/loadConfig.js';
|
|
6
|
-
|
|
7
|
-
const __dirname = path.dirname(new URL(import.meta.url).pathname);
|
|
8
|
-
const CONTEXTS_PATH = path.join(process.cwd(), 'src/app/contexts');
|
|
9
|
-
|
|
10
|
-
async function writeIfNotExists(filepath, content) {
|
|
11
|
-
try {
|
|
12
|
-
await fs.access(filepath);
|
|
13
|
-
console.log(`⚠️ Skip existing: ${filepath}`);
|
|
14
|
-
} catch {
|
|
15
|
-
await fs.mkdir(path.dirname(filepath), { recursive: true });
|
|
16
|
-
await fs.writeFile(filepath, content, 'utf-8');
|
|
17
|
-
console.log(`✅ Created: ${filepath}`);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
async function updateIndexTs(dir) {
|
|
22
|
-
const files = (await fs.readdir(dir)).filter(f => f.endsWith('.ts') && f !== 'index.ts');
|
|
23
|
-
const content = files.map(f => `export * from './${f.replace('.ts', '')}';`).join('\n') + '\n';
|
|
24
|
-
await fs.writeFile(path.join(dir, 'index.ts'), content, 'utf-8');
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
async function getAvailableSubfolders(baseDomainPath) {
|
|
28
|
-
try {
|
|
29
|
-
const entries = await fs.readdir(baseDomainPath, { withFileTypes: true });
|
|
30
|
-
return entries.filter(e => e.isDirectory()).map(e => e.name);
|
|
31
|
-
} catch {
|
|
32
|
-
return [];
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export default async function generateRequest() {
|
|
37
|
-
const config = await loadUserConfig();
|
|
38
|
-
|
|
39
|
-
const { module } = await prompts({
|
|
40
|
-
type: 'select',
|
|
41
|
-
name: 'module',
|
|
42
|
-
message: 'Select target module:',
|
|
43
|
-
choices: [...config.modules, 'shared-context'].map(m => ({ title: m, value: m }))
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
const { className } = await prompts({
|
|
47
|
-
type: 'text',
|
|
48
|
-
name: 'className',
|
|
49
|
-
message: 'Request class name (PascalCase, without `Request` suffix):'
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
const pascalCaseName = className.trim();
|
|
53
|
-
const aliasModule = module === 'shared-context' ? '$shared-context' : `$${module}`;
|
|
54
|
-
|
|
55
|
-
const domainPath = path.join(CONTEXTS_PATH, module, 'Domain');
|
|
56
|
-
const availableSub = await getAvailableSubfolders(domainPath);
|
|
57
|
-
|
|
58
|
-
const { submodule } = await prompts({
|
|
59
|
-
type: 'autocomplete',
|
|
60
|
-
name: 'submodule',
|
|
61
|
-
message: 'Select or enter submodule:',
|
|
62
|
-
choices: [...availableSub.map(s => ({ title: s, value: s })), { title: '[Create new submodule]', value: '__custom' }]
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
let actualSub = submodule;
|
|
66
|
-
if (submodule === '__custom') {
|
|
67
|
-
const { newSub } = await prompts({
|
|
68
|
-
type: 'text',
|
|
69
|
-
name: 'newSub',
|
|
70
|
-
message: 'Enter new submodule name:'
|
|
71
|
-
});
|
|
72
|
-
actualSub = newSub.trim();
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const basePath = path.join(domainPath, actualSub);
|
|
76
|
-
const abstractsDir = path.join(basePath, 'Abstracts');
|
|
77
|
-
const requestDir = path.join(basePath, 'Request');
|
|
78
|
-
|
|
79
|
-
const templateData = { pascalCaseName };
|
|
80
|
-
|
|
81
|
-
const abstractTpl = `export interface I${pascalCaseName}Request {
|
|
82
|
-
// TODO: define fields
|
|
83
|
-
[key: string]: unknown;
|
|
84
|
-
}`;
|
|
85
|
-
await writeIfNotExists(path.join(abstractsDir, `I${pascalCaseName}Request.ts`), abstractTpl);
|
|
86
|
-
await updateIndexTs(abstractsDir);
|
|
87
|
-
|
|
88
|
-
const requestTplPath = path.join(__dirname, '../templates/domain/request/ClassRequest.ejs');
|
|
89
|
-
const tpl = await fs.readFile(requestTplPath, 'utf-8');
|
|
90
|
-
const result = ejs.render(tpl, templateData);
|
|
91
|
-
await writeIfNotExists(path.join(requestDir, `${pascalCaseName}Request.ts`), result);
|
|
92
|
-
await updateIndexTs(requestDir);
|
|
93
|
-
|
|
94
|
-
console.log(`✅ Request generated in ${path.join(module, actualSub)}`);
|
|
95
|
-
}
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import prompts from 'prompts';
|
|
2
|
-
import fs from 'fs/promises';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { loadUserConfig } from '../utils/loadConfig.js';
|
|
5
|
-
|
|
6
|
-
const CONTEXTS_PATH = path.join(process.cwd(), 'src/app/contexts');
|
|
7
|
-
|
|
8
|
-
async function getAvailableRepos(module) {
|
|
9
|
-
const repoPath = path.join(CONTEXTS_PATH, module, 'Infra', 'Repo');
|
|
10
|
-
try {
|
|
11
|
-
const files = await fs.readdir(repoPath);
|
|
12
|
-
return ['Without repo', ...files.filter(f => f.endsWith('.ts') && f !== 'index.ts').map(f => f.replace('.ts', ''))];
|
|
13
|
-
} catch {
|
|
14
|
-
return ['Without repo'];
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
async function updateIndexTs(dir) {
|
|
19
|
-
const files = (await fs.readdir(dir)).filter(f => f.endsWith('.ts') && f !== 'index.ts');
|
|
20
|
-
const content = files.map(f => `export * from './${f.replace('.ts', '')}';`).join('\n') + '\n';
|
|
21
|
-
await fs.writeFile(path.join(dir, 'index.ts'), content, 'utf-8');
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export default async function generateService() {
|
|
25
|
-
const config = await loadUserConfig();
|
|
26
|
-
|
|
27
|
-
const { module } = await prompts({
|
|
28
|
-
type: 'select',
|
|
29
|
-
name: 'module',
|
|
30
|
-
message: 'Select target module:',
|
|
31
|
-
choices: [...config.modules, 'shared-context'].map(m => ({ title: m, value: m }))
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
const { name } = await prompts({
|
|
35
|
-
type: 'text',
|
|
36
|
-
name: 'name',
|
|
37
|
-
message: 'Service class name (PascalCase):'
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
const repos = await getAvailableRepos(module);
|
|
41
|
-
const { repo } = await prompts({
|
|
42
|
-
type: 'select',
|
|
43
|
-
name: 'repo',
|
|
44
|
-
message: 'Select repository:',
|
|
45
|
-
choices: repos.map(r => ({ title: r, value: r }))
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
const capital = name.trim();
|
|
49
|
-
const basePath = path.join(CONTEXTS_PATH, module || 'app-context');
|
|
50
|
-
const serviceDir = path.join(basePath, 'Application', 'Services');
|
|
51
|
-
const filePath = path.join(serviceDir, `${capital}Service.ts`);
|
|
52
|
-
|
|
53
|
-
const aliasRepo = module === 'shared-context'
|
|
54
|
-
? '$shared-context/Infra/Repo'
|
|
55
|
-
: `$${module}/Infra/Repo`;
|
|
56
|
-
|
|
57
|
-
const content = repo === 'Without repo'
|
|
58
|
-
? `export class ${capital}Service {
|
|
59
|
-
constructor() {
|
|
60
|
-
// TODO: fill generated class
|
|
61
|
-
}
|
|
62
|
-
}`
|
|
63
|
-
: `import { ${repo} } from '${aliasRepo}';
|
|
64
|
-
|
|
65
|
-
export class ${capital}Service {
|
|
66
|
-
private repo = new ${repo}();
|
|
67
|
-
|
|
68
|
-
constructor() {
|
|
69
|
-
// TODO: fill generated class
|
|
70
|
-
}
|
|
71
|
-
}`;
|
|
72
|
-
|
|
73
|
-
await fs.mkdir(serviceDir, { recursive: true });
|
|
74
|
-
await fs.writeFile(filePath, content);
|
|
75
|
-
await updateIndexTs(serviceDir);
|
|
76
|
-
console.log(`✅ Service created at ${filePath}`);
|
|
77
|
-
}
|
|
@@ -1,65 +0,0 @@
|
|
|
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 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 === 'Infra') {
|
|
25
|
-
await createDirIfNotExists(path.join(sectionPath, 'Repo'));
|
|
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
|
-
const hasModules = Array.isArray(modules) && modules.length > 0;
|
|
38
|
-
|
|
39
|
-
console.log('📦 Generating architecture in: /contexts');
|
|
40
|
-
|
|
41
|
-
// всегда shared-context
|
|
42
|
-
const sharedKernelPath = path.join(CONTEXTS_PATH, 'shared-context');
|
|
43
|
-
await createBaseStructure(sharedKernelPath);
|
|
44
|
-
|
|
45
|
-
if (hasModules) {
|
|
46
|
-
// по модулям
|
|
47
|
-
console.log('🔧 Creating module contexts...');
|
|
48
|
-
for (const mod of modules) {
|
|
49
|
-
const modPath = path.join(CONTEXTS_PATH, mod);
|
|
50
|
-
await createBaseStructure(modPath);
|
|
51
|
-
}
|
|
52
|
-
} else {
|
|
53
|
-
// fallback-контекст
|
|
54
|
-
console.log('🧱 No modules found — using default "app-context"...');
|
|
55
|
-
const fallbackPath = path.join(CONTEXTS_PATH, 'app-context');
|
|
56
|
-
await createBaseStructure(fallbackPath);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Доп. слои вне contexts
|
|
60
|
-
await createDirIfNotExists(CORE_PATH);
|
|
61
|
-
await createDirIfNotExists(path.join(CORE_PATH, 'datasources'));
|
|
62
|
-
await createDirIfNotExists(path.join(APP_ROOT, 'ui'));
|
|
63
|
-
|
|
64
|
-
console.log('✅ Structure initialization complete!');
|
|
65
|
-
}
|
|
@@ -1,101 +0,0 @@
|
|
|
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
|
-
config.modules.push('shared-context');
|
|
14
|
-
return Object.fromEntries(
|
|
15
|
-
[
|
|
16
|
-
...config.modules.map(m => [`$${m}`, `./src/app/contexts/${m}`]),
|
|
17
|
-
['$core', './src/app/core'],
|
|
18
|
-
['$ui', './src/app/ui']
|
|
19
|
-
]
|
|
20
|
-
);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return {
|
|
24
|
-
'$app-context': './src/app/contexts/app-context',
|
|
25
|
-
'$shared-context': './src/app/contexts/shared-context',
|
|
26
|
-
'$core': './src/app/core',
|
|
27
|
-
'$ui': './src/app/ui'
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function parseObjectLiteral(text) {
|
|
32
|
-
const obj = {};
|
|
33
|
-
const entries = text.split(/,(?![^{]*})/).filter(Boolean);
|
|
34
|
-
for (const entry of entries) {
|
|
35
|
-
const [key, value] = entry.split(':').map(s => s.trim());
|
|
36
|
-
if (key && value) {
|
|
37
|
-
obj[key.replace(/^['"]|['"]$/g, '')] = value.replace(/^['"]|['"]$/g, '');
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return obj;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function serializeObjectLiteral(obj) {
|
|
44
|
-
return Object.entries(obj)
|
|
45
|
-
.map(([key, value]) => `\t\t\t'${key}': '${value}'`)
|
|
46
|
-
.join(',\n');
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function insertAliasBlock(content, aliasBlock) {
|
|
50
|
-
const kitRegex = /kit:\s*{([\s\S]*?)}/m;
|
|
51
|
-
const match = content.match(kitRegex);
|
|
52
|
-
|
|
53
|
-
if (!match) {
|
|
54
|
-
throw new Error('❌ Cannot find `kit: {}` block in svelte.config.js');
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const existingKit = match[0];
|
|
58
|
-
const newKit = existingKit.includes('alias:')
|
|
59
|
-
? existingKit.replace(/alias:\s*{([\s\S]*?)}/m, aliasBlock)
|
|
60
|
-
: existingKit.replace(/{/, `{\n\t\t${aliasBlock},`);
|
|
61
|
-
|
|
62
|
-
return content.replace(kitRegex, newKit);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
async function updateAliases() {
|
|
66
|
-
const config = await loadUserConfig();
|
|
67
|
-
const newAliases = generateAliases(config);
|
|
68
|
-
|
|
69
|
-
let content = await fs.readFile(svelteConfigPath, 'utf-8');
|
|
70
|
-
|
|
71
|
-
// если alias уже есть
|
|
72
|
-
const aliasRegex = /alias:\s*{([\s\S]*?)}/m;
|
|
73
|
-
const aliasMatch = content.match(aliasRegex);
|
|
74
|
-
|
|
75
|
-
let updatedAliases = {};
|
|
76
|
-
|
|
77
|
-
if (aliasMatch) {
|
|
78
|
-
const existingAliases = parseObjectLiteral(aliasMatch[1]);
|
|
79
|
-
updatedAliases = { ...existingAliases, ...newAliases };
|
|
80
|
-
} else {
|
|
81
|
-
updatedAliases = { ...newAliases };
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const newAliasBlock = `alias: {\n${serializeObjectLiteral(updatedAliases)}\n\t\t}`;
|
|
85
|
-
|
|
86
|
-
content = aliasMatch
|
|
87
|
-
? content.replace(aliasRegex, newAliasBlock)
|
|
88
|
-
: insertAliasBlock(content, newAliasBlock);
|
|
89
|
-
|
|
90
|
-
await fs.writeFile(svelteConfigPath, content, 'utf-8');
|
|
91
|
-
console.log('✅ Aliases updated in svelte.config.js');
|
|
92
|
-
|
|
93
|
-
// Run formatter
|
|
94
|
-
try {
|
|
95
|
-
execSync('npm run format', { stdio: 'inherit' });
|
|
96
|
-
} catch {
|
|
97
|
-
console.warn('⚠️ Failed to run format. Make sure you have a format script in package.json');
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export default updateAliases;
|
|
File without changes
|