Files
directus/packages/cli/src/core/options.ts
WoLfulus d8caf221ed CLI 2.0 (#5376)
* merge components

merge args, parser, docs, formatter, help and handlers

* change directus command and add auto debug

* output format fixes

* adds back some reformatted and documented commands

* better help output format

* refactor all output flow

* export cli types

* more formatting fixes and param rework

* fix table spacing

* add yaml formatting and fix string colors

* finished formatting docs

* remove log

* remove package-lock

* update dependency versions

* fix command description

* workaround typescript loading

* module loading fixes
added command error
rename human to table
fix disconnect usage

* add typescript loader

redirect execution to local package if installed locally
added command alias `directus-ctl`

* fix module load directories

* reimplement stdin pipe to work on linux

* fix sdk server info type

* info command

* Fix stdin bug
Disable community extensions to discourage use for now
Added template to config files
Added password stdin to connect to instances
Fixed typescript command load

* Added command suggestions and QOL features

* Linter fixes

* Add command hints

* Separate positional options

* Add back delete many, fix delete one location

* Change score logic

* Add whoami util command

* Add short online docs

* Fix typo

* Fix typo

* Update commands

* Param consistency fix and docs update

* Create commands

* Update package.json version

* Update package-lock

* Fixed several linting problems

* Update dependencies

* Update lock

* Remove locked dependencies

* Stop conflicts when in home directory

* Package lock update and npm audit fix

* Fix formatting errors

* Comment out extending cli section until we figure out cli ext

* Update readme

* Tweak dev/build/prebuild script naming

* Use up to date deps

* Fix dependency version in lock (fix build)

Co-authored-by: rijkvanzanten <rijkvanzanten@me.com>
2021-05-12 20:38:30 +00:00

127 lines
3.1 KiB
TypeScript

//import * as util from 'util';
import { GluegunCommand } from 'gluegun';
import yargs, { Argv } from 'yargs';
import yargsParser from 'yargs-parser';
import { Command } from '../command';
import { IEvents } from '../events';
import { IOptions, Option } from '../options';
import { CLIRuntimeError } from './exceptions';
export type Registrator = (builder: Argv, command: Command, raw: any) => void;
export class Options implements IOptions {
private _raw: any;
private _parser: Argv;
private _parsed?: any;
private _error?: Error;
private _registrators: Registrator[];
constructor(events: IEvents, argv: string[]) {
this._parser = yargs(argv).help(false).version(false);
this._registrators = [];
this._parsed = null;
this._raw = yargsParser(argv);
events.on('command.options.register', (command: Command) => {
const cmd = command as any as GluegunCommand;
const name = cmd.commandPath
?.concat(...[command.settings?.parameters ?? ''])
.filter((p) => p != '')
.join(' ');
this._parser.fail((message, err) => {
this._error = err || new CLIRuntimeError(message);
});
this._parser.showHelpOnFail(false).exitProcess(false);
this._parser.command(
name ?? '$0',
cmd.description ?? '',
(builder) => {
for (const registrator of this._registrators) {
registrator(builder, command, this._raw);
}
return this._parser;
},
(values) => {
this._parsed = values;
}
);
this._parser.argv;
});
}
register(registrator: Registrator): void {
this._registrators.push(registrator);
}
feature(name: string, registrator: Registrator): void {
this._registrators.push((options: Argv, command: Command) => {
const { settings } = command;
if (!settings) {
return;
}
const { features } = settings;
if (!features || !(name in features) || !features[name]) {
return;
}
registrator(options, command, this._raw);
});
}
failed(): boolean {
return !!this._error;
}
error(): Error | undefined {
return this._error;
}
values(): any {
return this._parsed || {};
}
list(): Option[] {
const freeParser = this._parser as any;
const usage = freeParser.getUsageInstance();
const descriptions = usage.getDescriptions();
const keys = Object.keys(descriptions);
const options = freeParser.getOptions() as any;
const positionalGroup = usage.getPositionalGroupName() as any;
const groups = freeParser.getGroups() as any;
return keys.map<Option>((key) => {
const name = key;
const description = descriptions[key];
const value = options.default[key] ?? undefined;
const required = key in options.demandedOptions;
const choices = options.choices[key];
let type = 'string';
if (options.boolean.indexOf(key) >= 0) {
type = 'boolean';
} else if (options.number.indexOf(key) >= 0) {
type = 'number';
}
let positional = false;
if (positionalGroup in groups) {
positional = groups[positionalGroup].indexOf(key) >= 0;
}
return {
name,
description,
type,
required,
choices,
positional,
default: value,
};
});
}
}