@jakubmazanec/cli 0.5.7-unstable.72f063e3 → 0.5.8-next.24efc8d1f

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,8 +3,7 @@ import { type CommandAction } from './CommandAction.js';
3
3
  import { type CommandOptions } from './CommandOptions.js';
4
4
  import { type Program } from './Program.js';
5
5
  /**
6
- * Command encapsulates piece of a CLI's logic and is executed when {@link Program} instance parses
7
- * that command from the command line arguments.
6
+ * Command encapsulates piece of a CLI's logic and is executed when {@link Program} instance parses that command from the command line arguments.
8
7
  */
9
8
  export declare class Command<A extends string, const B extends ParametersConfig | undefined = undefined, const C extends OptionsConfig | undefined = undefined, D extends boolean = false, E extends boolean = false> {
10
9
  readonly name: A;
@@ -21,8 +20,7 @@ export declare class Command<A extends string, const B extends ParametersConfig
21
20
  */
22
21
  constructor(name: A, action: CommandAction<A, B, C, D, E>, { description, parameters, options, allowUnknownOptions, allowUnknownParameters, }: CommandOptions<NonNullable<B>, NonNullable<C>, D, E>);
23
22
  /**
24
- * Parses a list of command line arguments into an arguments object. Parser is pre-configured
25
- * based on this command.
23
+ * Parses a list of command line arguments into an arguments object. Parser is pre-configured based on this command.
26
24
  */
27
25
  parseArguments(argv: Argv): Arguments<{
28
26
  commands: readonly [A];
@@ -48,8 +48,7 @@ export class Command {
48
48
  }
49
49
  }
50
50
  /**
51
- * Parses a list of command line arguments into an arguments object. Parser is pre-configured
52
- * based on this command.
51
+ * Parses a list of command line arguments into an arguments object. Parser is pre-configured based on this command.
53
52
  */
54
53
  parseArguments(argv) {
55
54
  return parseArguments(argv, {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../source/program/Command.ts"],
4
- "sourcesContent": ["import {\n type Arguments,\n type Argv,\n type OptionsConfig,\n type ParametersConfig,\n parseArguments,\n} from '@jakubmazanec/args';\n\nimport {type CommandAction} from './CommandAction.js';\nimport {type CommandOptions} from './CommandOptions.js';\nimport {type Program} from './Program.js';\n\n/**\n * Command encapsulates piece of a CLI's logic and is executed when {@link Program} instance parses\n * that command from the command line arguments.\n */\nexport class Command<\n A extends string,\n const B extends ParametersConfig | undefined = undefined,\n const C extends OptionsConfig | undefined = undefined,\n D extends boolean = false,\n E extends boolean = false,\n> {\n readonly name: A;\n readonly description?: string;\n readonly parameters: B extends ParametersConfig ? B : null;\n readonly options: C extends OptionsConfig ? C : null;\n readonly allowUnknownOptions: D;\n readonly allowUnknownParameters: E;\n private readonly action: CommandAction<A, B, C, D, E>;\n\n /**\n * @param name Command name, ie. space-separated words consisting only of letters, numbers (but not at the start of the word) or dashes.\n * @param action Function that runs when command is executed.\n * @param options Additionl command options.\n */\n constructor(\n name: A,\n action: CommandAction<A, B, C, D, E>,\n {\n description,\n parameters,\n options,\n allowUnknownOptions,\n allowUnknownParameters,\n }: CommandOptions<NonNullable<B>, NonNullable<C>, D, E>,\n ) {\n this.name = name;\n this.action = action;\n\n if (description) {\n this.description = description;\n }\n\n if (parameters) {\n this.parameters = parameters as B extends ParametersConfig ? B : null;\n } else {\n this.parameters = null as B extends ParametersConfig ? B : null;\n }\n\n if (options) {\n this.options = options as C extends OptionsConfig ? C : null;\n } else {\n this.options = null as C extends OptionsConfig ? C : null;\n }\n\n if (allowUnknownOptions) {\n this.allowUnknownOptions = allowUnknownOptions;\n } else {\n this.allowUnknownOptions = false as D;\n }\n\n if (allowUnknownParameters) {\n this.allowUnknownParameters = allowUnknownParameters;\n } else {\n this.allowUnknownParameters = false as E;\n }\n }\n\n /**\n * Parses a list of command line arguments into an arguments object. Parser is pre-configured\n * based on this command.\n */\n parseArguments(argv: Argv): Arguments<{\n commands: readonly [A];\n parameters: B;\n options: C;\n allowUnknownOptions: D;\n allowUnknownParameters: E;\n }> {\n return parseArguments(argv, {\n commands: [this.name],\n parameters: this.parameters ?? undefined,\n options: this.options ?? undefined,\n allowUnknownOptions: this.allowUnknownOptions,\n allowUnknownParameters: this.allowUnknownParameters,\n } as {\n commands: readonly [A];\n parameters: B;\n options: C;\n allowUnknownOptions: D;\n allowUnknownParameters: E;\n });\n }\n\n /**\n * Executes command action with provided parsed arguments and {@link Program} instance.\n */\n async run(\n parsedArgs: Arguments<{\n commands: readonly [A];\n parameters: B;\n options: C;\n allowUnknownOptions: D;\n allowUnknownParameters: E;\n }>,\n program: Program,\n ): Promise<void> {\n await this.action(parsedArgs, program);\n }\n}\n"],
5
- "mappings": "AAAA;AAAA,EAKE;AAAA,OACK;AAUA,aAAM,QAMX;AAAA,EACS;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOjB,YACE,MACA,QACA;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GACA;AACA,SAAK,OAAO;AACZ,SAAK,SAAS;AAEd,QAAI,aAAa;AACf,WAAK,cAAc;AAAA,IACrB;AAEA,QAAI,YAAY;AACd,WAAK,aAAa;AAAA,IACpB,OAAO;AACL,WAAK,aAAa;AAAA,IACpB;AAEA,QAAI,SAAS;AACX,WAAK,UAAU;AAAA,IACjB,OAAO;AACL,WAAK,UAAU;AAAA,IACjB;AAEA,QAAI,qBAAqB;AACvB,WAAK,sBAAsB;AAAA,IAC7B,OAAO;AACL,WAAK,sBAAsB;AAAA,IAC7B;AAEA,QAAI,wBAAwB;AAC1B,WAAK,yBAAyB;AAAA,IAChC,OAAO;AACL,WAAK,yBAAyB;AAAA,IAChC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,eAAe,MAMZ;AACD,WAAO,eAAe,MAAM;AAAA,MAC1B,UAAU,CAAC,KAAK,IAAI;AAAA,MACpB,YAAY,KAAK,cAAc;AAAA,MAC/B,SAAS,KAAK,WAAW;AAAA,MACzB,qBAAqB,KAAK;AAAA,MAC1B,wBAAwB,KAAK;AAAA,IAC/B,CAMC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,IACJ,YAOA,SACe;AACf,UAAM,KAAK,OAAO,YAAY,OAAO;AAAA,EACvC;AACF;",
4
+ "sourcesContent": ["import {\n type Arguments,\n type Argv,\n type OptionsConfig,\n type ParametersConfig,\n parseArguments,\n} from '@jakubmazanec/args';\n\nimport {type CommandAction} from './CommandAction.js';\nimport {type CommandOptions} from './CommandOptions.js';\nimport {type Program} from './Program.js';\n\n/**\n * Command encapsulates piece of a CLI's logic and is executed when {@link Program} instance parses that command from the command line arguments.\n */\nexport class Command<\n A extends string,\n const B extends ParametersConfig | undefined = undefined,\n const C extends OptionsConfig | undefined = undefined,\n D extends boolean = false,\n E extends boolean = false,\n> {\n readonly name: A;\n readonly description?: string;\n readonly parameters: B extends ParametersConfig ? B : null;\n readonly options: C extends OptionsConfig ? C : null;\n readonly allowUnknownOptions: D;\n readonly allowUnknownParameters: E;\n private readonly action: CommandAction<A, B, C, D, E>;\n\n /**\n * @param name Command name, ie. space-separated words consisting only of letters, numbers (but not at the start of the word) or dashes.\n * @param action Function that runs when command is executed.\n * @param options Additionl command options.\n */\n constructor(\n name: A,\n action: CommandAction<A, B, C, D, E>,\n {\n description,\n parameters,\n options,\n allowUnknownOptions,\n allowUnknownParameters,\n }: CommandOptions<NonNullable<B>, NonNullable<C>, D, E>,\n ) {\n this.name = name;\n this.action = action;\n\n if (description) {\n this.description = description;\n }\n\n if (parameters) {\n this.parameters = parameters as B extends ParametersConfig ? B : null;\n } else {\n this.parameters = null as B extends ParametersConfig ? B : null;\n }\n\n if (options) {\n this.options = options as C extends OptionsConfig ? C : null;\n } else {\n this.options = null as C extends OptionsConfig ? C : null;\n }\n\n if (allowUnknownOptions) {\n this.allowUnknownOptions = allowUnknownOptions;\n } else {\n this.allowUnknownOptions = false as D;\n }\n\n if (allowUnknownParameters) {\n this.allowUnknownParameters = allowUnknownParameters;\n } else {\n this.allowUnknownParameters = false as E;\n }\n }\n\n /**\n * Parses a list of command line arguments into an arguments object. Parser is pre-configured based on this command.\n */\n parseArguments(argv: Argv): Arguments<{\n commands: readonly [A];\n parameters: B;\n options: C;\n allowUnknownOptions: D;\n allowUnknownParameters: E;\n }> {\n return parseArguments(argv, {\n commands: [this.name],\n parameters: this.parameters ?? undefined,\n options: this.options ?? undefined,\n allowUnknownOptions: this.allowUnknownOptions,\n allowUnknownParameters: this.allowUnknownParameters,\n } as {\n commands: readonly [A];\n parameters: B;\n options: C;\n allowUnknownOptions: D;\n allowUnknownParameters: E;\n });\n }\n\n /**\n * Executes command action with provided parsed arguments and {@link Program} instance.\n */\n async run(\n parsedArgs: Arguments<{\n commands: readonly [A];\n parameters: B;\n options: C;\n allowUnknownOptions: D;\n allowUnknownParameters: E;\n }>,\n program: Program,\n ): Promise<void> {\n await this.action(parsedArgs, program);\n }\n}\n"],
5
+ "mappings": "AAAA;AAAA,EAKE;AAAA,OACK;AASA,aAAM,QAMX;AAAA,EACS;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOjB,YACE,MACA,QACA;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GACA;AACA,SAAK,OAAO;AACZ,SAAK,SAAS;AAEd,QAAI,aAAa;AACf,WAAK,cAAc;AAAA,IACrB;AAEA,QAAI,YAAY;AACd,WAAK,aAAa;AAAA,IACpB,OAAO;AACL,WAAK,aAAa;AAAA,IACpB;AAEA,QAAI,SAAS;AACX,WAAK,UAAU;AAAA,IACjB,OAAO;AACL,WAAK,UAAU;AAAA,IACjB;AAEA,QAAI,qBAAqB;AACvB,WAAK,sBAAsB;AAAA,IAC7B,OAAO;AACL,WAAK,sBAAsB;AAAA,IAC7B;AAEA,QAAI,wBAAwB;AAC1B,WAAK,yBAAyB;AAAA,IAChC,OAAO;AACL,WAAK,yBAAyB;AAAA,IAChC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,MAMZ;AACD,WAAO,eAAe,MAAM;AAAA,MAC1B,UAAU,CAAC,KAAK,IAAI;AAAA,MACpB,YAAY,KAAK,cAAc;AAAA,MAC/B,SAAS,KAAK,WAAW;AAAA,MACzB,qBAAqB,KAAK;AAAA,MAC1B,wBAAwB,KAAK;AAAA,IAC/B,CAMC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,IACJ,YAOA,SACe;AACf,UAAM,KAAK,OAAO,YAAY,OAAO;AAAA,EACvC;AACF;",
6
6
  "names": []
7
7
  }
@@ -5,8 +5,7 @@ import { type Command } from './Command.js';
5
5
  import { type ProgramCreateOptions } from './ProgramCreateOptions.js';
6
6
  import { type ProgramStreams } from './ProgramStreams.js';
7
7
  /**
8
- * Program manages and executes {@link Command} instances attached to it based on parsing command
9
- * line arguments.
8
+ * Program manages and executes {@link Command} instances attached to it based on parsing command line arguments.
10
9
  */
11
10
  export declare class Program {
12
11
  /** Program name. */
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../source/program/Program.ts"],
4
- "sourcesContent": ["/* eslint-disable @typescript-eslint/no-explicit-any -- needed */\nimport {type Argv, type OptionsConfig, type ParametersConfig} from '@jakubmazanec/args';\nimport fs from 'fs-extra';\nimport fetchLatestVersion from 'latest-version';\nimport path from 'node:path';\nimport {type ComponentType} from 'react';\nimport {type FallbackProps} from 'react-error-boundary';\n\nimport {CACHE_PATH} from '../constants.js';\nimport {Failure, Help} from '../ui.js';\nimport {Wrapper} from '../ui/internals.js';\nimport {type Command} from './Command.js';\nimport {type ProgramCreateOptions} from './ProgramCreateOptions.js';\nimport {ProgramError} from './ProgramError.js';\nimport {type ProgramOptions} from './ProgramOptions.js';\nimport {type ProgramStreams} from './ProgramStreams.js';\n\n/**\n * Program manages and executes {@link Command} instances attached to it based on parsing command\n * line arguments.\n */\nexport class Program {\n /** Program name. */\n readonly name?: string;\n\n /** More readable program name. */\n readonly displayName?: string;\n\n /** Program version. */\n readonly version?: string;\n\n /** Program latest version. */\n readonly latestVersion?: string;\n\n /** Program description. */\n readonly description?: string;\n\n /** Program executable name. */\n readonly bin?: string;\n\n /** Program commands */\n readonly commands: Array<\n Command<string, ParametersConfig | undefined, OptionsConfig | undefined, boolean, boolean>\n > = [];\n\n protected isRendering = false;\n\n readonly streams: ProgramStreams = {\n stderr: process.stderr,\n stdin: process.stdin,\n stdout: process.stdout,\n };\n\n /** Custom error boundary fallback component */\n ErrorBoundaryFallbackComponent: ComponentType<FallbackProps>;\n\n private constructor({\n name,\n displayName,\n version,\n latestVersion,\n description,\n bin,\n ErrorBoundaryFallbackComponent,\n }: ProgramOptions) {\n if (name) {\n this.name = name;\n }\n\n if (displayName) {\n this.displayName = displayName;\n }\n\n if (version) {\n this.version = version;\n }\n\n if (latestVersion) {\n this.latestVersion = latestVersion;\n }\n\n if (description) {\n this.description = description;\n }\n\n if (bin) {\n this.bin = bin;\n }\n\n if (ErrorBoundaryFallbackComponent) {\n this.ErrorBoundaryFallbackComponent = ErrorBoundaryFallbackComponent;\n } else {\n this.ErrorBoundaryFallbackComponent = Failure;\n }\n }\n\n static async create({\n name,\n version,\n description,\n bin,\n ErrorBoundaryFallbackComponent,\n checkForUpdate,\n }: ProgramCreateOptions) {\n let latestVersion: string | undefined;\n\n if (checkForUpdate && name) {\n // first we try to read the cached latest version\n type CachedLatestVersion = {\n value: string;\n datetime: number;\n };\n\n let cachePath = path.join(CACHE_PATH, name, 'latest-version.json');\n let cachedLatestVersion: CachedLatestVersion | undefined;\n\n try {\n cachedLatestVersion = (await fs.readJson(cachePath)) as CachedLatestVersion;\n } catch {\n // no-op\n }\n\n // if there is no cache or the cached value is old, refetch and recache\n if (!cachedLatestVersion || Date.now() - cachedLatestVersion.datetime > 86_400_00) {\n latestVersion = await fetchLatestVersion(name);\n\n await fs.ensureFile(cachePath);\n await fs.writeJson(cachePath, {\n value: latestVersion,\n datetime: Date.now(),\n });\n }\n }\n\n return new this({\n name,\n version,\n latestVersion,\n description,\n bin,\n ErrorBoundaryFallbackComponent,\n });\n }\n\n /**\n * Adds command to the program.\n *\n * @param command Command to add.\n * @returns Program instance.\n */\n addCommand(command: Command<any, any, any, any, any>): this {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument -- it doesn't matter here; `any` is used to make TypeScript happy in this method, but isn't propagated further.\n this.commands.push(command);\n\n return this;\n }\n\n /**\n * Renders a React element using Ink and outputs to the configured streams.\n *\n * @param element The React element to render.\n */\n async renderElement(element: React.ReactElement): Promise<void> {\n if (this.isRendering) {\n throw new ProgramError('NO_NESTED_RENDER');\n } else {\n this.isRendering = true;\n }\n\n let {render} = await import('ink');\n let {createElement} = await import('react');\n let {stdin, stdout, stderr} = this.streams;\n\n try {\n render(createElement(Wrapper, {program: this}, element), {\n exitOnCtrlC: true,\n patchConsole: true,\n stderr,\n stdin,\n stdout,\n });\n } catch (error: unknown) {\n if (error instanceof Error) {\n await this.renderElement(\n createElement(this.ErrorBoundaryFallbackComponent, {error, resetErrorBoundary: () => {}}),\n );\n }\n } finally {\n this.isRendering = false;\n }\n }\n\n /**\n * Runs the program.\n *\n * @param argv Unparsed command line arguments.\n */\n async run(argv: Argv): Promise<void> {\n let hasCommandRun = false;\n\n for (let command of this.commands) {\n let parsedArgs = command.parseArguments(argv);\n\n if (parsedArgs.command) {\n hasCommandRun = true;\n\n if (parsedArgs.errors.length) {\n let {createElement} = await import('react');\n\n for (let error of parsedArgs.errors) {\n process.exitCode = 1;\n\n await this.renderElement(\n createElement(this.ErrorBoundaryFallbackComponent, {\n error,\n resetErrorBoundary: () => {},\n }),\n );\n }\n } else {\n try {\n await command.run(parsedArgs, this);\n } catch (error: unknown) {\n let {createElement} = await import('react');\n\n if (error instanceof Error) {\n process.exitCode = 1;\n\n await this.renderElement(\n createElement(this.ErrorBoundaryFallbackComponent, {\n error,\n resetErrorBoundary: () => {},\n }),\n );\n }\n }\n\n break;\n }\n }\n }\n\n if (!hasCommandRun) {\n let {createElement} = await import('react');\n\n await this.renderElement(createElement(Help, {program: this}));\n }\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/* eslint-disable @typescript-eslint/no-explicit-any -- needed */\nimport {type Argv, type OptionsConfig, type ParametersConfig} from '@jakubmazanec/args';\nimport fs from 'fs-extra';\nimport fetchLatestVersion from 'latest-version';\nimport path from 'node:path';\nimport {type ComponentType} from 'react';\nimport {type FallbackProps} from 'react-error-boundary';\n\nimport {CACHE_PATH} from '../constants.js';\nimport {Failure, Help} from '../ui.js';\nimport {Wrapper} from '../ui/internals.js';\nimport {type Command} from './Command.js';\nimport {type ProgramCreateOptions} from './ProgramCreateOptions.js';\nimport {ProgramError} from './ProgramError.js';\nimport {type ProgramOptions} from './ProgramOptions.js';\nimport {type ProgramStreams} from './ProgramStreams.js';\n\n/**\n * Program manages and executes {@link Command} instances attached to it based on parsing command line arguments.\n */\nexport class Program {\n /** Program name. */\n readonly name?: string;\n\n /** More readable program name. */\n readonly displayName?: string;\n\n /** Program version. */\n readonly version?: string;\n\n /** Program latest version. */\n readonly latestVersion?: string;\n\n /** Program description. */\n readonly description?: string;\n\n /** Program executable name. */\n readonly bin?: string;\n\n /** Program commands */\n readonly commands: Array<\n Command<string, ParametersConfig | undefined, OptionsConfig | undefined, boolean, boolean>\n > = [];\n\n protected isRendering = false;\n\n readonly streams: ProgramStreams = {\n stderr: process.stderr,\n stdin: process.stdin,\n stdout: process.stdout,\n };\n\n /** Custom error boundary fallback component */\n ErrorBoundaryFallbackComponent: ComponentType<FallbackProps>;\n\n private constructor({\n name,\n displayName,\n version,\n latestVersion,\n description,\n bin,\n ErrorBoundaryFallbackComponent,\n }: ProgramOptions) {\n if (name) {\n this.name = name;\n }\n\n if (displayName) {\n this.displayName = displayName;\n }\n\n if (version) {\n this.version = version;\n }\n\n if (latestVersion) {\n this.latestVersion = latestVersion;\n }\n\n if (description) {\n this.description = description;\n }\n\n if (bin) {\n this.bin = bin;\n }\n\n if (ErrorBoundaryFallbackComponent) {\n this.ErrorBoundaryFallbackComponent = ErrorBoundaryFallbackComponent;\n } else {\n this.ErrorBoundaryFallbackComponent = Failure;\n }\n }\n\n static async create({\n name,\n version,\n description,\n bin,\n ErrorBoundaryFallbackComponent,\n checkForUpdate,\n }: ProgramCreateOptions) {\n let latestVersion: string | undefined;\n\n if (checkForUpdate && name) {\n // first we try to read the cached latest version\n type CachedLatestVersion = {\n value: string;\n datetime: number;\n };\n\n let cachePath = path.join(CACHE_PATH, name, 'latest-version.json');\n let cachedLatestVersion: CachedLatestVersion | undefined;\n\n try {\n cachedLatestVersion = (await fs.readJson(cachePath)) as CachedLatestVersion;\n } catch {\n // no-op\n }\n\n // if there is no cache or the cached value is old, refetch and recache\n if (!cachedLatestVersion || Date.now() - cachedLatestVersion.datetime > 86_400_00) {\n latestVersion = await fetchLatestVersion(name);\n\n await fs.ensureFile(cachePath);\n await fs.writeJson(cachePath, {\n value: latestVersion,\n datetime: Date.now(),\n });\n }\n }\n\n return new this({\n name,\n version,\n latestVersion,\n description,\n bin,\n ErrorBoundaryFallbackComponent,\n });\n }\n\n /**\n * Adds command to the program.\n *\n * @param command Command to add.\n * @returns Program instance.\n */\n addCommand(command: Command<any, any, any, any, any>): this {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument -- it doesn't matter here; `any` is used to make TypeScript happy in this method, but isn't propagated further.\n this.commands.push(command);\n\n return this;\n }\n\n /**\n * Renders a React element using Ink and outputs to the configured streams.\n *\n * @param element The React element to render.\n */\n async renderElement(element: React.ReactElement): Promise<void> {\n if (this.isRendering) {\n throw new ProgramError('NO_NESTED_RENDER');\n } else {\n this.isRendering = true;\n }\n\n let {render} = await import('ink');\n let {createElement} = await import('react');\n let {stdin, stdout, stderr} = this.streams;\n\n try {\n render(createElement(Wrapper, {program: this}, element), {\n exitOnCtrlC: true,\n patchConsole: true,\n stderr,\n stdin,\n stdout,\n });\n } catch (error: unknown) {\n if (error instanceof Error) {\n await this.renderElement(\n createElement(this.ErrorBoundaryFallbackComponent, {error, resetErrorBoundary: () => {}}),\n );\n }\n } finally {\n this.isRendering = false;\n }\n }\n\n /**\n * Runs the program.\n *\n * @param argv Unparsed command line arguments.\n */\n async run(argv: Argv): Promise<void> {\n let hasCommandRun = false;\n\n for (let command of this.commands) {\n let parsedArgs = command.parseArguments(argv);\n\n if (parsedArgs.command) {\n hasCommandRun = true;\n\n if (parsedArgs.errors.length) {\n let {createElement} = await import('react');\n\n for (let error of parsedArgs.errors) {\n process.exitCode = 1;\n\n await this.renderElement(\n createElement(this.ErrorBoundaryFallbackComponent, {\n error,\n resetErrorBoundary: () => {},\n }),\n );\n }\n } else {\n try {\n await command.run(parsedArgs, this);\n } catch (error: unknown) {\n let {createElement} = await import('react');\n\n if (error instanceof Error) {\n process.exitCode = 1;\n\n await this.renderElement(\n createElement(this.ErrorBoundaryFallbackComponent, {\n error,\n resetErrorBoundary: () => {},\n }),\n );\n }\n }\n\n break;\n }\n }\n }\n\n if (!hasCommandRun) {\n let {createElement} = await import('react');\n\n await this.renderElement(createElement(Help, {program: this}));\n }\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -4,11 +4,7 @@ import { type ErrorDetail } from './ErrorDetail.js';
4
4
  * {@link Failure} component props.
5
5
  */
6
6
  export type FailureProps = BoxProps & {
7
- /**
8
- * Error that describes a failure state. Function {@link getErrorDetail} is used for getting all
9
- * the information from the error; you can use it to implement own retrieval logic and pass the
10
- * result as `errorDetail` prop.
11
- */
7
+ /** Error that describes a failure state. Function {@link getErrorDetail} is used for getting all the information from the error; you can use it to implement own retrieval logic and pass the result as `errorDetail` prop. */
12
8
  error: unknown;
13
9
  /** Information about the failure state. Overrides information retireved from `error` prop. */
14
10
  errorDetail?: ErrorDetail;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../source/ui/Failure.tsx"],
4
- "sourcesContent": ["import {Box, type BoxProps, Text} from 'ink';\n\nimport * as colors from './colors.js';\nimport {type ErrorDetail} from './ErrorDetail.js';\nimport {getErrorDetail} from './getErrorDetail.js';\nimport {Header} from './Header.js';\nimport * as icons from './icons.js';\n\n/**\n * {@link Failure} component props.\n */\nexport type FailureProps = BoxProps & {\n /**\n * Error that describes a failure state. Function {@link getErrorDetail} is used for getting all\n * the information from the error; you can use it to implement own retrieval logic and pass the\n * result as `errorDetail` prop.\n */\n error: unknown;\n\n /** Information about the failure state. Overrides information retireved from `error` prop. */\n errorDetail?: ErrorDetail;\n};\n\n/**\n * A component that renders a failure state.\n */\nexport function Failure({error, errorDetail, ...boxProps}: FailureProps) {\n let {label, description, stack, cause} = errorDetail ?? getErrorDetail(error);\n\n return (\n <Box {...boxProps} flexDirection=\"column\">\n <Header icon={icons.error}>\n <Text color={colors.highlighted}>{label}</Text>\n </Header>\n\n {description ?\n <Box flexDirection=\"column\" marginLeft={2}>\n <Text color={colors.failure}>{description}</Text>\n </Box>\n : null}\n\n {stack ?\n <Box flexDirection=\"column\" marginLeft={2} marginTop={1}>\n <Text color={colors.muted}>{stack}</Text>\n </Box>\n : null}\n\n {cause ?\n <>\n <Box flexDirection=\"column\" marginLeft={2} marginTop={1}>\n <Text color={colors.muted}>{cause.description}</Text>\n </Box>\n\n {cause.stack ?\n <Box flexDirection=\"column\" marginLeft={2} marginTop={1}>\n <Text color={colors.muted}>{cause.stack}</Text>\n </Box>\n : null}\n </>\n : null}\n </Box>\n );\n}\n"],
5
- "mappings": "AAgCQ,SAgBA,UAhBA,KAgBA,YAhBA;AAhCR,SAAQ,KAAoB,YAAW;AAEvC,YAAY,YAAY;AAExB,SAAQ,sBAAqB;AAC7B,SAAQ,cAAa;AACrB,YAAY,WAAW;AAoBhB,gBAAS,QAAQ,EAAC,OAAO,aAAa,GAAG,SAAQ,GAAiB;AACvE,MAAI,EAAC,OAAO,aAAa,OAAO,MAAK,IAAI,eAAe,eAAe,KAAK;AAE5E,SACE,qBAAC,OAAK,GAAG,UAAU,eAAc,UAC/B;AAAA,wBAAC,UAAO,MAAM,MAAM,OAClB,8BAAC,QAAK,OAAO,OAAO,aAAc,iBAAM,GAC1C;AAAA,IAEC,cACC,oBAAC,OAAI,eAAc,UAAS,YAAY,GACtC,8BAAC,QAAK,OAAO,OAAO,SAAU,uBAAY,GAC5C,IACA;AAAA,IAED,QACC,oBAAC,OAAI,eAAc,UAAS,YAAY,GAAG,WAAW,GACpD,8BAAC,QAAK,OAAO,OAAO,OAAQ,iBAAM,GACpC,IACA;AAAA,IAED,QACC,iCACE;AAAA,0BAAC,OAAI,eAAc,UAAS,YAAY,GAAG,WAAW,GACpD,8BAAC,QAAK,OAAO,OAAO,OAAQ,gBAAM,aAAY,GAChD;AAAA,MAEC,MAAM,QACL,oBAAC,OAAI,eAAc,UAAS,YAAY,GAAG,WAAW,GACpD,8BAAC,QAAK,OAAO,OAAO,OAAQ,gBAAM,OAAM,GAC1C,IACA;AAAA,OACJ,IACA;AAAA,KACJ;AAEJ;",
4
+ "sourcesContent": ["import {Box, type BoxProps, Text} from 'ink';\n\nimport * as colors from './colors.js';\nimport {type ErrorDetail} from './ErrorDetail.js';\nimport {getErrorDetail} from './getErrorDetail.js';\nimport {Header} from './Header.js';\nimport * as icons from './icons.js';\n\n/**\n * {@link Failure} component props.\n */\nexport type FailureProps = BoxProps & {\n /** Error that describes a failure state. Function {@link getErrorDetail} is used for getting all the information from the error; you can use it to implement own retrieval logic and pass the result as `errorDetail` prop. */\n error: unknown;\n\n /** Information about the failure state. Overrides information retireved from `error` prop. */\n errorDetail?: ErrorDetail;\n};\n\n/**\n * A component that renders a failure state.\n */\nexport function Failure({error, errorDetail, ...boxProps}: FailureProps) {\n let {label, description, stack, cause} = errorDetail ?? getErrorDetail(error);\n\n return (\n <Box {...boxProps} flexDirection=\"column\">\n <Header icon={icons.error}>\n <Text color={colors.highlighted}>{label}</Text>\n </Header>\n\n {description ?\n <Box flexDirection=\"column\" marginLeft={2}>\n <Text color={colors.failure}>{description}</Text>\n </Box>\n : null}\n\n {stack ?\n <Box flexDirection=\"column\" marginLeft={2} marginTop={1}>\n <Text color={colors.muted}>{stack}</Text>\n </Box>\n : null}\n\n {cause ?\n <>\n <Box flexDirection=\"column\" marginLeft={2} marginTop={1}>\n <Text color={colors.muted}>{cause.description}</Text>\n </Box>\n\n {cause.stack ?\n <Box flexDirection=\"column\" marginLeft={2} marginTop={1}>\n <Text color={colors.muted}>{cause.stack}</Text>\n </Box>\n : null}\n </>\n : null}\n </Box>\n );\n}\n"],
5
+ "mappings": "AA4BQ,SAgBA,UAhBA,KAgBA,YAhBA;AA5BR,SAAQ,KAAoB,YAAW;AAEvC,YAAY,YAAY;AAExB,SAAQ,sBAAqB;AAC7B,SAAQ,cAAa;AACrB,YAAY,WAAW;AAgBhB,gBAAS,QAAQ,EAAC,OAAO,aAAa,GAAG,SAAQ,GAAiB;AACvE,MAAI,EAAC,OAAO,aAAa,OAAO,MAAK,IAAI,eAAe,eAAe,KAAK;AAE5E,SACE,qBAAC,OAAK,GAAG,UAAU,eAAc,UAC/B;AAAA,wBAAC,UAAO,MAAM,MAAM,OAClB,8BAAC,QAAK,OAAO,OAAO,aAAc,iBAAM,GAC1C;AAAA,IAEC,cACC,oBAAC,OAAI,eAAc,UAAS,YAAY,GACtC,8BAAC,QAAK,OAAO,OAAO,SAAU,uBAAY,GAC5C,IACA;AAAA,IAED,QACC,oBAAC,OAAI,eAAc,UAAS,YAAY,GAAG,WAAW,GACpD,8BAAC,QAAK,OAAO,OAAO,OAAQ,iBAAM,GACpC,IACA;AAAA,IAED,QACC,iCACE;AAAA,0BAAC,OAAI,eAAc,UAAS,YAAY,GAAG,WAAW,GACpD,8BAAC,QAAK,OAAO,OAAO,OAAQ,gBAAM,aAAY,GAChD;AAAA,MAEC,MAAM,QACL,oBAAC,OAAI,eAAc,UAAS,YAAY,GAAG,WAAW,GACpD,8BAAC,QAAK,OAAO,OAAO,OAAQ,gBAAM,OAAM,GAC1C,IACA;AAAA,OACJ,IACA;AAAA,KACJ;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -14,19 +14,13 @@ type FormRowProps<C extends FormConfig> = BoxProps & {
14
14
  rowName: keyof C['rows'];
15
15
  /** Value. */
16
16
  value: unknown;
17
- /**
18
- * Should component listen to Listen to user's input? Useful in case there are multiple input
19
- * components at the same time and input must be "routed" to a specific component.
20
- */
17
+ /** Should component listen to Listen to user's input? Useful in case there are multiple input components at the same time and input must be "routed" to a specific component. */
21
18
  focus: boolean;
22
19
  /** Handler function that is called when value changes. */
23
20
  onChange: (value: unknown, inputName: keyof C['rows']) => void;
24
21
  /** Handler function that is called when the value is accepted. */
25
22
  onComplete: (value: unknown, inputName: keyof C['rows']) => void;
26
- /**
27
- * Indicates whether value has been accepted. Component in the row then doesn't accept more
28
- * input.
29
- */
23
+ /** Indicates whether value has been accepted. Component in the row then doesn't accept more input. */
30
24
  isComplete: boolean;
31
25
  };
32
26
  /**
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../source/ui/form/FormRow.tsx"],
4
- "sourcesContent": ["import {type BoxProps} from 'ink';\nimport {useCallback} from 'react';\n\nimport {type FormConfig} from './FormConfig.js';\nimport {type FormProps} from './FormProps.js';\nimport {type FormRowConfig} from './FormRowConfig.js';\nimport {SelectInput} from './SelectInput.js';\nimport {TextInput} from './TextInput.js';\n\n/**\n * Form row component props.\n */\ntype FormRowProps<C extends FormConfig> = BoxProps & {\n /** Form row configuration. */\n config: FormRowConfig;\n\n // TODO: Should all rows props be passed to each row?\n /** Props of all form rows. */\n rows: FormProps<C>['rows'] | null;\n\n /** Row name. */\n rowName: keyof C['rows'];\n\n /** Value. */\n value: unknown;\n\n /**\n * Should component listen to Listen to user's input? Useful in case there are multiple input\n * components at the same time and input must be \"routed\" to a specific component.\n */\n focus: boolean;\n\n /** Handler function that is called when value changes. */\n onChange: (value: unknown, inputName: keyof C['rows']) => void;\n\n /** Handler function that is called when the value is accepted. */\n onComplete: (value: unknown, inputName: keyof C['rows']) => void;\n\n /**\n * Indicates whether value has been accepted. Component in the row then doesn't accept more\n * input.\n */\n isComplete: boolean;\n};\n\n/**\n * Form row component.\n */\nexport function FormRow<C extends FormConfig>({\n rowName,\n config,\n rows,\n value,\n focus,\n isComplete,\n onChange,\n onComplete,\n ...boxProps\n}: FormRowProps<C>) {\n // TODO: Each input component handles values and events differently; the APIs should be adjusted.\n let handleChange = useCallback(\n (newValue: unknown) => {\n onChange(newValue, rowName);\n },\n [rowName, onChange],\n );\n\n let handleFinish = useCallback(\n (newValue: unknown) => {\n onComplete(newValue, rowName);\n },\n [rowName, onComplete],\n );\n\n let handleSelectFinish = useCallback(\n (item: {value: unknown}) => {\n onComplete(item.value, rowName);\n },\n [rowName, onComplete],\n );\n\n switch (config.type) {\n case 'confirm': {\n return null;\n }\n case 'select': {\n return (\n <SelectInput\n key={String(rowName)}\n items={\n rows ?\n (\n (\n rows as {\n [key: string]: unknown;\n }\n )[rowName as string] as {choices: Array<{value: string; label: string}>}\n ).choices\n : []\n }\n focus={focus}\n isComplete={isComplete}\n label={config.label ?? ''}\n onSelect={handleSelectFinish}\n {...boxProps}\n />\n );\n }\n case 'text': {\n return (\n <TextInput\n key={String(rowName)}\n focus={focus}\n isComplete={isComplete}\n label={config.label ?? ''}\n validate={config.validate}\n value={value as string}\n onChange={handleChange}\n onSubmit={handleFinish}\n {...boxProps}\n />\n );\n }\n default: {\n config satisfies never;\n\n return null;\n }\n }\n}\n"],
5
- "mappings": "AAuFQ;AAtFR,SAAQ,mBAAkB;AAK1B,SAAQ,mBAAkB;AAC1B,SAAQ,iBAAgB;AAyCjB,gBAAS,QAA8B;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAoB;AAElB,MAAI,eAAe;AAAA,IACjB,CAAC,aAAsB;AACrB,eAAS,UAAU,OAAO;AAAA,IAC5B;AAAA,IACA,CAAC,SAAS,QAAQ;AAAA,EACpB;AAEA,MAAI,eAAe;AAAA,IACjB,CAAC,aAAsB;AACrB,iBAAW,UAAU,OAAO;AAAA,IAC9B;AAAA,IACA,CAAC,SAAS,UAAU;AAAA,EACtB;AAEA,MAAI,qBAAqB;AAAA,IACvB,CAAC,SAA2B;AAC1B,iBAAW,KAAK,OAAO,OAAO;AAAA,IAChC;AAAA,IACA,CAAC,SAAS,UAAU;AAAA,EACtB;AAEA,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK,WAAW;AACd,aAAO;AAAA,IACT;AAAA,IACA,KAAK,UAAU;AACb,aACE;AAAA,QAAC;AAAA;AAAA,UAEC,OACE,OAGM,KAGA,OAAiB,EACnB,UACF,CAAC;AAAA,UAEL;AAAA,UACA;AAAA,UACA,OAAO,OAAO,SAAS;AAAA,UACvB,UAAU;AAAA,UACT,GAAG;AAAA;AAAA,QAhBC,OAAO,OAAO;AAAA,MAiBrB;AAAA,IAEJ;AAAA,IACA,KAAK,QAAQ;AACX,aACE;AAAA,QAAC;AAAA;AAAA,UAEC;AAAA,UACA;AAAA,UACA,OAAO,OAAO,SAAS;AAAA,UACvB,UAAU,OAAO;AAAA,UACjB;AAAA,UACA,UAAU;AAAA,UACV,UAAU;AAAA,UACT,GAAG;AAAA;AAAA,QARC,OAAO,OAAO;AAAA,MASrB;AAAA,IAEJ;AAAA,IACA,SAAS;AACP;AAEA,aAAO;AAAA,IACT;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import {type BoxProps} from 'ink';\nimport {useCallback} from 'react';\n\nimport {type FormConfig} from './FormConfig.js';\nimport {type FormProps} from './FormProps.js';\nimport {type FormRowConfig} from './FormRowConfig.js';\nimport {SelectInput} from './SelectInput.js';\nimport {TextInput} from './TextInput.js';\n\n/**\n * Form row component props.\n */\ntype FormRowProps<C extends FormConfig> = BoxProps & {\n /** Form row configuration. */\n config: FormRowConfig;\n\n // TODO: Should all rows props be passed to each row?\n /** Props of all form rows. */\n rows: FormProps<C>['rows'] | null;\n\n /** Row name. */\n rowName: keyof C['rows'];\n\n /** Value. */\n value: unknown;\n\n /** Should component listen to Listen to user's input? Useful in case there are multiple input components at the same time and input must be \"routed\" to a specific component. */\n focus: boolean;\n\n /** Handler function that is called when value changes. */\n onChange: (value: unknown, inputName: keyof C['rows']) => void;\n\n /** Handler function that is called when the value is accepted. */\n onComplete: (value: unknown, inputName: keyof C['rows']) => void;\n\n /** Indicates whether value has been accepted. Component in the row then doesn't accept more input. */\n isComplete: boolean;\n};\n\n/**\n * Form row component.\n */\nexport function FormRow<C extends FormConfig>({\n rowName,\n config,\n rows,\n value,\n focus,\n isComplete,\n onChange,\n onComplete,\n ...boxProps\n}: FormRowProps<C>) {\n // TODO: Each input component handles values and events differently; the APIs should be adjusted.\n let handleChange = useCallback(\n (newValue: unknown) => {\n onChange(newValue, rowName);\n },\n [rowName, onChange],\n );\n\n let handleFinish = useCallback(\n (newValue: unknown) => {\n onComplete(newValue, rowName);\n },\n [rowName, onComplete],\n );\n\n let handleSelectFinish = useCallback(\n (item: {value: unknown}) => {\n onComplete(item.value, rowName);\n },\n [rowName, onComplete],\n );\n\n switch (config.type) {\n case 'confirm': {\n return null;\n }\n case 'select': {\n return (\n <SelectInput\n key={String(rowName)}\n items={\n rows ?\n (\n (\n rows as {\n [key: string]: unknown;\n }\n )[rowName as string] as {choices: Array<{value: string; label: string}>}\n ).choices\n : []\n }\n focus={focus}\n isComplete={isComplete}\n label={config.label ?? ''}\n onSelect={handleSelectFinish}\n {...boxProps}\n />\n );\n }\n case 'text': {\n return (\n <TextInput\n key={String(rowName)}\n focus={focus}\n isComplete={isComplete}\n label={config.label ?? ''}\n validate={config.validate}\n value={value as string}\n onChange={handleChange}\n onSubmit={handleFinish}\n {...boxProps}\n />\n );\n }\n default: {\n config satisfies never;\n\n return null;\n }\n }\n}\n"],
5
+ "mappings": "AAiFQ;AAhFR,SAAQ,mBAAkB;AAK1B,SAAQ,mBAAkB;AAC1B,SAAQ,iBAAgB;AAmCjB,gBAAS,QAA8B;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAoB;AAElB,MAAI,eAAe;AAAA,IACjB,CAAC,aAAsB;AACrB,eAAS,UAAU,OAAO;AAAA,IAC5B;AAAA,IACA,CAAC,SAAS,QAAQ;AAAA,EACpB;AAEA,MAAI,eAAe;AAAA,IACjB,CAAC,aAAsB;AACrB,iBAAW,UAAU,OAAO;AAAA,IAC9B;AAAA,IACA,CAAC,SAAS,UAAU;AAAA,EACtB;AAEA,MAAI,qBAAqB;AAAA,IACvB,CAAC,SAA2B;AAC1B,iBAAW,KAAK,OAAO,OAAO;AAAA,IAChC;AAAA,IACA,CAAC,SAAS,UAAU;AAAA,EACtB;AAEA,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK,WAAW;AACd,aAAO;AAAA,IACT;AAAA,IACA,KAAK,UAAU;AACb,aACE;AAAA,QAAC;AAAA;AAAA,UAEC,OACE,OAGM,KAGA,OAAiB,EACnB,UACF,CAAC;AAAA,UAEL;AAAA,UACA;AAAA,UACA,OAAO,OAAO,SAAS;AAAA,UACvB,UAAU;AAAA,UACT,GAAG;AAAA;AAAA,QAhBC,OAAO,OAAO;AAAA,MAiBrB;AAAA,IAEJ;AAAA,IACA,KAAK,QAAQ;AACX,aACE;AAAA,QAAC;AAAA;AAAA,UAEC;AAAA,UACA;AAAA,UACA,OAAO,OAAO,SAAS;AAAA,UACvB,UAAU,OAAO;AAAA,UACjB;AAAA,UACA,UAAU;AAAA,UACV,UAAU;AAAA,UACT,GAAG;AAAA;AAAA,QARC,OAAO,OAAO;AAAA,MASrB;AAAA,IAEJ;AAAA,IACA,SAAS;AACP;AAEA,aAAO;AAAA,IACT;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -9,10 +9,7 @@ type SelectInputProps = BoxProps & {
9
9
  label: string;
10
10
  /** Items to display in a list. */
11
11
  items: SelectInputItem[];
12
- /**
13
- * Should component listen to user's input? Useful in case there are multiple input components at
14
- * the same time and input must be handled only by a specific component.
15
- */
12
+ /** Should component listen to user's input? Useful in case there are multiple input components at the same time and input must be handled only by a specific component. */
16
13
  focus?: boolean | undefined;
17
14
  /** Index of initially selected item. */
18
15
  initialIndex?: number | undefined;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../source/ui/form/SelectInput.tsx"],
4
- "sourcesContent": ["import {Box, type BoxProps, type Key, Text, useInput} from 'ink';\nimport _ from 'lodash';\nimport React, {useEffect, useRef, useState} from 'react';\n\nimport * as colors from '../colors.js';\nimport * as icons from '../icons.js';\nimport {rotate} from '../internals.js';\nimport {type SelectInputItem} from './SelectInputItem.js';\n\n/**\n * {@linkcode SelectInput} component props.\n */\ntype SelectInputProps = BoxProps & {\n /** Text to display as a label. */\n label: string;\n\n /** Items to display in a list. */\n items: SelectInputItem[];\n\n /**\n * Should component listen to user's input? Useful in case there are multiple input components at\n * the same time and input must be handled only by a specific component.\n */\n focus?: boolean | undefined;\n\n /** Index of initially selected item. */\n initialIndex?: number | undefined;\n\n /** Number of items to display. */\n limit?: number | undefined;\n\n /** Handler function that is called when item is selected. */\n onSelect?: ((item: SelectInputItem) => void) | undefined;\n\n /** Handler function that is called when item is highlighted. */\n onHighlight?: ((item: SelectInputItem) => void) | undefined;\n\n /** Indicates whether value has been accepted. Component then doesn't accept more input. */\n isComplete?: boolean | undefined;\n};\n\n/**\n * Select input component.\n */\nexport function SelectInput({\n label,\n items,\n focus = true,\n initialIndex = 0,\n limit: userDefinedLimit,\n onSelect,\n onHighlight,\n isComplete,\n ...boxProps\n}: SelectInputProps): React.JSX.Element {\n let [rotatedIndex, setRotatedIndex] = useState(0);\n let [selectedIndex, setSelectedIndex] = useState(initialIndex);\n let hasLimit = typeof userDefinedLimit === 'number' && items.length > userDefinedLimit;\n let limit = hasLimit ? Math.min(userDefinedLimit as number, items.length) : items.length;\n let previousItems = useRef<SelectInputItem[]>(items);\n\n useEffect(() => {\n if (\n !_.isEqual(\n previousItems.current.map((item) => item.value),\n items.map((item) => item.value),\n )\n ) {\n setRotatedIndex(0);\n setSelectedIndex(0);\n }\n\n previousItems.current = items;\n }, [items]);\n\n useInput(\n (input: string, key: Key) => {\n if (input === 'k' || key.upArrow) {\n let lastIndex = (hasLimit ? limit : items.length) - 1;\n let isAtFirstIndex = selectedIndex === 0;\n let nextIndex = hasLimit ? selectedIndex : lastIndex;\n let nextRotatedIndex = isAtFirstIndex ? rotatedIndex + 1 : rotatedIndex;\n let nextSelectedIndex = isAtFirstIndex ? nextIndex : selectedIndex - 1;\n\n setRotatedIndex(nextRotatedIndex);\n setSelectedIndex(nextSelectedIndex);\n\n let slicedItems = hasLimit ? rotate(items, nextRotatedIndex).slice(0, limit) : items;\n\n if (typeof onHighlight === 'function') {\n onHighlight(slicedItems[nextSelectedIndex] as SelectInputItem);\n }\n }\n\n if (input === 'j' || key.downArrow) {\n let isAtLastIndex = selectedIndex === (hasLimit ? limit : items.length) - 1;\n let nextIndex = hasLimit ? selectedIndex : 0;\n let nextRotatedIndex = isAtLastIndex ? rotatedIndex - 1 : rotatedIndex;\n let nextSelectedIndex = isAtLastIndex ? nextIndex : selectedIndex + 1;\n\n setRotatedIndex(nextRotatedIndex);\n setSelectedIndex(nextSelectedIndex);\n\n let slicedItems = hasLimit ? rotate(items, nextRotatedIndex).slice(0, limit) : items;\n\n if (typeof onHighlight === 'function') {\n onHighlight(slicedItems[nextSelectedIndex] as SelectInputItem);\n }\n }\n\n if (key.return) {\n let slicedItems = hasLimit ? rotate(items, rotatedIndex).slice(0, limit) : items;\n\n if (typeof onSelect === 'function') {\n onSelect(slicedItems[selectedIndex] as SelectInputItem);\n }\n }\n },\n {isActive: focus},\n );\n\n let visibleItems: SelectInputItem[] =\n hasLimit ? rotate(items, rotatedIndex).slice(0, limit) : items;\n\n return (\n <Box {...boxProps}>\n <Box marginRight={1}>\n <Text>{isComplete ? icons.success : icons.question}</Text>\n </Box>\n\n <Box flexDirection=\"column\">\n <Box marginRight={1}>\n <Text color={colors.highlighted}>{label}</Text>\n </Box>\n {isComplete ?\n <Text color={colors.body}>\n {items[selectedIndex]?.label ?? String(items[selectedIndex]?.value)}\n </Text>\n : <Box flexDirection=\"column\">\n {visibleItems.map((item, index) => {\n let isSelected = index === selectedIndex;\n\n return (\n <Box key={item.value}>\n <Box marginRight={1}>\n {isSelected ?\n <Text color={colors.selected}>{icons.selectedCircle}</Text>\n : <Text color={colors.unselected}>{icons.unselectedCircle}</Text>}\n </Box>\n <Text color={isSelected ? colors.highlighted : colors.muted}>{item.label}</Text>\n </Box>\n );\n })}\n </Box>\n }\n </Box>\n </Box>\n );\n}\n\n// partially based on https://github.com/vadimdemedes/ink-select-input/tree/309497ca641f55d8df0083ec2d07264f101358e4 (see https://github.com/vadimdemedes/ink-select-input/blob/309497ca641f55d8df0083ec2d07264f101358e4/license for license)\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {Box, type BoxProps, type Key, Text, useInput} from 'ink';\nimport _ from 'lodash';\nimport React, {useEffect, useRef, useState} from 'react';\n\nimport * as colors from '../colors.js';\nimport * as icons from '../icons.js';\nimport {rotate} from '../internals.js';\nimport {type SelectInputItem} from './SelectInputItem.js';\n\n/**\n * {@linkcode SelectInput} component props.\n */\ntype SelectInputProps = BoxProps & {\n /** Text to display as a label. */\n label: string;\n\n /** Items to display in a list. */\n items: SelectInputItem[];\n\n /** Should component listen to user's input? Useful in case there are multiple input components at the same time and input must be handled only by a specific component. */\n focus?: boolean | undefined;\n\n /** Index of initially selected item. */\n initialIndex?: number | undefined;\n\n /** Number of items to display. */\n limit?: number | undefined;\n\n /** Handler function that is called when item is selected. */\n onSelect?: ((item: SelectInputItem) => void) | undefined;\n\n /** Handler function that is called when item is highlighted. */\n onHighlight?: ((item: SelectInputItem) => void) | undefined;\n\n /** Indicates whether value has been accepted. Component then doesn't accept more input. */\n isComplete?: boolean | undefined;\n};\n\n/**\n * Select input component.\n */\nexport function SelectInput({\n label,\n items,\n focus = true,\n initialIndex = 0,\n limit: userDefinedLimit,\n onSelect,\n onHighlight,\n isComplete,\n ...boxProps\n}: SelectInputProps): React.JSX.Element {\n let [rotatedIndex, setRotatedIndex] = useState(0);\n let [selectedIndex, setSelectedIndex] = useState(initialIndex);\n let hasLimit = typeof userDefinedLimit === 'number' && items.length > userDefinedLimit;\n let limit = hasLimit ? Math.min(userDefinedLimit as number, items.length) : items.length;\n let previousItems = useRef<SelectInputItem[]>(items);\n\n useEffect(() => {\n if (\n !_.isEqual(\n previousItems.current.map((item) => item.value),\n items.map((item) => item.value),\n )\n ) {\n setRotatedIndex(0);\n setSelectedIndex(0);\n }\n\n previousItems.current = items;\n }, [items]);\n\n useInput(\n (input: string, key: Key) => {\n if (input === 'k' || key.upArrow) {\n let lastIndex = (hasLimit ? limit : items.length) - 1;\n let isAtFirstIndex = selectedIndex === 0;\n let nextIndex = hasLimit ? selectedIndex : lastIndex;\n let nextRotatedIndex = isAtFirstIndex ? rotatedIndex + 1 : rotatedIndex;\n let nextSelectedIndex = isAtFirstIndex ? nextIndex : selectedIndex - 1;\n\n setRotatedIndex(nextRotatedIndex);\n setSelectedIndex(nextSelectedIndex);\n\n let slicedItems = hasLimit ? rotate(items, nextRotatedIndex).slice(0, limit) : items;\n\n if (typeof onHighlight === 'function') {\n onHighlight(slicedItems[nextSelectedIndex] as SelectInputItem);\n }\n }\n\n if (input === 'j' || key.downArrow) {\n let isAtLastIndex = selectedIndex === (hasLimit ? limit : items.length) - 1;\n let nextIndex = hasLimit ? selectedIndex : 0;\n let nextRotatedIndex = isAtLastIndex ? rotatedIndex - 1 : rotatedIndex;\n let nextSelectedIndex = isAtLastIndex ? nextIndex : selectedIndex + 1;\n\n setRotatedIndex(nextRotatedIndex);\n setSelectedIndex(nextSelectedIndex);\n\n let slicedItems = hasLimit ? rotate(items, nextRotatedIndex).slice(0, limit) : items;\n\n if (typeof onHighlight === 'function') {\n onHighlight(slicedItems[nextSelectedIndex] as SelectInputItem);\n }\n }\n\n if (key.return) {\n let slicedItems = hasLimit ? rotate(items, rotatedIndex).slice(0, limit) : items;\n\n if (typeof onSelect === 'function') {\n onSelect(slicedItems[selectedIndex] as SelectInputItem);\n }\n }\n },\n {isActive: focus},\n );\n\n let visibleItems: SelectInputItem[] =\n hasLimit ? rotate(items, rotatedIndex).slice(0, limit) : items;\n\n return (\n <Box {...boxProps}>\n <Box marginRight={1}>\n <Text>{isComplete ? icons.success : icons.question}</Text>\n </Box>\n\n <Box flexDirection=\"column\">\n <Box marginRight={1}>\n <Text color={colors.highlighted}>{label}</Text>\n </Box>\n {isComplete ?\n <Text color={colors.body}>\n {items[selectedIndex]?.label ?? String(items[selectedIndex]?.value)}\n </Text>\n : <Box flexDirection=\"column\">\n {visibleItems.map((item, index) => {\n let isSelected = index === selectedIndex;\n\n return (\n <Box key={item.value}>\n <Box marginRight={1}>\n {isSelected ?\n <Text color={colors.selected}>{icons.selectedCircle}</Text>\n : <Text color={colors.unselected}>{icons.unselectedCircle}</Text>}\n </Box>\n <Text color={isSelected ? colors.highlighted : colors.muted}>{item.label}</Text>\n </Box>\n );\n })}\n </Box>\n }\n </Box>\n </Box>\n );\n}\n\n// partially based on https://github.com/vadimdemedes/ink-select-input/tree/309497ca641f55d8df0083ec2d07264f101358e4 (see https://github.com/vadimdemedes/ink-select-input/blob/309497ca641f55d8df0083ec2d07264f101358e4/license for license)\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -9,10 +9,7 @@ export type TextInputProps = BoxProps & {
9
9
  placeholder?: string | undefined;
10
10
  /** Value. */
11
11
  value: string;
12
- /**
13
- * Should component listen to Listen to user's input? Useful in case there are multiple input
14
- * components at the same time and input must be handled only by a specific component.
15
- */
12
+ /** Should component listen to Listen to user's input? Useful in case there are multiple input components at the same time and input must be handled only by a specific component. */
16
13
  focus?: boolean | undefined;
17
14
  /** Replace all chars and mask the value. Useful for password inputs. */
18
15
  mask?: string | undefined;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../source/ui/form/TextInput.tsx"],
4
- "sourcesContent": ["import chalk from 'chalk';\nimport {Box, type BoxProps, Text, useInput} from 'ink';\nimport {useEffect, useState} from 'react';\n\nimport * as colors from '../colors.js';\nimport * as icons from '../icons.js';\n\n/**\n * Text input component props.\n */\nexport type TextInputProps = BoxProps & {\n /** Text to display as a label. */\n label: string;\n\n /** Text to display when `value` is empty. */\n placeholder?: string | undefined;\n\n /** Value. */\n value: string;\n\n /**\n * Should component listen to Listen to user's input? Useful in case there are multiple input\n * components at the same time and input must be handled only by a specific component.\n */\n focus?: boolean | undefined;\n\n /** Replace all chars and mask the value. Useful for password inputs. */\n mask?: string | undefined;\n\n /** Show cursor and allow navigation using arrow keys. */\n showCursor?: boolean | undefined;\n\n /** Validation function that is called when value changes. If this function throws an error*/\n validate?: ((value: string) => void) | undefined;\n\n /** Handler function that is called when value changes. */\n onChange: (value: string) => void;\n\n /** Handler function that is called when enter is pressed. */\n onSubmit?: ((value: string) => void) | undefined;\n\n /** Indicates whether value has been accepted. Component then doesn't accept more input. */\n isComplete?: boolean | undefined;\n};\n\n/**\n * Text input component.\n */\nexport function TextInput({\n label,\n validate,\n isComplete,\n value: originalValue,\n placeholder = '',\n focus = true,\n mask,\n showCursor = true,\n onChange,\n onSubmit,\n ...boxProps\n}: TextInputProps) {\n let [validationError, setValidationError] = useState('');\n let [state, setState] = useState({\n cursorOffset: (originalValue || '').length,\n cursorWidth: 0,\n });\n\n useEffect(() => {\n setState((previousState) => {\n if (!focus || !showCursor) {\n return previousState;\n }\n\n let newValue = originalValue || '';\n\n if (previousState.cursorOffset > newValue.length - 1) {\n return {\n cursorOffset: newValue.length,\n cursorWidth: 0,\n };\n }\n\n return previousState;\n });\n }, [originalValue, focus, showCursor]);\n\n let value = mask ? mask.repeat(originalValue.length) : originalValue;\n let renderedValue = value;\n let renderedPlaceholder = placeholder ? chalk[colors.muted](placeholder) : undefined;\n\n if (showCursor && focus) {\n renderedPlaceholder =\n placeholder.length > 0 ?\n chalk.inverse(placeholder[0]) + chalk[colors.muted](placeholder.slice(1))\n : chalk.inverse(' ');\n\n renderedValue = value.length > 0 ? '' : chalk.inverse(' ');\n\n for (let [i, character] of Object.entries(value)) {\n if (Number(i) >= state.cursorOffset && Number(i) <= state.cursorOffset) {\n renderedValue += chalk.inverse(character);\n } else {\n renderedValue += character;\n }\n }\n\n if (value.length > 0 && state.cursorOffset === value.length) {\n renderedValue += chalk.inverse(' ');\n }\n }\n\n useInput(\n (input, key) => {\n if (\n key.upArrow ||\n key.downArrow ||\n (key.ctrl && input === 'c') ||\n (key.shift && key.tab) ||\n key.tab\n ) {\n return;\n }\n\n if (key.return) {\n if (onSubmit) {\n if (validate) {\n try {\n validate(originalValue);\n } catch (error: unknown) {\n setValidationError((error as Error).message);\n\n return;\n }\n }\n\n if (validationError) {\n setValidationError('');\n } else {\n onSubmit(originalValue);\n }\n }\n\n return;\n }\n\n let nextCursorOffset = state.cursorOffset;\n let nextValue = originalValue;\n let nextCursorWidth = 0;\n\n if (key.leftArrow) {\n if (showCursor) {\n nextCursorOffset -= 1;\n }\n } else if (key.rightArrow) {\n if (showCursor) {\n nextCursorOffset += 1;\n }\n } else if (key.backspace || key.delete) {\n if (state.cursorOffset > 0) {\n nextValue =\n originalValue.slice(0, state.cursorOffset - 1) +\n originalValue.slice(state.cursorOffset);\n\n nextCursorOffset -= 1;\n }\n } else {\n nextValue =\n originalValue.slice(0, state.cursorOffset) +\n input +\n originalValue.slice(state.cursorOffset);\n\n nextCursorOffset += input.length;\n\n if (input.length > 1) {\n nextCursorWidth = input.length;\n }\n }\n\n if (state.cursorOffset < 0) {\n nextCursorOffset = 0;\n }\n\n if (state.cursorOffset > originalValue.length) {\n nextCursorOffset = originalValue.length;\n }\n\n setState({\n cursorOffset: nextCursorOffset,\n cursorWidth: nextCursorWidth,\n });\n\n if (nextValue !== originalValue) {\n onChange(nextValue);\n }\n },\n {isActive: focus},\n );\n\n return (\n <Box {...boxProps}>\n <Box marginRight={1}>\n <Text>{isComplete ? icons.success : icons.question}</Text>\n </Box>\n\n <Box flexDirection=\"column\">\n <Box marginRight={1}>\n <Text color={colors.highlighted}>{label}</Text>\n </Box>\n {isComplete ?\n <Text color={colors.body}>{value}</Text>\n : <Text color={colors.highlighted}>\n {placeholder ?\n value.length > 0 ?\n renderedValue\n : renderedPlaceholder\n : renderedValue}\n </Text>\n }\n {validationError ?\n <Box marginTop={0}>\n <Text color={colors.warning}>{validationError}</Text>\n </Box>\n : null}\n </Box>\n </Box>\n );\n}\n\n// partially based on https://github.com/vadimdemedes/ink-text-input/tree/0787c505415f0d059801d80600e4ccb0651385f3 (see https://github.com/vadimdemedes/ink-text-input/blob/0787c505415f0d059801d80600e4ccb0651385f3/license for license)\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import chalk from 'chalk';\nimport {Box, type BoxProps, Text, useInput} from 'ink';\nimport {useEffect, useState} from 'react';\n\nimport * as colors from '../colors.js';\nimport * as icons from '../icons.js';\n\n/**\n * Text input component props.\n */\nexport type TextInputProps = BoxProps & {\n /** Text to display as a label. */\n label: string;\n\n /** Text to display when `value` is empty. */\n placeholder?: string | undefined;\n\n /** Value. */\n value: string;\n\n /** Should component listen to Listen to user's input? Useful in case there are multiple input components at the same time and input must be handled only by a specific component. */\n focus?: boolean | undefined;\n\n /** Replace all chars and mask the value. Useful for password inputs. */\n mask?: string | undefined;\n\n /** Show cursor and allow navigation using arrow keys. */\n showCursor?: boolean | undefined;\n\n /** Validation function that is called when value changes. If this function throws an error*/\n validate?: ((value: string) => void) | undefined;\n\n /** Handler function that is called when value changes. */\n onChange: (value: string) => void;\n\n /** Handler function that is called when enter is pressed. */\n onSubmit?: ((value: string) => void) | undefined;\n\n /** Indicates whether value has been accepted. Component then doesn't accept more input. */\n isComplete?: boolean | undefined;\n};\n\n/**\n * Text input component.\n */\nexport function TextInput({\n label,\n validate,\n isComplete,\n value: originalValue,\n placeholder = '',\n focus = true,\n mask,\n showCursor = true,\n onChange,\n onSubmit,\n ...boxProps\n}: TextInputProps) {\n let [validationError, setValidationError] = useState('');\n let [state, setState] = useState({\n cursorOffset: (originalValue || '').length,\n cursorWidth: 0,\n });\n\n useEffect(() => {\n setState((previousState) => {\n if (!focus || !showCursor) {\n return previousState;\n }\n\n let newValue = originalValue || '';\n\n if (previousState.cursorOffset > newValue.length - 1) {\n return {\n cursorOffset: newValue.length,\n cursorWidth: 0,\n };\n }\n\n return previousState;\n });\n }, [originalValue, focus, showCursor]);\n\n let value = mask ? mask.repeat(originalValue.length) : originalValue;\n let renderedValue = value;\n let renderedPlaceholder = placeholder ? chalk[colors.muted](placeholder) : undefined;\n\n if (showCursor && focus) {\n renderedPlaceholder =\n placeholder.length > 0 ?\n chalk.inverse(placeholder[0]) + chalk[colors.muted](placeholder.slice(1))\n : chalk.inverse(' ');\n\n renderedValue = value.length > 0 ? '' : chalk.inverse(' ');\n\n for (let [i, character] of Object.entries(value)) {\n if (Number(i) >= state.cursorOffset && Number(i) <= state.cursorOffset) {\n renderedValue += chalk.inverse(character);\n } else {\n renderedValue += character;\n }\n }\n\n if (value.length > 0 && state.cursorOffset === value.length) {\n renderedValue += chalk.inverse(' ');\n }\n }\n\n useInput(\n (input, key) => {\n if (\n key.upArrow ||\n key.downArrow ||\n (key.ctrl && input === 'c') ||\n (key.shift && key.tab) ||\n key.tab\n ) {\n return;\n }\n\n if (key.return) {\n if (onSubmit) {\n if (validate) {\n try {\n validate(originalValue);\n } catch (error: unknown) {\n setValidationError((error as Error).message);\n\n return;\n }\n }\n\n if (validationError) {\n setValidationError('');\n } else {\n onSubmit(originalValue);\n }\n }\n\n return;\n }\n\n let nextCursorOffset = state.cursorOffset;\n let nextValue = originalValue;\n let nextCursorWidth = 0;\n\n if (key.leftArrow) {\n if (showCursor) {\n nextCursorOffset -= 1;\n }\n } else if (key.rightArrow) {\n if (showCursor) {\n nextCursorOffset += 1;\n }\n } else if (key.backspace || key.delete) {\n if (state.cursorOffset > 0) {\n nextValue =\n originalValue.slice(0, state.cursorOffset - 1) +\n originalValue.slice(state.cursorOffset);\n\n nextCursorOffset -= 1;\n }\n } else {\n nextValue =\n originalValue.slice(0, state.cursorOffset) +\n input +\n originalValue.slice(state.cursorOffset);\n\n nextCursorOffset += input.length;\n\n if (input.length > 1) {\n nextCursorWidth = input.length;\n }\n }\n\n if (state.cursorOffset < 0) {\n nextCursorOffset = 0;\n }\n\n if (state.cursorOffset > originalValue.length) {\n nextCursorOffset = originalValue.length;\n }\n\n setState({\n cursorOffset: nextCursorOffset,\n cursorWidth: nextCursorWidth,\n });\n\n if (nextValue !== originalValue) {\n onChange(nextValue);\n }\n },\n {isActive: focus},\n );\n\n return (\n <Box {...boxProps}>\n <Box marginRight={1}>\n <Text>{isComplete ? icons.success : icons.question}</Text>\n </Box>\n\n <Box flexDirection=\"column\">\n <Box marginRight={1}>\n <Text color={colors.highlighted}>{label}</Text>\n </Box>\n {isComplete ?\n <Text color={colors.body}>{value}</Text>\n : <Text color={colors.highlighted}>\n {placeholder ?\n value.length > 0 ?\n renderedValue\n : renderedPlaceholder\n : renderedValue}\n </Text>\n }\n {validationError ?\n <Box marginTop={0}>\n <Text color={colors.warning}>{validationError}</Text>\n </Box>\n : null}\n </Box>\n </Box>\n );\n}\n\n// partially based on https://github.com/vadimdemedes/ink-text-input/tree/0787c505415f0d059801d80600e4ccb0651385f3 (see https://github.com/vadimdemedes/ink-text-input/blob/0787c505415f0d059801d80600e4ccb0651385f3/license for license)\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -7,7 +7,6 @@ export type WrapperProps = {
7
7
  program: Program;
8
8
  };
9
9
  /**
10
- * A component that wraps anything {@link Program} tries to render with an error boundary and all
11
- * neccessary providers.
10
+ * A component that wraps anything {@link Program} tries to render with an error boundary and all neccessary providers.
12
11
  */
13
12
  export declare const Wrapper: FC<PropsWithChildren<WrapperProps>>;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../source/ui/internals/Wrapper.tsx"],
4
- "sourcesContent": ["import {Box, Spacer, Text} from 'ink';\nimport {type FC, type PropsWithChildren, useMemo} from 'react';\nimport {ErrorBoundary} from 'react-error-boundary';\n\nimport {type Program} from '../../program.js';\nimport {highlighted, notice} from '../colors.js';\nimport {Failure} from '../Failure.js';\nimport {programContext} from './programContext.js';\n\n/**\n * {@link Wrapper} component props.\n */\nexport type WrapperProps = {\n program: Program;\n};\n\n/**\n * A component that wraps anything {@link Program} tries to render with an error boundary and all\n * neccessary providers.\n */\nexport const Wrapper: FC<PropsWithChildren<WrapperProps>> = ({program, children}) => {\n let programContextValue = useMemo(\n () => ({\n program,\n }),\n [program],\n );\n\n return (\n <ErrorBoundary FallbackComponent={Failure}>\n <programContext.Provider value={programContextValue}>\n {program.latestVersion && program.latestVersion !== program.version ?\n <Box>\n <Box\n borderColor={notice}\n borderStyle=\"round\"\n flexDirection=\"column\"\n margin={1}\n paddingBottom={1}\n paddingLeft={4}\n paddingRight={4}\n paddingTop={1}\n >\n <Text>\n New version <Text color={highlighted}>{program.latestVersion}</Text> is available!\n </Text>\n <Text>\n Run <Text color={highlighted}>{`npm install ${program.name} -D`}</Text> to update.\n </Text>\n </Box>\n <Spacer />\n </Box>\n : null}\n <Box>{children}</Box>\n </programContext.Provider>\n </ErrorBoundary>\n );\n};\n"],
5
- "mappings": "AA2Cc,SACc,KADd;AA3Cd,SAAQ,KAAK,QAAQ,YAAW;AAChC,SAAyC,eAAc;AACvD,SAAQ,qBAAoB;AAG5B,SAAQ,aAAa,cAAa;AAClC,SAAQ,eAAc;AACtB,SAAQ,sBAAqB;AAatB,aAAM,UAA+C,CAAC,EAAC,SAAS,SAAQ,MAAM;AACnF,MAAI,sBAAsB;AAAA,IACxB,OAAO;AAAA,MACL;AAAA,IACF;AAAA,IACA,CAAC,OAAO;AAAA,EACV;AAEA,SACE,oBAAC,iBAAc,mBAAmB,SAChC,+BAAC,eAAe,UAAf,EAAwB,OAAO,qBAC7B;AAAA,YAAQ,iBAAiB,QAAQ,kBAAkB,QAAQ,UAC1D,qBAAC,OACC;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,aAAa;AAAA,UACb,aAAY;AAAA,UACZ,eAAc;AAAA,UACd,QAAQ;AAAA,UACR,eAAe;AAAA,UACf,aAAa;AAAA,UACb,cAAc;AAAA,UACd,YAAY;AAAA,UAEZ;AAAA,iCAAC,QAAK;AAAA;AAAA,cACQ,oBAAC,QAAK,OAAO,aAAc,kBAAQ,eAAc;AAAA,cAAO;AAAA,eACtE;AAAA,YACA,qBAAC,QAAK;AAAA;AAAA,cACA,oBAAC,QAAK,OAAO,aAAc,yBAAe,QAAQ,IAAI,OAAM;AAAA,cAAO;AAAA,eACzE;AAAA;AAAA;AAAA,MACF;AAAA,MACA,oBAAC,UAAO;AAAA,OACV,IACA;AAAA,IACF,oBAAC,OAAK,UAAS;AAAA,KACjB,GACF;AAEJ;",
4
+ "sourcesContent": ["import {Box, Spacer, Text} from 'ink';\nimport {type FC, type PropsWithChildren, useMemo} from 'react';\nimport {ErrorBoundary} from 'react-error-boundary';\n\nimport {type Program} from '../../program.js';\nimport {highlighted, notice} from '../colors.js';\nimport {Failure} from '../Failure.js';\nimport {programContext} from './programContext.js';\n\n/**\n * {@link Wrapper} component props.\n */\nexport type WrapperProps = {\n program: Program;\n};\n\n/**\n * A component that wraps anything {@link Program} tries to render with an error boundary and all neccessary providers.\n */\nexport const Wrapper: FC<PropsWithChildren<WrapperProps>> = ({program, children}) => {\n let programContextValue = useMemo(\n () => ({\n program,\n }),\n [program],\n );\n\n return (\n <ErrorBoundary FallbackComponent={Failure}>\n <programContext.Provider value={programContextValue}>\n {program.latestVersion && program.latestVersion !== program.version ?\n <Box>\n <Box\n borderColor={notice}\n borderStyle=\"round\"\n flexDirection=\"column\"\n margin={1}\n paddingBottom={1}\n paddingLeft={4}\n paddingRight={4}\n paddingTop={1}\n >\n <Text>\n New version <Text color={highlighted}>{program.latestVersion}</Text> is available!\n </Text>\n <Text>\n Run <Text color={highlighted}>{`npm install ${program.name} -D`}</Text> to update.\n </Text>\n </Box>\n <Spacer />\n </Box>\n : null}\n <Box>{children}</Box>\n </programContext.Provider>\n </ErrorBoundary>\n );\n};\n"],
5
+ "mappings": "AA0Cc,SACc,KADd;AA1Cd,SAAQ,KAAK,QAAQ,YAAW;AAChC,SAAyC,eAAc;AACvD,SAAQ,qBAAoB;AAG5B,SAAQ,aAAa,cAAa;AAClC,SAAQ,eAAc;AACtB,SAAQ,sBAAqB;AAYtB,aAAM,UAA+C,CAAC,EAAC,SAAS,SAAQ,MAAM;AACnF,MAAI,sBAAsB;AAAA,IACxB,OAAO;AAAA,MACL;AAAA,IACF;AAAA,IACA,CAAC,OAAO;AAAA,EACV;AAEA,SACE,oBAAC,iBAAc,mBAAmB,SAChC,+BAAC,eAAe,UAAf,EAAwB,OAAO,qBAC7B;AAAA,YAAQ,iBAAiB,QAAQ,kBAAkB,QAAQ,UAC1D,qBAAC,OACC;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,aAAa;AAAA,UACb,aAAY;AAAA,UACZ,eAAc;AAAA,UACd,QAAQ;AAAA,UACR,eAAe;AAAA,UACf,aAAa;AAAA,UACb,cAAc;AAAA,UACd,YAAY;AAAA,UAEZ;AAAA,iCAAC,QAAK;AAAA;AAAA,cACQ,oBAAC,QAAK,OAAO,aAAc,kBAAQ,eAAc;AAAA,cAAO;AAAA,eACtE;AAAA,YACA,qBAAC,QAAK;AAAA;AAAA,cACA,oBAAC,QAAK,OAAO,aAAc,yBAAe,QAAQ,IAAI,OAAM;AAAA,cAAO;AAAA,eACzE;AAAA;AAAA;AAAA,MACF;AAAA,MACA,oBAAC,UAAO;AAAA,OACV,IACA;AAAA,IACF,oBAAC,OAAK,UAAS;AAAA,KACjB,GACF;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,5 @@
1
1
  /**
2
- * A React hook for accessing {@link Program} instance and `exit` function that is used for showing
3
- * an error (via an error boundary) and exiting.
2
+ * A React hook for accessing {@link Program} instance and `exit` function that is used for showing an error (via an error boundary) and exiting.
4
3
  */
5
4
  export declare function useProgram(): {
6
5
  program: import("../program.js").Program;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../source/ui/useProgram.ts"],
4
- "sourcesContent": ["import {useApp} from 'ink';\nimport {useCallback, useContext} from 'react';\nimport {useErrorBoundary} from 'react-error-boundary';\n\nimport {programContext} from './internals.js';\n\n/**\n * A React hook for accessing {@link Program} instance and `exit` function that is used for showing\n * an error (via an error boundary) and exiting.\n */\nexport function useProgram() {\n let {showBoundary} = useErrorBoundary();\n let {exit: appExit} = useApp();\n let {program} = useContext(programContext);\n\n let exit = useCallback(\n (error: unknown) => {\n process.exitCode = 1;\n\n showBoundary(error);\n appExit(error as Error);\n },\n [appExit, showBoundary],\n );\n\n return {program, exit};\n}\n"],
5
- "mappings": "AAAA,SAAQ,cAAa;AACrB,SAAQ,aAAa,kBAAiB;AACtC,SAAQ,wBAAuB;AAE/B,SAAQ,sBAAqB;AAMtB,gBAAS,aAAa;AAC3B,MAAI,EAAC,aAAY,IAAI,iBAAiB;AACtC,MAAI,EAAC,MAAM,QAAO,IAAI,OAAO;AAC7B,MAAI,EAAC,QAAO,IAAI,WAAW,cAAc;AAEzC,MAAI,OAAO;AAAA,IACT,CAAC,UAAmB;AAClB,cAAQ,WAAW;AAEnB,mBAAa,KAAK;AAClB,cAAQ,KAAc;AAAA,IACxB;AAAA,IACA,CAAC,SAAS,YAAY;AAAA,EACxB;AAEA,SAAO,EAAC,SAAS,KAAI;AACvB;",
4
+ "sourcesContent": ["import {useApp} from 'ink';\nimport {useCallback, useContext} from 'react';\nimport {useErrorBoundary} from 'react-error-boundary';\n\nimport {programContext} from './internals.js';\n\n/**\n * A React hook for accessing {@link Program} instance and `exit` function that is used for showing an error (via an error boundary) and exiting.\n */\nexport function useProgram() {\n let {showBoundary} = useErrorBoundary();\n let {exit: appExit} = useApp();\n let {program} = useContext(programContext);\n\n let exit = useCallback(\n (error: unknown) => {\n process.exitCode = 1;\n\n showBoundary(error);\n appExit(error);\n },\n [appExit, showBoundary],\n );\n\n return {program, exit};\n}\n"],
5
+ "mappings": "AAAA,SAAQ,cAAa;AACrB,SAAQ,aAAa,kBAAiB;AACtC,SAAQ,wBAAuB;AAE/B,SAAQ,sBAAqB;AAKtB,gBAAS,aAAa;AAC3B,MAAI,EAAC,aAAY,IAAI,iBAAiB;AACtC,MAAI,EAAC,MAAM,QAAO,IAAI,OAAO;AAC7B,MAAI,EAAC,QAAO,IAAI,WAAW,cAAc;AAEzC,MAAI,OAAO;AAAA,IACT,CAAC,UAAmB;AAClB,cAAQ,WAAW;AAEnB,mBAAa,KAAK;AAClB,cAAQ,KAAK;AAAA,IACf;AAAA,IACA,CAAC,SAAS,YAAY;AAAA,EACxB;AAEA,SAAO,EAAC,SAAS,KAAI;AACvB;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jakubmazanec/cli",
3
- "version": "0.5.7-unstable.72f063e3",
3
+ "version": "0.5.8-next.24efc8d1f",
4
4
  "description": "TypeScript-first library for building CLIs.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -17,9 +17,9 @@
17
17
  "source"
18
18
  ],
19
19
  "scripts": {
20
- "build": "del-cli build tsconfig.tsbuildinfo && esbuild \"source/**/*\" --platform=node --target=node24.3 --outdir=build --sourcemap && tsc",
20
+ "build": "del-cli build tsconfig.tsbuildinfo && esbuild \"source/**/*\" --platform=node --target=node24.22 --outdir=build --sourcemap && tsc",
21
21
  "clean": "del-cli coverage build *.tsbuildinfo",
22
- "develop": "concurrently \"esbuild \"source/**/*\" --platform=node --target=node24.3 --outdir=build --sourcemap --watch\" \"tsc --watch\"",
22
+ "develop": "concurrently \"esbuild \"source/**/*\" --platform=node --target=node24.22 --outdir=build --sourcemap --watch\" \"tsc --watch\"",
23
23
  "document": "del-cli docs && typedoc --options typedoc.config.cjs",
24
24
  "format": "prettier . --write --ignore-unknown",
25
25
  "lint": "eslint .",
@@ -27,46 +27,46 @@
27
27
  "typecheck": "tsc --project tsconfig.typecheck.json"
28
28
  },
29
29
  "dependencies": {
30
- "@jakubmazanec/args": "2.0.19-unstable.72f063e3",
31
- "@jakubmazanec/error": "3.0.19-unstable.72f063e3",
32
- "@jakubmazanec/ts-utils": "3.0.20-unstable.72f063e3",
33
- "@jakubmazanec/zod-utils": "^3.0.0",
30
+ "@jakubmazanec/args": "2.0.20-next.24efc8d1f",
31
+ "@jakubmazanec/error": "3.0.20-next.24efc8d1f",
32
+ "@jakubmazanec/ts-utils": "3.0.21-next.24efc8d1f",
33
+ "@jakubmazanec/zod-utils": "3.0.6-next.24efc8d1f",
34
34
  "chalk": "^5.6.2",
35
- "fs-extra": "^11.3.6",
35
+ "fs-extra": "^11.4.1",
36
36
  "latest-version": "^9.0.0",
37
37
  "lodash": "^4.18.1",
38
- "react-error-boundary": "^6.1.2",
39
- "zod": "^4.4.3"
38
+ "react-error-boundary": "^6.1.6",
39
+ "zod": "^4.6.7"
40
40
  },
41
41
  "devDependencies": {
42
- "@jakubmazanec/eslint-config": "6.0.0-unstable.72f063e3",
42
+ "@jakubmazanec/eslint-config": "5.0.2-next.24efc8d1f",
43
43
  "@types/fs-extra": "^11.0.4",
44
- "@types/lodash": "^4.17.24",
45
- "@types/node": "^24.0.4",
46
- "@types/react": "^19.2.17",
47
- "@vitest/coverage-v8": "^4.1.10",
48
- "concurrently": "^10.0.3",
44
+ "@types/lodash": "^4.17.26",
45
+ "@types/node": "^24.19.2",
46
+ "@types/react": "^19.3.0",
47
+ "@vitest/coverage-v8": "^4.1.12",
48
+ "concurrently": "^10.0.6",
49
49
  "cross-env": "^10.1.0",
50
50
  "del-cli": "^7.0.0",
51
- "esbuild": "^0.28.1",
52
- "eslint": "^9.39.4",
53
- "ink": "^6.5.1",
51
+ "esbuild": "^0.28.2",
52
+ "eslint": "^9.39.5",
53
+ "ink": "^6.8.0",
54
54
  "ink-testing-library": "^4.0.0",
55
- "prettier": "^3.9.5",
55
+ "prettier": "^3.9.10",
56
56
  "prettier-plugin-packagejson": "^2.5.22",
57
- "react": "^19.2.7",
57
+ "react": "^19.3.1",
58
58
  "typedoc": "^0.28.20",
59
- "typedoc-plugin-markdown": "^4.12.0",
60
- "typescript": "^6.0.0",
61
- "vitest": "^4.1.10"
59
+ "typedoc-plugin-markdown": "^4.14.0",
60
+ "typescript": "^6.0.3",
61
+ "vitest": "^4.1.12"
62
62
  },
63
63
  "peerDependencies": {
64
64
  "ink": "6.x",
65
65
  "react": "19.x"
66
66
  },
67
- "packageManager": "npm@11.3.0",
67
+ "packageManager": "npm@11.21.1",
68
68
  "engines": {
69
- "node": "^24.3.0",
70
- "npm": "^11.3.0"
69
+ "node": "^24.22.0",
70
+ "npm": "^11.21.1"
71
71
  }
72
72
  }
@@ -11,8 +11,7 @@ import {type CommandOptions} from './CommandOptions.js';
11
11
  import {type Program} from './Program.js';
12
12
 
13
13
  /**
14
- * Command encapsulates piece of a CLI's logic and is executed when {@link Program} instance parses
15
- * that command from the command line arguments.
14
+ * Command encapsulates piece of a CLI's logic and is executed when {@link Program} instance parses that command from the command line arguments.
16
15
  */
17
16
  export class Command<
18
17
  A extends string,
@@ -78,8 +77,7 @@ export class Command<
78
77
  }
79
78
 
80
79
  /**
81
- * Parses a list of command line arguments into an arguments object. Parser is pre-configured
82
- * based on this command.
80
+ * Parses a list of command line arguments into an arguments object. Parser is pre-configured based on this command.
83
81
  */
84
82
  parseArguments(argv: Argv): Arguments<{
85
83
  commands: readonly [A];
@@ -16,8 +16,7 @@ import {type ProgramOptions} from './ProgramOptions.js';
16
16
  import {type ProgramStreams} from './ProgramStreams.js';
17
17
 
18
18
  /**
19
- * Program manages and executes {@link Command} instances attached to it based on parsing command
20
- * line arguments.
19
+ * Program manages and executes {@link Command} instances attached to it based on parsing command line arguments.
21
20
  */
22
21
  export class Program {
23
22
  /** Program name. */
@@ -10,11 +10,7 @@ import * as icons from './icons.js';
10
10
  * {@link Failure} component props.
11
11
  */
12
12
  export type FailureProps = BoxProps & {
13
- /**
14
- * Error that describes a failure state. Function {@link getErrorDetail} is used for getting all
15
- * the information from the error; you can use it to implement own retrieval logic and pass the
16
- * result as `errorDetail` prop.
17
- */
13
+ /** Error that describes a failure state. Function {@link getErrorDetail} is used for getting all the information from the error; you can use it to implement own retrieval logic and pass the result as `errorDetail` prop. */
18
14
  error: unknown;
19
15
 
20
16
  /** Information about the failure state. Overrides information retireved from `error` prop. */
@@ -24,10 +24,7 @@ type FormRowProps<C extends FormConfig> = BoxProps & {
24
24
  /** Value. */
25
25
  value: unknown;
26
26
 
27
- /**
28
- * Should component listen to Listen to user's input? Useful in case there are multiple input
29
- * components at the same time and input must be "routed" to a specific component.
30
- */
27
+ /** Should component listen to Listen to user's input? Useful in case there are multiple input components at the same time and input must be "routed" to a specific component. */
31
28
  focus: boolean;
32
29
 
33
30
  /** Handler function that is called when value changes. */
@@ -36,10 +33,7 @@ type FormRowProps<C extends FormConfig> = BoxProps & {
36
33
  /** Handler function that is called when the value is accepted. */
37
34
  onComplete: (value: unknown, inputName: keyof C['rows']) => void;
38
35
 
39
- /**
40
- * Indicates whether value has been accepted. Component in the row then doesn't accept more
41
- * input.
42
- */
36
+ /** Indicates whether value has been accepted. Component in the row then doesn't accept more input. */
43
37
  isComplete: boolean;
44
38
  };
45
39
 
@@ -17,10 +17,7 @@ type SelectInputProps = BoxProps & {
17
17
  /** Items to display in a list. */
18
18
  items: SelectInputItem[];
19
19
 
20
- /**
21
- * Should component listen to user's input? Useful in case there are multiple input components at
22
- * the same time and input must be handled only by a specific component.
23
- */
20
+ /** Should component listen to user's input? Useful in case there are multiple input components at the same time and input must be handled only by a specific component. */
24
21
  focus?: boolean | undefined;
25
22
 
26
23
  /** Index of initially selected item. */
@@ -18,10 +18,7 @@ export type TextInputProps = BoxProps & {
18
18
  /** Value. */
19
19
  value: string;
20
20
 
21
- /**
22
- * Should component listen to Listen to user's input? Useful in case there are multiple input
23
- * components at the same time and input must be handled only by a specific component.
24
- */
21
+ /** Should component listen to Listen to user's input? Useful in case there are multiple input components at the same time and input must be handled only by a specific component. */
25
22
  focus?: boolean | undefined;
26
23
 
27
24
  /** Replace all chars and mask the value. Useful for password inputs. */
@@ -15,8 +15,7 @@ export type WrapperProps = {
15
15
  };
16
16
 
17
17
  /**
18
- * A component that wraps anything {@link Program} tries to render with an error boundary and all
19
- * neccessary providers.
18
+ * A component that wraps anything {@link Program} tries to render with an error boundary and all neccessary providers.
20
19
  */
21
20
  export const Wrapper: FC<PropsWithChildren<WrapperProps>> = ({program, children}) => {
22
21
  let programContextValue = useMemo(
@@ -5,8 +5,7 @@ import {useErrorBoundary} from 'react-error-boundary';
5
5
  import {programContext} from './internals.js';
6
6
 
7
7
  /**
8
- * A React hook for accessing {@link Program} instance and `exit` function that is used for showing
9
- * an error (via an error boundary) and exiting.
8
+ * A React hook for accessing {@link Program} instance and `exit` function that is used for showing an error (via an error boundary) and exiting.
10
9
  */
11
10
  export function useProgram() {
12
11
  let {showBoundary} = useErrorBoundary();
@@ -18,7 +17,7 @@ export function useProgram() {
18
17
  process.exitCode = 1;
19
18
 
20
19
  showBoundary(error);
21
- appExit(error as Error);
20
+ appExit(error);
22
21
  },
23
22
  [appExit, showBoundary],
24
23
  );