@kui-shell/core
Version:
An Electron-based shell for cloud-native development
245 lines (244 loc) • 8.95 kB
TypeScript
import REPL from './repl';
import { Entity } from './entity';
import { CodedError } from './errors';
import { ExecOptions } from './execOptions';
import { UsageModel } from '../core/usage-error';
import { Tab } from '../webapp/tab';
import { Block } from '../webapp/models/block';
import { StreamableFactory } from './streamable';
import * as Yargs from 'yargs-parser';
/**
* A command `KResponse` can be any supported `Entity` type
*
*/
export type KResponse<Content extends any = any> = Entity<Content>;
export default KResponse;
/**
* "top-level", meaning the user hit enter in the CLI,
* "click-handler", meaning that the user clicked on a UI element
* "nested", meaning that some evaluator uses the repl in its internal implementation
*
*/
export declare enum ExecType {
TopLevel = 0,
ClickHandler = 1,
Nested = 2,
Rerun = 3
}
export type ViewTransformer<T extends KResponse, O extends ParsedOptions> = (args: EvaluatorArgs<O>, response: T) => Promise<T> | void | Promise<void>;
export interface CommandOptions extends CapabilityRequirements {
/** does this command accept no arguments of any sort (neither positional nor optional)? */
noArgs?: boolean;
/** Semicolon-expand the command line? Default: true */
semiExpand?: boolean;
usage?: UsageModel;
flags?: YargsParserFlags;
hidden?: boolean;
incognito?: 'popup'[];
viewName?: string;
/**
* Desired window title; this only pertains to situations where the
* command execution will result in opening a new window specific to
* the execution of the command. You may either provide a fixed
* title (the `string` case), or a function that returns the title
* to use for the given arguments.
*/
title?: string | ((argv: string[]) => string);
width?: number;
height?: number;
/** is this an interior node ("directory", versus a leaf-node with a command handler */
isDirectory?: boolean;
listen?: CommandListener;
docs?: string;
synonymFor?: Command<KResponse, ParsedOptions>;
hide?: boolean;
override?: CommandHandler<KResponse, ParsedOptions>;
plugin?: string;
okOptions?: string[];
/** controller wants to handle redirect */
noCoreRedirect?: boolean;
/** model to view transformer */
viewTransformer?: ViewTransformer<KResponse, ParsedOptions>;
/**
* Is the command experimental? e.g. initial release, lack of test coverage
*
*/
isExperimental?: boolean;
/**
* Is the command only want to show output and hide input?
*
*/
outputOnly?: boolean;
/** When this command is being replayed, prefer to re-execute if possible */
preferReExecute?: boolean;
}
export interface Event {
tab?: Tab;
command?: string;
route?: string;
plugin?: string;
isIntention?: boolean;
error?: string;
options?: string[];
execType?: ExecType;
isDrilldown?: boolean;
}
export interface ParsedOptions {
_?: string[];
[key: string]: any;
}
/**
* This information represents a command line, but split out in
* various useful ways.
*
*/
export interface CommandLine<Options = ParsedOptions> {
/**
* the raw command string, as given by the user
*/
command: string;
/** the result of a whitespace split applied to the `command` string
* that pays attention to backslash escaping and quotations
*/
argv: string[];
/**
* the residual of `argv` without `parsedOptions`
*/
argvNoOptions: string[];
/**
* pipeline stages, e.g. if command='a b --foo|c', the pipeStages=[['a','b, '--foo'],'c']
*/
pipeStages: {
prefix?: string;
stages: string[][];
redirect?: string;
redirector?: '>' | '>>' | '2>&1' | '>&' | '>>&';
};
/**
* the dash options parsed out in a way that pays attention to n-ary
* options such as `--option key value`
*/
parsedOptions: Options;
}
/**
* The full set of data passed to a command handler
*
*/
export interface EvaluatorArgs<Options = ParsedOptions> extends CommandLine<Options> {
/**
* The tab context in which the command was initiated
*/
tab: Tab;
REPL: REPL;
/**
* Optional command channel options that one command can use to
* influence the execution of another.
*/
execOptions: ExecOptions;
/**
* Commands can use this to stream output to the UI, rather than
* using the normal request-response interaction between the REPL
* and the command.
*/
createOutputStream: StreamableFactory;
/**
* Same as createOutputStream, but for stderr
*/
createErrorStream: StreamableFactory;
/**
* EXPERT MODE: The REPL block in which this command was initiated
* (rarely used, but useful for more complex UI extensions)
*/
block: Block | boolean;
/**
* EXPERT MODE: The REPL block that will house the *subsequent*
* command execution (rarely used, but useful for more complex UI
* extensions)
*/
nextBlock: HTMLElement;
}
/** base command handler */
export type CommandHandler<T extends KResponse, O extends ParsedOptions> = (args: EvaluatorArgs<O>) => T | Promise<T>;
/** command handler when overriding commands from other plugins */
export type CommandOverrideHandler<T extends KResponse, O extends ParsedOptions> = (args: EvaluatorArgs<O>, underlyingHandler: CommandHandler<T, O>) => T | Promise<T>;
/**
* Evaluator
*
*/
export interface Evaluator<T extends KResponse, O extends ParsedOptions> {
eval: CommandHandler<T, O>;
}
export interface CommandBase {
route: string;
plugin?: string;
options?: CommandOptions;
}
type CommandKey = string;
interface CommandKeyMap {
[key: string]: Command<KResponse, ParsedOptions>;
}
export interface Disambiguator {
[key: string]: CommandBase[];
}
export interface Command<T extends KResponse, O extends ParsedOptions> extends CommandBase {
$: CommandHandler<T, O>;
key: CommandKey;
parent: Command<KResponse, ParsedOptions>;
children?: CommandKeyMap;
synonyms?: CommandKeyMap;
}
/** a command tree rooted by a command */
export type CommandTree = Command<KResponse, ParsedOptions>;
export interface CapabilityRequirements {
needsUI?: boolean;
requiresLocal?: boolean;
noAuthOk?: boolean | string[];
fullscreen?: boolean;
}
export type OnSuccess = (args: {
tab: Tab;
type: ExecType;
command: string;
isDrilldown: boolean;
parsedOptions: ParsedOptions;
}) => void;
export type OnError = (command: string, tab: Tab, type: ExecType, err: CodedError) => CodedError;
export interface CommandHandlerWithEvents<T extends KResponse, O extends ParsedOptions> extends Evaluator<T, O> {
subtree: Command<T, O>;
route: string;
options: CommandOptions;
success: OnSuccess;
error: OnError;
}
export declare function isCommandHandlerWithEvents<T extends KResponse, O extends ParsedOptions>(evaluator: Evaluator<T, O>): evaluator is CommandHandlerWithEvents<T, O>;
export type CommandTreeResolution<T extends KResponse, O extends ParsedOptions> = boolean | CommandHandlerWithEvents<T, O> | CodedError;
export interface YargsParserFlags {
configuration?: Partial<Yargs.Configuration>;
array?: string[];
boolean?: string[];
string?: string[];
narg?: Record<string, number>;
alias?: Record<string, string[]>;
}
/** a catch all handler is presented with an offer to handle a given argv */
export type CatchAllOffer = (argv: string[]) => boolean;
export interface CatchAllHandler<T extends KResponse, O extends ParsedOptions> extends Command<T, O> {
prio: number;
plugin: string;
offer: CatchAllOffer;
eval: CommandHandler<T, O>;
}
/**
* The registrar.listen API
*
*/
type CommandListener = <T extends KResponse, O extends ParsedOptions>(route: string, handler: CommandHandler<T, O>, options?: CommandOptions) => Command<T, O>;
export interface CommandRegistrar {
find: <T extends KResponse, O extends ParsedOptions>(route: string, fromPlugin?: string, noOverride?: boolean) => Promise<Command<T, O>>;
listen: CommandListener;
override: <T extends KResponse, O extends ParsedOptions>(route: string, fromPlugin: string, handler: CommandOverrideHandler<T, O>, options?: CommandOptions) => Promise<Command<T, O>>;
synonym: <T extends KResponse, O extends ParsedOptions>(route: string, handler: CommandHandler<T, O>, master: Command<T, O>, options?: CommandOptions) => void;
subtree: <T extends KResponse, O extends ParsedOptions>(route: string, options: CommandOptions) => Command<T, O>;
subtreeSynonym: <T extends KResponse, O extends ParsedOptions>(route: string, masterTree: Command<T, O>, options?: CommandOptions) => void;
catchall: <T extends KResponse, O extends ParsedOptions>(offer: CatchAllOffer, handler: CommandHandler<T, O>, prio: number, options?: CommandOptions) => void;
}