@azure-net/cli 1.3.12 → 1.4.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 +17 -4
- package/package.json +1 -1
- package/src/commands/generateDatasource.js +44 -0
- package/src/commands/generateRepo.js +69 -0
- package/src/commands/generateService.js +77 -0
- package/src/templates/data/datasource/ClassDatasource.ejs +7 -0
- package/src/commands/generateCrudRepo.js +0 -27
- package/src/templates/generateCrudRepo.ejs +0 -26
package/bin/azure-net.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { Command } from 'commander';
|
|
4
|
-
import
|
|
4
|
+
import generateDatasource from '../src/commands/generateDatasource.js';
|
|
5
|
+
import generateRepo from '../src/commands/generateRepo.js';
|
|
6
|
+
import generateService from '../src/commands/generateService.js';
|
|
5
7
|
import generateCrud from '../src/commands/generateCrud.js';
|
|
6
8
|
import initLint from '../src/commands/initLint.js';
|
|
7
9
|
import initStructure from '../src/commands/generateStructure.js';
|
|
@@ -14,9 +16,20 @@ program
|
|
|
14
16
|
.description('Universal code generator')
|
|
15
17
|
.version('1.0.0');
|
|
16
18
|
|
|
17
|
-
program
|
|
18
|
-
.
|
|
19
|
-
.
|
|
19
|
+
program
|
|
20
|
+
.command('make:datasource')
|
|
21
|
+
.description('Generate datasource')
|
|
22
|
+
.action(generateDatasource);
|
|
23
|
+
|
|
24
|
+
program
|
|
25
|
+
.command('make:repo')
|
|
26
|
+
.description('Generate repo')
|
|
27
|
+
.action(generateRepo);
|
|
28
|
+
|
|
29
|
+
program
|
|
30
|
+
.command('make:service')
|
|
31
|
+
.description('Generate service')
|
|
32
|
+
.action(generateService);
|
|
20
33
|
|
|
21
34
|
program
|
|
22
35
|
.command('make:crud')
|
package/package.json
CHANGED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import prompts from 'prompts';
|
|
2
|
+
import fs from 'fs/promises';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
const CORE_DATASOURCES_PATH = path.join(process.cwd(), 'src/app/core/datasources');
|
|
6
|
+
|
|
7
|
+
async function writeIfNotExists(filepath, content) {
|
|
8
|
+
try {
|
|
9
|
+
await fs.access(filepath);
|
|
10
|
+
console.log(`⚠️ Skip existing: ${filepath}`);
|
|
11
|
+
} catch {
|
|
12
|
+
await fs.mkdir(path.dirname(filepath), { recursive: true });
|
|
13
|
+
await fs.writeFile(filepath, content, 'utf-8');
|
|
14
|
+
console.log(`✅ Created: ${filepath}`);
|
|
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 generateDatasource() {
|
|
25
|
+
const { name } = await prompts({
|
|
26
|
+
type: 'text',
|
|
27
|
+
name: 'name',
|
|
28
|
+
message: 'Datasource class name (PascalCase, e.g., BackendApi):'
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const capital = name.trim();
|
|
32
|
+
const filePath = path.join(CORE_DATASOURCES_PATH, `${capital}Datasource.ts`);
|
|
33
|
+
|
|
34
|
+
const content = `import { BaseHttpDatasource, HttpService } from '@azure-net/kit';
|
|
35
|
+
|
|
36
|
+
export class ${capital}Datasource extends BaseHttpDatasource {
|
|
37
|
+
constructor() {
|
|
38
|
+
super({ http: new HttpService({ baseUrl: '' }) }); // TODO: fill generated class
|
|
39
|
+
}
|
|
40
|
+
}`;
|
|
41
|
+
|
|
42
|
+
await writeIfNotExists(filePath, content);
|
|
43
|
+
await updateIndexTs(CORE_DATASOURCES_PATH);
|
|
44
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
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 CORE_DATASOURCES_PATH = path.join(process.cwd(), 'src/app/core/datasources');
|
|
7
|
+
const CONTEXTS_PATH = path.join(process.cwd(), 'src/app/contexts');
|
|
8
|
+
|
|
9
|
+
async function getAvailableDatasources() {
|
|
10
|
+
try {
|
|
11
|
+
const files = await fs.readdir(CORE_DATASOURCES_PATH);
|
|
12
|
+
return files.filter(f => f.endsWith('.ts') && !f.startsWith('_')).map(f => f.replace('.ts', ''));
|
|
13
|
+
} catch {
|
|
14
|
+
return [];
|
|
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 generateRepo() {
|
|
25
|
+
const config = await loadUserConfig();
|
|
26
|
+
const datasources = await getAvailableDatasources();
|
|
27
|
+
|
|
28
|
+
const answers = await prompts([
|
|
29
|
+
config.modules?.length ? {
|
|
30
|
+
type: 'select',
|
|
31
|
+
name: 'module',
|
|
32
|
+
message: 'Select target module:',
|
|
33
|
+
choices: [...config.modules, 'shared-context'].map(m => ({ title: m, value: m }))
|
|
34
|
+
} : null,
|
|
35
|
+
{ type: 'text', name: 'name', message: 'Repository class name (PascalCase):' },
|
|
36
|
+
{
|
|
37
|
+
type: 'select',
|
|
38
|
+
name: 'datasource',
|
|
39
|
+
message: 'Select datasource:',
|
|
40
|
+
choices: datasources.map(d => ({ title: d, value: d }))
|
|
41
|
+
}
|
|
42
|
+
].filter(Boolean));
|
|
43
|
+
|
|
44
|
+
const { name, module, datasource } = answers;
|
|
45
|
+
const capital = name.trim();
|
|
46
|
+
|
|
47
|
+
const basePath = path.join(CONTEXTS_PATH, module || 'app-context');
|
|
48
|
+
const repoDir = path.join(basePath, 'Infra', 'Repo');
|
|
49
|
+
const filePath = path.join(repoDir, `${capital}Repo.ts`);
|
|
50
|
+
|
|
51
|
+
const aliasRepo = module === 'shared-context'
|
|
52
|
+
? '$shared-context/Infra/Repo'
|
|
53
|
+
: `$${module}/Infra/Repo`;
|
|
54
|
+
|
|
55
|
+
const content = `import { ${datasource} } from '$core/datasources';
|
|
56
|
+
|
|
57
|
+
export class ${capital}Repo {
|
|
58
|
+
private source = new ${datasource}();
|
|
59
|
+
|
|
60
|
+
constructor() {
|
|
61
|
+
// TODO: fill generated class
|
|
62
|
+
}
|
|
63
|
+
}`;
|
|
64
|
+
|
|
65
|
+
await fs.mkdir(repoDir, { recursive: true });
|
|
66
|
+
await fs.writeFile(filePath, content);
|
|
67
|
+
await updateIndexTs(repoDir);
|
|
68
|
+
console.log(`✅ Repo created at ${filePath}`);
|
|
69
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
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,27 +0,0 @@
|
|
|
1
|
-
import prompts from 'prompts';
|
|
2
|
-
import ejs from 'ejs';
|
|
3
|
-
import fs from 'fs/promises';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
import { fileURLToPath } from 'url';
|
|
6
|
-
import { loadUserConfig } from "../utils/loadConfig.js";
|
|
7
|
-
|
|
8
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
-
|
|
10
|
-
export default async function generateCrudRepository() {
|
|
11
|
-
const config = await loadUserConfig();
|
|
12
|
-
const answers = await prompts([
|
|
13
|
-
{ type: 'text', name: 'className', message: 'Class name:' },
|
|
14
|
-
{ type: 'text', name: 'endpoint', message: 'API endpoint:' },
|
|
15
|
-
]);
|
|
16
|
-
|
|
17
|
-
const templatePath = path.join(__dirname, '../templates/generateCrudRepo.ejs');
|
|
18
|
-
const template = await fs.readFile(templatePath, 'utf-8');
|
|
19
|
-
const result = ejs.render(template, answers);
|
|
20
|
-
|
|
21
|
-
const outputDir = config.output.repository;
|
|
22
|
-
const outFile = path.join(process.cwd(), outputDir, `${answers.className}Repo.ts`);
|
|
23
|
-
await fs.mkdir(path.dirname(outFile), { recursive: true });
|
|
24
|
-
await fs.writeFile(outFile, result, 'utf-8');
|
|
25
|
-
|
|
26
|
-
console.log(`✅ Created: ${outFile}`);
|
|
27
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { BaseDatasource } from '@azure-net/kit';
|
|
2
|
-
|
|
3
|
-
export class <%= className %>Repo {
|
|
4
|
-
private endpoint = '<%= endpoint %>';
|
|
5
|
-
constructor(private source: BaseDatasource) {}
|
|
6
|
-
|
|
7
|
-
public async collection() {
|
|
8
|
-
return await this.source.createRequest<unknown[]>(({ http }) => http.get(this.endpoint));
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
public async resource(id: number) {
|
|
12
|
-
return await this.source.createRequest<unknown>(({ http }) => http.get(`${this.endpoint}/${id}`));
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
public async create(data: unknown) {
|
|
16
|
-
return await this.source.createRequest<unknown>(({ http }) => http.post(this.endpoint, { json: data }));
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
public async update(id: number, data: unknown) {
|
|
20
|
-
return await this.source.createRequest<unknown>(({ http }) => http.put(`${this.endpoint}/${id}`, { json: data }));
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
public async delete(id: number) {
|
|
24
|
-
return await this.source.createRequest<unknown>(({ http }) => http.delete(`${this.endpoint}/${id}`));
|
|
25
|
-
}
|
|
26
|
-
}
|