@azure-net/cli 1.3.11 → 1.4.0

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
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { Command } from 'commander';
4
- import generateRepository from '../src/commands/generateCrudRepo.js';
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.command('generate:crud-repo')
18
- .description('Generate a CRUD repository')
19
- .action(generateRepository);
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
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@azure-net/cli",
3
- "version": "1.3.11",
3
+ "version": "1.4.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "azure-net": "bin/azure-net.js"
7
7
  },
8
8
  "dependencies": {
9
- "@azure-net/kit": "^0.1.3",
9
+ "@azure-net/kit": "^0.3.3",
10
10
  "commander": "^11",
11
11
  "ejs": "^3",
12
12
  "prompts": "^2"
@@ -96,7 +96,7 @@ export default async function generateCrud() {
96
96
 
97
97
  // === 1) Abstracts
98
98
  const abstractsDir = path.join(domainPath, 'Abstracts');
99
- for (const file of ['Class', 'ClassCreateRequest', 'ClassUpdateRequest']) {
99
+ for (const file of ['Class', 'ClassCreateRequest', 'ClassUpdateRequest', 'ClassCollectionQuery']) {
100
100
  const tpl = await fs.readFile(path.join(__dirname, `../templates/domain/abstracts/${file}.ejs`), 'utf-8');
101
101
  const result = ejs.render(tpl, templateData);
102
102
  await writeIfNotExists(path.join(abstractsDir, `${capital}${file.replace('Class', '')}.ts`), result);
@@ -0,0 +1,38 @@
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
+ export default async function generateDatasource() {
19
+ const { name } = await prompts({
20
+ type: 'text',
21
+ name: 'name',
22
+ message: 'Datasource class name (PascalCase, e.g., BackendApi):'
23
+ });
24
+
25
+ const capital = name.trim();
26
+ const filePath = path.join(CORE_DATASOURCES_PATH, `${capital}Datasource.ts`);
27
+
28
+ const content = `import { BaseHttpDatasource, HttpService } from '@azure-net/kit';
29
+
30
+ export class ${capital}Datasource extends BaseHttpDatasource {
31
+ // TODO: fill generated class
32
+ constructor() {
33
+ super({ http: new HttpService({ baseUrl: '' }) });
34
+ }
35
+ }`;
36
+
37
+ await writeIfNotExists(filePath, content);
38
+ }
@@ -0,0 +1,63 @@
1
+ // === generateRepo.js ===
2
+ import prompts from 'prompts';
3
+ import fs from 'fs/promises';
4
+ import path from 'path';
5
+ import { loadUserConfig } from '../utils/loadConfig.js';
6
+
7
+ const CORE_DATASOURCES_PATH = path.join(process.cwd(), 'src/app/core/datasources');
8
+ const CONTEXTS_PATH = path.join(process.cwd(), 'src/app/contexts');
9
+
10
+ async function getAvailableDatasources() {
11
+ try {
12
+ const files = await fs.readdir(CORE_DATASOURCES_PATH);
13
+ return files.filter(f => f.endsWith('.ts') && !f.startsWith('_')).map(f => f.replace('.ts', ''));
14
+ } catch {
15
+ return [];
16
+ }
17
+ }
18
+
19
+ export default async function generateRepo() {
20
+ const config = await loadUserConfig();
21
+ const datasources = await getAvailableDatasources();
22
+
23
+ const answers = await prompts([
24
+ config.modules?.length ? {
25
+ type: 'select',
26
+ name: 'module',
27
+ message: 'Select target module:',
28
+ choices: [...config.modules, 'shared-context'].map(m => ({ title: m, value: m }))
29
+ } : null,
30
+ { type: 'text', name: 'name', message: 'Repository class name (PascalCase):' },
31
+ {
32
+ type: 'select',
33
+ name: 'datasource',
34
+ message: 'Select datasource:',
35
+ choices: datasources.map(d => ({ title: d, value: d }))
36
+ }
37
+ ].filter(Boolean));
38
+
39
+ const { name, module, datasource } = answers;
40
+ const capital = name.trim();
41
+
42
+ const basePath = path.join(CONTEXTS_PATH, module || 'app-context');
43
+ const repoDir = path.join(basePath, 'Infra', 'Repo');
44
+ const filePath = path.join(repoDir, `${capital}Repo.ts`);
45
+
46
+ const aliasRepo = module === 'shared-context'
47
+ ? '$shared-context/Infra/Repo'
48
+ : `$${module}/Infra/Repo`;
49
+
50
+ const content = `import { ${datasource} } from '$core/datasources';
51
+
52
+ export class ${capital}Repo {
53
+ private source = new ${datasource}();
54
+
55
+ constructor() {
56
+ // TODO: fill generated class
57
+ }
58
+ }`;
59
+
60
+ await fs.mkdir(repoDir, { recursive: true });
61
+ await fs.writeFile(filePath, content);
62
+ console.log(`✅ Repo created at ${filePath}`);
63
+ }
@@ -0,0 +1,70 @@
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
+ export default async function generateService() {
19
+ const config = await loadUserConfig();
20
+
21
+ const { module } = await prompts({
22
+ type: 'select',
23
+ name: 'module',
24
+ message: 'Select target module:',
25
+ choices: [...config.modules, 'shared-context'].map(m => ({ title: m, value: m }))
26
+ });
27
+
28
+ const { name } = await prompts({
29
+ type: 'text',
30
+ name: 'name',
31
+ message: 'Service class name (PascalCase):'
32
+ });
33
+
34
+ const repos = await getAvailableRepos(module);
35
+ const { repo } = await prompts({
36
+ type: 'select',
37
+ name: 'repo',
38
+ message: 'Select repository:',
39
+ choices: repos.map(r => ({ title: r, value: r }))
40
+ });
41
+
42
+ const capital = name.trim();
43
+ const basePath = path.join(CONTEXTS_PATH, module || 'app-context');
44
+ const serviceDir = path.join(basePath, 'Application', 'Services');
45
+ const filePath = path.join(serviceDir, `${capital}Service.ts`);
46
+
47
+ const aliasRepo = module === 'shared-context'
48
+ ? '$shared-context/Infra/Repo'
49
+ : `$${module}/Infra/Repo`;
50
+
51
+ const content = repo === 'Without repo'
52
+ ? `export class ${capital}Service {
53
+ constructor() {
54
+ // TODO: fill generated class
55
+ }
56
+ }`
57
+ : `import { ${repo} } from '${aliasRepo}';
58
+
59
+ export class ${capital}Service {
60
+ private repo = new ${repo}();
61
+
62
+ constructor() {
63
+ // TODO: fill generated class
64
+ }
65
+ }`;
66
+
67
+ await fs.mkdir(serviceDir, { recursive: true });
68
+ await fs.writeFile(filePath, content);
69
+ console.log(`✅ Service created at ${filePath}`);
70
+ }
@@ -0,0 +1,7 @@
1
+ import { BaseHttpDatasource, HttpService } from '@azure-net/kit';
2
+
3
+ export class <%= name %>Datasource extends BaseHttpDatasource {
4
+ constructor() {
5
+ super({ http: new HttpService({ baseUrl: '' }) });
6
+ }
7
+ }
@@ -3,15 +3,16 @@ import type {
3
3
  I<%= pascalCaseName %>Collection,
4
4
  I<%= pascalCaseName %>Resource,
5
5
  I<%= pascalCaseName %>CreateRequest,
6
- I<%= pascalCaseName %>UpdateRequest
6
+ I<%= pascalCaseName %>UpdateRequest,
7
+ I<%= pascalCaseName %>CollectionQuery,
7
8
  } from '<%= aliasDomain %>/<%= pascalCaseName %>';
8
9
 
9
10
  export class <%= pascalCaseName %>Repo {
10
11
  private endpoint = '<%= endpoint %>';
11
12
  constructor(private source = new <%= datasource %>()) {}
12
13
 
13
- public async collection() {
14
- return await this.source.createRequest<I<%= pascalCaseName %>Collection>(({ http }) => http.get(this.endpoint));
14
+ public async collection(queryParams?: I<%= pascalCaseName %>CollectionQuery) {
15
+ return await this.source.createRequest<I<%= pascalCaseName %>Collection>(({ http, query }) => http.get(`${this.endpoint}${query.build(queryParams)}`));
15
16
  }
16
17
 
17
18
  public async resource(id: number) {
@@ -0,0 +1,3 @@
1
+ export interface I<%= pascalCaseName %>CollectionQuery {
2
+ [key: string]: unknown;
3
+ }
@@ -1,14 +1,14 @@
1
1
  import { BaseService } from '@azure-net/kit';
2
2
  import { <%= pascalCaseName %>Repo } from '<%= aliasRepo %>';
3
- import type { <%= pascalCaseName %>CreateRequest, <%= pascalCaseName %>UpdateRequest } from '<%= aliasDomain %>/<%= pascalCaseName %>';
3
+ import type { <%= pascalCaseName %>CreateRequest, <%= pascalCaseName %>UpdateRequest, I<%= pascalCaseName %>CollectionQuery } from '<%= aliasDomain %>/<%= pascalCaseName %>';
4
4
 
5
5
  export class <%= pascalCaseName %>Service extends BaseService {
6
6
  constructor(private <%= camelCaseName %>Repo = new <%= pascalCaseName %>Repo()) {
7
7
  super();
8
8
  }
9
9
 
10
- async collection() {
11
- return await this.transformResponse(this.<%= camelCaseName %>Repo.collection());
10
+ async collection(queryParams?: I<%= pascalCaseName %>CollectionQuery) {
11
+ return await this.transformResponse(this.<%= camelCaseName %>Repo.collection(queryParams));
12
12
  }
13
13
 
14
14
  async resource(id: number) {
@@ -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
- }