UNPKG

@kui-shell/core

Version:

An Electron-based shell for cloud-native development

245 lines (244 loc) • 8.95 kB
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; }