Skip to content

Commit feaa4e1

Browse files
committed
feat(commands): add make commands
1 parent 76c63f1 commit feaa4e1

17 files changed

+687
-2
lines changed

commands/Make/Base.ts

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* @adonisjs/assembler
3+
*
4+
* (c) Harminder Virk <virk@adonisjs.com>
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
import { join } from 'path'
11+
import { pathExists } from 'fs-extra'
12+
import { BaseCommand } from '@adonisjs/ace'
13+
import { RcFile } from '@ioc:Adonis/Core/Application'
14+
import { rcParser } from '@adonisjs/application/build/standalone'
15+
16+
import { ADONIS_ACE_CWD } from '../../config/env'
17+
18+
/**
19+
* Base class to generate framework entities
20+
*/
21+
export abstract class BaseGenerator extends BaseCommand {
22+
protected abstract $resourceName: string
23+
protected abstract $getStub (rcContents: RcFile): string
24+
protected abstract $getDestinationPath (rcContents: RcFile): string
25+
26+
protected $suffix?: string
27+
protected $form?: 'singular' | 'plural'
28+
protected $pattern?: 'camelcase' | 'snakecase' | 'pascalcase'
29+
protected $templateData (_rcContents: RcFile): any {
30+
return {}
31+
}
32+
33+
/**
34+
* Returns path for a given namespace by replacing the base namespace
35+
* with the defined directories map inside the `.adonisrc.json`
36+
* file
37+
*/
38+
protected $getPathForNamespace (rcContents: RcFile, namespaceFor: string): string | null {
39+
/**
40+
* Return null when rcfile doesn't have a special
41+
* entry for namespaces
42+
*/
43+
if (!rcContents.namespaces[namespaceFor]) {
44+
return null
45+
}
46+
47+
let output: string | null = null
48+
Object.keys(rcContents.autoloads).forEach((baseNamespace) => {
49+
const autoloadPath = rcContents.autoloads[baseNamespace]
50+
if (rcContents.namespaces[namespaceFor].startsWith(`${baseNamespace}/`)) {
51+
output = rcContents.namespaces[namespaceFor].replace(baseNamespace, autoloadPath)
52+
}
53+
return output
54+
})
55+
56+
return output
57+
}
58+
59+
/**
60+
* Returns contents of the rcFile
61+
*/
62+
protected async $getRcContents (cwd: string) {
63+
const filePath = join(cwd, '.adonisrc.json')
64+
const hasRcFile = await pathExists(filePath)
65+
if (!hasRcFile) {
66+
return null
67+
}
68+
69+
return rcParser.parse(require(filePath))
70+
}
71+
72+
/**
73+
* Handle command
74+
*/
75+
public async handle () {
76+
const cwd = ADONIS_ACE_CWD()
77+
if (!cwd) {
78+
const commandName = this.constructor['commandName']
79+
this.logger.error(
80+
`Cannot run "${commandName}". Make sure you running this command as "node ace ${commandName}"`,
81+
)
82+
return
83+
}
84+
85+
const rcContents = await this.$getRcContents(cwd)
86+
87+
/**
88+
* Ensure `.adonisrc.json` file exists
89+
*/
90+
if (!rcContents) {
91+
this.logger.error('Make sure your project root has .adonisrc.json file to continue')
92+
return
93+
}
94+
95+
this.generator
96+
.addFile(this.$resourceName, { suffix: this.$suffix, form: this.$form, pattern: this.$pattern })
97+
.stub(this.$getStub(rcContents))
98+
.destinationDir(this.$getDestinationPath(rcContents))
99+
.appRoot(cwd)
100+
.apply(this.$templateData(rcContents))
101+
102+
await this.generator.run()
103+
}
104+
}

commands/Make/Command.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* @adonisjs/assembler
3+
*
4+
* (c) Harminder Virk <virk@adonisjs.com>
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
import { join } from 'path'
11+
import { args } from '@adonisjs/ace'
12+
import { RcFile } from '@ioc:Adonis/Core/Application'
13+
import { BaseGenerator } from './Base'
14+
15+
/**
16+
* Command to make a new command
17+
*/
18+
export default class MakeCommand extends BaseGenerator {
19+
/**
20+
* Required by BaseGenerator
21+
*/
22+
protected $pattern = 'pascalcase' as const
23+
protected $resourceName: string
24+
25+
/**
26+
* Command meta data
27+
*/
28+
public static commandName = 'make:command'
29+
public static description = 'Make a new ace command'
30+
31+
@args.string({ description: 'Make of the command class' })
32+
public name: string
33+
34+
/**
35+
* Returns the template stub based upon the `--resource`
36+
* flag value
37+
*/
38+
protected $getStub (): string {
39+
return join(
40+
__dirname,
41+
'..',
42+
'..',
43+
'templates',
44+
'command.txt',
45+
)
46+
}
47+
48+
/**
49+
* Path to the commands directory
50+
*/
51+
protected $getDestinationPath (rcFile: RcFile): string {
52+
return rcFile.directories.commands || 'commands'
53+
}
54+
55+
public async handle () {
56+
this.$resourceName = this.name
57+
await super.handle()
58+
}
59+
}

commands/Make/Controller.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* @adonisjs/assembler
3+
*
4+
* (c) Harminder Virk <virk@adonisjs.com>
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
import { join } from 'path'
11+
import { args, flags } from '@adonisjs/ace'
12+
import { RcFile } from '@ioc:Adonis/Core/Application'
13+
import { BaseGenerator } from './Base'
14+
15+
/**
16+
* Command to make a new HTTP Controller
17+
*/
18+
export default class MakeController extends BaseGenerator {
19+
/**
20+
* Required by BaseGenerator
21+
*/
22+
protected $suffix = 'Controller'
23+
protected $form = 'plural' as const
24+
protected $pattern = 'pascalcase' as const
25+
protected $resourceName: string
26+
27+
/**
28+
* Command meta data
29+
*/
30+
public static commandName = 'make:controller'
31+
public static description = 'Make a new HTTP controller'
32+
33+
@args.string({ description: 'Make of the controller class' })
34+
public name: string
35+
36+
@flags.boolean({ description: 'Add resourceful methods to the controller class', alias: 'r' })
37+
public resource: boolean
38+
39+
/**
40+
* Returns the template stub based upon the `--resource`
41+
* flag value
42+
*/
43+
protected $getStub (): string {
44+
return join(
45+
__dirname,
46+
'..',
47+
'..',
48+
'templates',
49+
this.resource ? 'resource-controller.txt' : 'controller.txt',
50+
)
51+
}
52+
53+
/**
54+
* Pull path from the `httpControllers` directory declaration from
55+
* the `.adonisrc.json` file or fallback to `app/Controllers/Http`
56+
*/
57+
protected $getDestinationPath (rcContents: RcFile): string {
58+
return this.$getPathForNamespace(rcContents, 'httpControllers') || 'app/Controllers/Http'
59+
}
60+
61+
public async handle () {
62+
this.$resourceName = this.name
63+
await super.handle()
64+
}
65+
}

commands/Make/Middleware.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* @adonisjs/assembler
3+
*
4+
* (c) Harminder Virk <virk@adonisjs.com>
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
import { join } from 'path'
11+
import { args } from '@adonisjs/ace'
12+
import { BaseGenerator } from './Base'
13+
14+
/**
15+
* Command to make a new middleware
16+
*/
17+
export default class MakeMiddleware extends BaseGenerator {
18+
/**
19+
* Required by BaseGenerator
20+
*/
21+
protected $suffix = ''
22+
protected $form = 'singular' as const
23+
protected $pattern = 'pascalcase' as const
24+
protected $resourceName: string
25+
26+
/**
27+
* Command meta data
28+
*/
29+
public static commandName = 'make:middleware'
30+
public static description = 'Make a new middleware'
31+
32+
@args.string({ description: 'Make of the middleware class' })
33+
public name: string
34+
35+
/**
36+
* Returns the template stub path
37+
*/
38+
protected $getStub (): string {
39+
return join(
40+
__dirname,
41+
'..',
42+
'..',
43+
'templates',
44+
'middleware.txt',
45+
)
46+
}
47+
48+
/**
49+
* Middleware are always created inside `app/Middleware` directory.
50+
* We can look into configuring it later.
51+
*/
52+
protected $getDestinationPath (): string {
53+
return 'app/Middleware'
54+
}
55+
56+
public async handle () {
57+
this.$resourceName = this.name
58+
await super.handle()
59+
}
60+
}

commands/Make/Provider.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* @adonisjs/assembler
3+
*
4+
* (c) Harminder Virk <virk@adonisjs.com>
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
import { join } from 'path'
11+
import { args } from '@adonisjs/ace'
12+
import { RcFile } from '@ioc:Adonis/Core/Application'
13+
import { BaseGenerator } from './Base'
14+
15+
/**
16+
* Command to make a new provider
17+
*/
18+
export default class MakeProvider extends BaseGenerator {
19+
/**
20+
* Required by BaseGenerator
21+
*/
22+
protected $suffix = 'Provider'
23+
protected $form = 'singular' as const
24+
protected $pattern = 'pascalcase' as const
25+
protected $resourceName: string
26+
27+
/**
28+
* Command meta data
29+
*/
30+
public static commandName = 'make:provider'
31+
public static description = 'Make a new IoC container provider'
32+
33+
@args.string({ description: 'Make of the provider class' })
34+
public name: string
35+
36+
/**
37+
* Returns the template stub path
38+
*/
39+
protected $getStub (): string {
40+
return join(
41+
__dirname,
42+
'..',
43+
'..',
44+
'templates',
45+
'provider.txt',
46+
)
47+
}
48+
49+
/**
50+
* Path to the providers directory
51+
*/
52+
protected $getDestinationPath (rcFile: RcFile): string {
53+
return rcFile.directories.providers || 'providers'
54+
}
55+
56+
public async handle () {
57+
this.$resourceName = this.name
58+
await super.handle()
59+
}
60+
}

index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,8 @@ new Manifest(__dirname).generate([
1212
'./commands/Build',
1313
'./commands/Serve',
1414
'./commands/Invoke',
15+
'./commands/Make/Command',
16+
'./commands/Make/Controller',
17+
'./commands/Make/Middleware',
18+
'./commands/Make/Provider',
1519
])

templates/command.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { BaseCommand } from '@adonisjs/ace'
2+
3+
export abstract class {filename} extends BaseCommand {
4+
public static commandName = ''
5+
public static description = ''
6+
7+
public async handle () {
8+
this.logger.info('Hello world!')
9+
}
10+
}

templates/controller.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
2+
3+
export default class ${filename} {
4+
}

templates/middleware.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
2+
3+
export default class ${filename} {
4+
public async handle (ctx: HttpContextContract, next: () => Promise<void>) {
5+
}
6+
}

templates/model.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { BaseModel, column } from '@ioc:Adonis/Lucid/Orm'
2+
3+
export default class ${filename} extends BaseModel {
4+
@column({ primary: true })
5+
public id: number
6+
}

0 commit comments

Comments
 (0)