@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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-net/cli",
3
- "version": "1.2.10",
3
+ "version": "1.3.1",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "azure-net": "bin/azure-net.js"
@@ -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
- // === Domain lowercase folder ===
36
- const domainPath = path.join(process.cwd(), config.output.domain, lower);
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
- // 1) Abstracts
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 writeIfNotExists(
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 writeIfNotExists(
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
- // ✅ Services index.ts
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) Generate Repo ===
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
- // === 6) Repo Index ===
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 %>/request';
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()) {
@@ -8,10 +8,7 @@ export async function loadUserConfig() {
8
8
  return userConfig.default || {};
9
9
  } catch {
10
10
  return {
11
- output: {
12
- domain: 'src/app/layers/domain',
13
- repo: 'src/app/layers/data/repo'
14
- }
11
+ modules: ['admin', 'auth']
15
12
  };
16
13
  }
17
14
  }