parent
fb85e42dee
commit
cae260b9ce
@ -0,0 +1,9 @@
|
|||||||
|
import {UniversalPath} from '@extollo/util'
|
||||||
|
|
||||||
|
export interface Template {
|
||||||
|
name: string,
|
||||||
|
fileSuffix: string,
|
||||||
|
description: string,
|
||||||
|
baseAppPath: string[],
|
||||||
|
render: (name: string, fullCanonicalName: string, targetFilePath: UniversalPath) => string | Promise<string>
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
import {Directive, OptionDefinition} from "../Directive"
|
||||||
|
import {Injectable, Inject} from "@extollo/di"
|
||||||
|
import {ErrorWithContext} from "@extollo/util"
|
||||||
|
import {PositionalOption} from "./options/PositionalOption"
|
||||||
|
import {CommandLine} from "../service"
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class TemplateDirective extends Directive {
|
||||||
|
@Inject()
|
||||||
|
protected readonly cli!: CommandLine
|
||||||
|
|
||||||
|
getKeywords(): string | string[] {
|
||||||
|
return ['new', 'make']
|
||||||
|
}
|
||||||
|
|
||||||
|
getDescription(): string {
|
||||||
|
return 'create a new file from a registered template'
|
||||||
|
}
|
||||||
|
|
||||||
|
getOptions(): OptionDefinition[] {
|
||||||
|
const registeredTemplates = this.cli.getTemplates()
|
||||||
|
const template = new PositionalOption('template_name', 'the template to base the new file on (e.g. model, controller)')
|
||||||
|
template.whitelist(...registeredTemplates.pluck('name'))
|
||||||
|
|
||||||
|
const destination = new PositionalOption('file_name', 'canonical name of the file to create (e.g. auth:Group, dash:Activity)')
|
||||||
|
|
||||||
|
return [template, destination]
|
||||||
|
}
|
||||||
|
|
||||||
|
getHelpText(): string {
|
||||||
|
const registeredTemplates = this.cli.getTemplates()
|
||||||
|
|
||||||
|
return [
|
||||||
|
'Modules in Extollo register templates that can be used to quickly create common file types.',
|
||||||
|
'',
|
||||||
|
'For example, you can create a new model from @extollo/orm using the "model" template:',
|
||||||
|
'',
|
||||||
|
'./ex new model auth:Group',
|
||||||
|
'',
|
||||||
|
'This would create a new Group model in the ./src/app/models/auth/Group.model.ts file.',
|
||||||
|
'',
|
||||||
|
'AVAILABLE TEMPLATES:',
|
||||||
|
'',
|
||||||
|
...(registeredTemplates.map(template => {
|
||||||
|
return ` - ${template.name}: ${template.description}`
|
||||||
|
}))
|
||||||
|
].join('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
async handle(argv: string[]) {
|
||||||
|
const templateName: string = this.option('template_name')
|
||||||
|
const destinationName: string = this.option('file_name')
|
||||||
|
|
||||||
|
if ( destinationName.includes('/') || destinationName.includes('\\') ) {
|
||||||
|
this.error(`The destination should be a canonical name, not a file path.`)
|
||||||
|
this.error(`Reference sub-directories using the : character instead.`)
|
||||||
|
this.error(`Did you mean ${destinationName.replace(/\/|\\/g, ':')}?`)
|
||||||
|
process.exitCode = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const template = this.cli.getTemplate(templateName)
|
||||||
|
if ( !template ) {
|
||||||
|
throw new ErrorWithContext(`Unable to find template supposedly registered with name: ${templateName}`, {
|
||||||
|
templateName,
|
||||||
|
destinationName,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const name = destinationName.split(':').reverse()[0]
|
||||||
|
const path = this.app().path('..', 'src', 'app', ...template.baseAppPath, ...(`${destinationName}${template.fileSuffix}`).split(':'))
|
||||||
|
|
||||||
|
if ( await path.exists() ) {
|
||||||
|
this.error(`File already exists: ${path}`)
|
||||||
|
process.exitCode = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the parent direction exists
|
||||||
|
await path.concat('..').mkdir()
|
||||||
|
|
||||||
|
const contents = await template.render(name, destinationName, path.clone())
|
||||||
|
await path.write(contents)
|
||||||
|
|
||||||
|
this.success(`Created new ${template.name} in ${path}`)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
import {Template} from "../Template"
|
||||||
|
import {UniversalPath} from "@extollo/util"
|
||||||
|
|
||||||
|
const directive_template: Template = {
|
||||||
|
name: 'directive',
|
||||||
|
fileSuffix: '.directive.ts',
|
||||||
|
description: 'Create a new Directive class which adds functionality to the ./ex command.',
|
||||||
|
baseAppPath: ['directives'],
|
||||||
|
render(name: string, fullCanonicalName: string, targetFilePath: UniversalPath) {
|
||||||
|
return `import {Directive, OptionDefinition} from "@extollo/cli"
|
||||||
|
import {Injectable} from "@extollo/di"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ${name} Directive
|
||||||
|
* ---------------------------------------------------
|
||||||
|
* Put some description here.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class ${name}Directive extends Directive {
|
||||||
|
getKeywords(): string | string[] {
|
||||||
|
return ['${name.toLowerCase()}']
|
||||||
|
}
|
||||||
|
|
||||||
|
getDescription(): string {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
getOptions(): OptionDefinition[] {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
async handle(argv: string[]) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { directive_template }
|
@ -0,0 +1,10 @@
|
|||||||
|
`{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "es5",
|
||||||
|
"sourceMap": true
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in new issue