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 in src/generators/project
as well as templates/project
.
In Commands
Considering the structure shown above, one would implement a generator
in the following way:
import { Plugin, Command, BaseCommand } from '@jib/cli';
import { GeneratorEnv } from '@jib/codegen';
@Command({
description: 'Sample command usage of @jib/codegen plugin',
allowUnknown: true,
})
export class InitProject extends BaseCommand {
@Plugin(GeneratorEnv)
private _codegen: GeneratorEnv;
public help(): void {
const usage = this._codegen.usage('project')[0];
this.ui.outputSection(`Generator Options`, this.ui.grid(usage.options));
}
public async run(options: any, ...args: any[]) {
await this._codegen.load()
.run('project', options, args)
}
}
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:
import { ProjectGenerator } from './project';
export = ProjectGenerator;
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