Skip to main content

Plugin Architecture

Code Shaper is designed to be modular and extensible using the concept of plugins. The shaper CLI can load plugins dynamically, thus extending its functionality to your unique needs. This topic describes the plugin architecture and implementation mechanics to help you write your own plugins.

Concepts

Code Shaper allows you to bundle multiple generators into a plugin. The plugin can be used within its own repository or published to a central registry (e.g. npm or artifactory) for use in other repositories.

Thus creating a generator involves two steps:

  1. Create a plugin
  2. Add one or more generators to it

The diagram below shows the plugin architecture visually.

Plugin Architecture

  • A plugin consists of one or more generators.
  • A generator generates artifacts based on user input.

Here's an example of a plugin that generates React code. It consists of three generators: Component, Page and Context.

  • The Component Generator generates components, e.g. Button and MovieList.
  • The Page Generator generates pages, e.g. HomePage.
  • The Context Generator generates React contexts, e.g. OrderContext.

Plugin Example

Technical Design

Options

The concept of Options is used throughout Code Shaper. Options is a hash of key-value pairs, where keys are strings and values can be anything (usually strings, arrays or objects). For example, here's an Options object:

{
"itemName": "Button",
"workspace": "packages/ui-lib",
"dirInWorkspace": "src/components/Button"
}

Here's the TypeScript definition of Options:

type Options = { [option: string]: unknown };

Options can be specified on the shaper command line where they are parsed and passed onto the selected plugin. The plugin can add to the options by asking questions to the user. The plugin then sends the combined options to the selected generator which can ask further questions and add more options. Finally, the generator uses these options to make text substitutions in templates before copying them to their destination.

Code Shaper uses the Inquirer library for asking questions to the user and collecting responses. Inquirer itself has a rich plugin ecosystem that is available for use in your Code Shaper plugins.

Plugins

A plugin must conform to the following interface:

interface Plugin {
/**
* Unique identifier of the plugin
* By convention we use the package name
* Example: "@code-shaper/react"
*/
id: string;

/**
* Human-readable name
* Example: "React"
*/
name: string;

/**
* Short description
* Keep it under 80 characters
* Example: "generates React applications"
*/
description: string;

/**
* Runs the plugin
* @param options specific to the plugin - if a required option is not
* specified, the plugin should prompt for it.
*/
run: (options: Options) => Promise<void>;
}

The shaper CLI loads the selected plugin and calls its run method, passing in all the options.

In order to load a plugin, it should be installed as a dev dependency at the root of your repository. shaper reads the dev dependencies to detect which plugins are available for the user to use.

Generators

A generator must conform to the following interface:

interface Generator {
/**
* Identifier of the generator
* Must be unique within a plugin
* Example: "app"
*/
id: string;

/**
* Human-readable name
* Example: "Application"
*/
name: string;

/**
* Short description
* Keep it under 80 characters
* Example: "generates a React application"
*/
description: string;

/**
* Runs the generator
* @param options specific to the generator - if a required option is not
* specified, the generator should prompt for it.
*/
generate: (options: Options) => Promise<void>;
}

The plugin calls the run method of the selected generator, passing in all the options.

Writing your own plugin

Code Shaper provides a plugin to scaffold your own plugins and generators. You can learn how to use this plugin under Create a Custom Generator.