@qui-cli/plugin
v4.0.0
Published
@qui-cli plugin structure and registrar
Downloads
492
Readme
@qui-cli/plugin
@qui-cli plugin structure and registrar
Install
npm install @qui-cli/pluginUsage
Refer to @qui-cli/env for a complete example defining a plugin. The model is to define an ESM module and then to register that module with the Plugin.Registrar. The plugin module can optionally define the following hooks:
configure(config?: Plugin.Configuration) => voidmay be invoked either manually before processing user-provided command line arguments (e.g. to update default values) and also (if defined) whenoptions()is invoked. See Configuration below.options() => Plugin.Optionsis invoked (if defined) when preparing to process user-provided command-line arguments and must return aPlugin.Optionsobject describing any user-configurable command line arguments and other user-readable documentation. See Options below.init(args: Plugin.Arguments<ReturnType<typeof options>>) => voidis invoked to process any user-provided command line arguments. See Initialization below.
Recommended Plugin Structure
Refer to @qui-cli/shell for a relatively straight-forward example.
📁 @example/plugin
↳ package.json
↳ 📁 src
↳ index.ts
↳ Example.tspackage.json
Define both a name and version. Include @qui-cli/plugin and any other plugins that your Plugin depends on as peer dependencies:
{
"peerDependencies": {
"@qui-cli/plugin": "^2.4"
}
}While npm will install all dependencies at the same level of the ./node_modules/ folder hierarchy, tools like pnpm will not install non-peer dependencies at the same level as the plugin. To ensure that the plugin's peers are both installed and shared properly with other plugins that rely on them, plugin dependencies must be listed as peerDependencies.
src/index.ts
Register your plugin with the Plugin.Registrar and export the module for the convenience of other plugins that may depend on it.
import { register } from '@qui-cli/plugin';
import * as Example from './Example.js';
await register(Example);
export { Example };src/Example.ts
Define your plugin module, including exported name and any of the optional Plugin Hooks.
export const name = 'example';
export function configure(config?) {
// ...
}
export function myMethod() {
// ...
}Plugin Hooks
See dev-plugin-lifecycle for an illustration of the order in which hooks are called.
Configuration
The configure() hook may prepare the plugin module for use.
While the provided Plugin.Configuration type can be used as the parameter type for the configure() hook, it is recommended to extend that configuration to support IntelliSense in your IDE:
type Configuration = Plugin.Configuration & {
myOption?: string;
};All plugin-defined configuration parameters must be optional, as the configure() hook may be invoked with no parameters to ensure that a plugin is ready to to provide options() or receive init().
In general, it is recommended that configure() be used to set/update/instantiate any module variables that are used elsewhere, and can be understood as the constructor for the singleton object represented by the plugin module.
Options
The options() hook may provide command-line options for jackspeak initialization and user-facing usage documentation.
type ConfigSet<Value> = Record<
string,
{
description?: string; // user-readable usage information
short?: string; // single-character short-hand for this option
default?: Value;
hint?: string
validate?: (value: any) => v is Value | (v: any) => boolean;
type?: 'number' | 'string' | 'boolean';
multiple?: boolean;
delim?: string // default ' '
}
>;
type Paragraph = {
text: string;
level?: 1 | 2 | 3 | 4 | 5 | 6;
pre?: boolean;
};
type Options = {
// an option that expects a single number
num?: ConfigSet<number>;
// an option that expects a `delim`-separated list of numbers
numList?: ConfigSet<number[]>;
// an option that expects a string value (optionally quoted)
opt?: ConfigSet<string>;
// an option that expects a `delim`-separated list of strings
optList?: ConfigSet<string[]>;
// a flag that is set (true) or unset (false), --example can be explicitly unset as --no-example
flag?: ConfigSet<boolean>;
// a flag that can be set multiple times (-d vs -ddd)
flagList?: ConfigSet<boolean[]>;
// must explicitly define type and multiple
fields?: ConfigSet<any>;
// additional user-readable usage information
man?: Paragraph[];
};For example, the options() hook could be defined thus:
export function options() {
return {
flag: {
foo: {
description: 'Engage foo-ness',
short: 'f'
}
},
opt: {
bar: {
description: `Bar value`,
short: 'b',
default: 'argle-bargle'
}
}
};
}Initialization
The init() hook may receive user-provided command line arguments to update the plugin configuration. The arguments are provided as the result of the jackspeak parse() method.
The arguments may be assumed to reflect that Plugin.Options object returned from the options() hook (if no options() hook is defined, it is recommended to examine only the positional arguments).
export function init({
values: { foo, bar }
}: Plugin.ExpectedArguments<typeof options>) {
// ...
}API
import * as Plugin from '@qui-cli/plugin';Plugin.register(plugin): void
Register a plugin for use.
import * as MyPlugin from './MyPlugin.js';
Plugin.register(MyPlugin);Plugin.Configuration
Typing for configure() hook. Intended to be extended to provide IntelliSense support, discussed in detail in Configuration.
type Configuration = Plugin.Configuration & {
// ...
};
export function configure(config?: Configuration) {
// ...
}Plugin.Options
Typing for options() hook. Maps 1:1 to the jackspeak options API, discussed in detail inOptions.
export function options(): Plugin.Options {
// ...
}Plugin.ExpectedArguments
Typing for init() hook. Intended to provide IntelliSense support for parameters defined by options() hook.
export function init(args: Plugin.ExpectedArguments<typeof options>) {
// ...
}Plugin.Registrar
The Plugin Registrar, responsible for tracking plugin registrations and triggering plugin hooks. Intended primarily for use by @qui-cli/core
Plugin.mergeOptions(a, b): Plugin.Options
Merge two Plugin.Options objects. b overwrites a in the event of duplicate keys.
