The jib CodeGen Plugin
Adds flexible, simplified support for yeoman
(source code)
generators within a @jib/cli
project.
Technically this package could be used as a standalone plugin to other CLI
frameworks, however it is designed to work in accordance with the @jib/cli
opinions and applicaton structure.
Usage
npm install @jib/codegen
Implementation
This plugin adds source code generators shipped directly within the CLI
itself. Integrating the plugin with @jib/cli
project follows a slightly
different pattern than what one might expect if already familiar with
yeoman.
Structure
With jib, or TypeScript in general, the generators
code is part of src
whereas templates
is somewhere outside that in the hierarchy. This is because
src
is the TypeScript source code and is normally excluded when the project
is built/packaged/published. In the case of yeoman, templates
can contain
anything, and should also be distributed with the project build.
├── package.json
├── src
│ ├── commands
│ │ └── init
│ │ └── project.ts
│ └── generators
│ └── project
│ ├── index.ts
│ └── project.ts
└── templates
└── project
└── README.md
In the tree above, there is a single generator called
project
, and corresponding subdirectories insrc/generators/project
as well astemplates/project
.
In Commands
Considering the structure shown above, one would implement a generator in the following way:
// commands/init/project
import { Plugin, Command, BaseCommand } from '@jib/cli';
import { GeneratorEnv } from '@jib/codegen';
@Command({
description: 'Sample command usage of @jib/codegen plugin',
allowUnknown: true, // allows any options from the generator to be passed
})
export class InitProject extends BaseCommand {
// load the plugin
@Plugin(GeneratorEnv)
private _codegen: GeneratorEnv;
public help(): void {
// get usage and append help text
const usage = this._codegen.usage('project')[0];
this.ui.outputSection(`Generator Options`, this.ui.grid(usage.options));
}
public async run(options: any, ...args: any[]) {
// do things with this._gen
await this._codegen.load() // load the generator enviroment
.run('project', options, args) // run the `project` generator
}
}
Generator Code
This project adds only a few simple abstractions onto the
Generator
class maintainted by Yeoman,
and does not change standard behavior in any way. As such, you're encouraged to
reference their docs accordingly.
While not required, it's yeoman expects an index.ts
file in each generator directory
that exports only the Generator
implementation. This might look something
like the following:
// generators/project/index.ts
import { ProjectGenerator } from './project';
export = ProjectGenerator;
// generators/project/project.ts
import { BaseGenerator, IBaseGeneratorOptions } from '@jib/codejen';
export interface IProjectGeneratorOptions extends IBaseGeneratorOptions {
name: string;
description: string;
}
export class ProjectGenerator extends BaseGenerator<IProjectGeneratorOptions> {
constructor(...args: any[]) {
super(...args);
this.option('name', {type: String, description: 'The new project name'})
.option('description', {type: String, description: 'Description for the project'})
}
// ...
}
This approach is particularly useful with generator composability, where child generators have exported interfaces for their options, etc.
TODOs
- [ ] Create
@Generator()
decorator mapping@jib/cli
option/argument annotations to the generator abstract