@jakubmazanec/cli 0.1.0-593aae1 → 0.1.0-5f6d70c

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.
Files changed (45) hide show
  1. package/dist/program/Command.d.ts +2 -2
  2. package/dist/program/Command.js +2 -2
  3. package/dist/program/Command.js.map +1 -1
  4. package/dist/program/Program.d.ts +6 -3
  5. package/dist/program/Program.js +17 -8
  6. package/dist/program/Program.js.map +1 -1
  7. package/dist/program/ProgramOptions.d.ts +5 -1
  8. package/dist/program/ProgramOptions.js +1 -3
  9. package/dist/program/ProgramOptions.js.map +1 -1
  10. package/dist/program/ProgramStreams.d.ts +1 -1
  11. package/dist/program/ProgramStreams.js +1 -1
  12. package/dist/program/ProgramStreams.js.map +1 -1
  13. package/dist/ui/Failure.d.ts +2 -2
  14. package/dist/ui/Failure.js.map +1 -1
  15. package/dist/ui/Header.d.ts +1 -1
  16. package/dist/ui/Header.js.map +1 -1
  17. package/dist/ui/Help.d.ts +2 -2
  18. package/dist/ui/Help.js.map +1 -1
  19. package/dist/ui/form/SelectInput.d.ts +1 -1
  20. package/dist/ui/form/SelectInput.js +2 -2
  21. package/dist/ui/form/SelectInput.js.map +1 -1
  22. package/dist/ui/getErrorDetail.js +9 -0
  23. package/dist/ui/getErrorDetail.js.map +1 -1
  24. package/dist/ui/internals/Wrapper.d.ts +2 -2
  25. package/dist/ui/internals/Wrapper.js +1 -1
  26. package/dist/ui/internals/Wrapper.js.map +1 -1
  27. package/dist/ui/internals/programContext.d.ts +1 -1
  28. package/dist/ui/internals/programContext.js +1 -1
  29. package/dist/ui/internals/programContext.js.map +1 -1
  30. package/dist/ui/useProgram.d.ts +1 -1
  31. package/dist/ui/useProgram.js +1 -1
  32. package/dist/ui/useProgram.js.map +1 -1
  33. package/package.json +7 -6
  34. package/src/program/Command.ts +2 -2
  35. package/src/program/Program.ts +28 -5
  36. package/src/program/ProgramOptions.ts +7 -1
  37. package/src/program/ProgramStreams.ts +1 -1
  38. package/src/ui/Failure.tsx +2 -2
  39. package/src/ui/Header.tsx +1 -1
  40. package/src/ui/Help.tsx +2 -2
  41. package/src/ui/form/SelectInput.tsx +1 -4
  42. package/src/ui/getErrorDetail.ts +11 -0
  43. package/src/ui/internals/Wrapper.tsx +2 -2
  44. package/src/ui/internals/programContext.ts +1 -1
  45. package/src/ui/useProgram.ts +1 -1
@@ -3,7 +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 {@linkcode Program} instance parses 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.
7
7
  */
8
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> {
9
9
  readonly name: A;
@@ -30,7 +30,7 @@ export declare class Command<A extends string, const B extends ParametersConfig
30
30
  allowUnknownParameters: E;
31
31
  }>;
32
32
  /**
33
- * Executes command action with provided parsed arguments and {@linkcode Program} instance.
33
+ * Executes command action with provided parsed arguments and {@link Program} instance.
34
34
  */
35
35
  run(parsedArgs: Arguments<{
36
36
  commands: readonly [A];
@@ -1,7 +1,7 @@
1
1
  import { parseArguments } from '@jakubmazanec/args';
2
2
  // import {type ProgramCommand} from './ProgramCommand.js';
3
3
  /**
4
- * Command encapsulates piece of a CLI's logic and is executed when {@linkcode Program} instance parses that command from the command line arguments.
4
+ * Command encapsulates piece of a CLI's logic and is executed when {@link Program} instance parses that command from the command line arguments.
5
5
  */ export class Command {
6
6
  /* implements ProgramCommand*/ name;
7
7
  description;
@@ -55,7 +55,7 @@ import { parseArguments } from '@jakubmazanec/args';
55
55
  });
56
56
  }
57
57
  /**
58
- * Executes command action with provided parsed arguments and {@linkcode Program} instance.
58
+ * Executes command action with provided parsed arguments and {@link Program} instance.
59
59
  */ async run(parsedArgs, program) {
60
60
  await this.action(parsedArgs, program);
61
61
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/program/Command.ts"],"sourcesContent":["import {\n type Argv,\n parseArguments,\n type OptionsConfig,\n type ParametersConfig,\n type Arguments,\n} from '@jakubmazanec/args';\n\nimport {type CommandAction} from './CommandAction.js';\nimport {type CommandOptions} from './CommandOptions.js';\nimport {type Program} from './Program.js';\n// import {type ProgramCommand} from './ProgramCommand.js';\n\n/**\n * Command encapsulates piece of a CLI's logic and is executed when {@linkcode 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 /* implements ProgramCommand*/\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 {@linkcode 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"],"names":["parseArguments","Command","name","description","parameters","options","allowUnknownOptions","allowUnknownParameters","action","constructor","argv","commands","undefined","run","parsedArgs","program"],"mappings":"AAAA,SAEEA,cAAc,QAIT,qBAAqB;AAK5B,2DAA2D;AAE3D;;CAEC,GACD,OAAO,MAAMC;IAOX,4BAA4B,GAC5B,AAASC,KAAQ;IACRC,YAAqB;IACrBC,WAAkD;IAClDC,QAA4C;IAC5CC,oBAAuB;IACvBC,uBAA0B;IAClBC,OAAqC;IAEtD;;;;GAIC,GACDC,YACEP,IAAO,EACPM,MAAoC,EACpC,EACEL,WAAW,EACXC,UAAU,EACVC,OAAO,EACPC,mBAAmB,EACnBC,sBAAsB,EAC+B,CACvD;QACA,IAAI,CAACL,IAAI,GAAGA;QACZ,IAAI,CAACM,MAAM,GAAGA;QAEd,IAAIL,aAAa;YACf,IAAI,CAACA,WAAW,GAAGA;QACrB;QAEA,IAAIC,YAAY;YACd,IAAI,CAACA,UAAU,GAAGA;QACpB,OAAO;YACL,IAAI,CAACA,UAAU,GAAG;QACpB;QAEA,IAAIC,SAAS;YACX,IAAI,CAACA,OAAO,GAAGA;QACjB,OAAO;YACL,IAAI,CAACA,OAAO,GAAG;QACjB;QAEA,IAAIC,qBAAqB;YACvB,IAAI,CAACA,mBAAmB,GAAGA;QAC7B,OAAO;YACL,IAAI,CAACA,mBAAmB,GAAG;QAC7B;QAEA,IAAIC,wBAAwB;YAC1B,IAAI,CAACA,sBAAsB,GAAGA;QAChC,OAAO;YACL,IAAI,CAACA,sBAAsB,GAAG;QAChC;IACF;IAEA;;GAEC,GACDP,eAAeU,IAAU,EAMtB;QACD,OAAOV,eAAeU,MAAM;YAC1BC,UAAU;gBAAC,IAAI,CAACT,IAAI;aAAC;YACrBE,YAAY,IAAI,CAACA,UAAU,IAAIQ;YAC/BP,SAAS,IAAI,CAACA,OAAO,IAAIO;YACzBN,qBAAqB,IAAI,CAACA,mBAAmB;YAC7CC,wBAAwB,IAAI,CAACA,sBAAsB;QACrD;IAOF;IAEA;;GAEC,GACD,MAAMM,IACJC,UAME,EACFC,OAAgB,EACD;QACf,MAAM,IAAI,CAACP,MAAM,CAACM,YAAYC;IAChC;AACF"}
1
+ {"version":3,"sources":["../../src/program/Command.ts"],"sourcesContent":["import {\n type Argv,\n parseArguments,\n type OptionsConfig,\n type ParametersConfig,\n type Arguments,\n} from '@jakubmazanec/args';\n\nimport {type CommandAction} from './CommandAction.js';\nimport {type CommandOptions} from './CommandOptions.js';\nimport {type Program} from './Program.js';\n// import {type ProgramCommand} from './ProgramCommand.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 /* implements ProgramCommand*/\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"],"names":["parseArguments","Command","name","description","parameters","options","allowUnknownOptions","allowUnknownParameters","action","constructor","argv","commands","undefined","run","parsedArgs","program"],"mappings":"AAAA,SAEEA,cAAc,QAIT,qBAAqB;AAK5B,2DAA2D;AAE3D;;CAEC,GACD,OAAO,MAAMC;IAOX,4BAA4B,GAC5B,AAASC,KAAQ;IACRC,YAAqB;IACrBC,WAAkD;IAClDC,QAA4C;IAC5CC,oBAAuB;IACvBC,uBAA0B;IAClBC,OAAqC;IAEtD;;;;GAIC,GACDC,YACEP,IAAO,EACPM,MAAoC,EACpC,EACEL,WAAW,EACXC,UAAU,EACVC,OAAO,EACPC,mBAAmB,EACnBC,sBAAsB,EAC+B,CACvD;QACA,IAAI,CAACL,IAAI,GAAGA;QACZ,IAAI,CAACM,MAAM,GAAGA;QAEd,IAAIL,aAAa;YACf,IAAI,CAACA,WAAW,GAAGA;QACrB;QAEA,IAAIC,YAAY;YACd,IAAI,CAACA,UAAU,GAAGA;QACpB,OAAO;YACL,IAAI,CAACA,UAAU,GAAG;QACpB;QAEA,IAAIC,SAAS;YACX,IAAI,CAACA,OAAO,GAAGA;QACjB,OAAO;YACL,IAAI,CAACA,OAAO,GAAG;QACjB;QAEA,IAAIC,qBAAqB;YACvB,IAAI,CAACA,mBAAmB,GAAGA;QAC7B,OAAO;YACL,IAAI,CAACA,mBAAmB,GAAG;QAC7B;QAEA,IAAIC,wBAAwB;YAC1B,IAAI,CAACA,sBAAsB,GAAGA;QAChC,OAAO;YACL,IAAI,CAACA,sBAAsB,GAAG;QAChC;IACF;IAEA;;GAEC,GACDP,eAAeU,IAAU,EAMtB;QACD,OAAOV,eAAeU,MAAM;YAC1BC,UAAU;gBAAC,IAAI,CAACT,IAAI;aAAC;YACrBE,YAAY,IAAI,CAACA,UAAU,IAAIQ;YAC/BP,SAAS,IAAI,CAACA,OAAO,IAAIO;YACzBN,qBAAqB,IAAI,CAACA,mBAAmB;YAC7CC,wBAAwB,IAAI,CAACA,sBAAsB;QACrD;IAOF;IAEA;;GAEC,GACD,MAAMM,IACJC,UAME,EACFC,OAAgB,EACD;QACf,MAAM,IAAI,CAACP,MAAM,CAACM,YAAYC;IAChC;AACF"}
@@ -1,10 +1,11 @@
1
- /// <reference types="react" resolution-mode="require"/>
2
1
  import { type ParametersConfig, type Argv, type OptionsConfig } from '@jakubmazanec/args';
2
+ import { type ComponentType } from 'react';
3
+ import { type FallbackProps } from 'react-error-boundary';
3
4
  import { type Command } from './Command.js';
4
5
  import { type ProgramOptions } from './ProgramOptions.js';
5
6
  import { type ProgramStreams } from './ProgramStreams.js';
6
7
  /**
7
- * Program manages and executes {@linkcode Command} instances attached to it based on parsing command line arguments.
8
+ * Program manages and executes {@link Command} instances attached to it based on parsing command line arguments.
8
9
  */
9
10
  export declare class Program {
10
11
  /** Program name. */
@@ -19,7 +20,9 @@ export declare class Program {
19
20
  readonly commands: Array<Command<string, ParametersConfig | undefined, OptionsConfig | undefined, boolean, boolean>>;
20
21
  protected isRendering: boolean;
21
22
  readonly streams: ProgramStreams;
22
- constructor({ name, version, description, bin }: ProgramOptions);
23
+ /** Custom error boundary fallback component */
24
+ ErrorBoundaryFallbackComponent: ComponentType<FallbackProps>;
25
+ constructor({ name, version, description, bin, ErrorBoundaryFallbackComponent }: ProgramOptions);
23
26
  /**
24
27
  * Adds command to the program.
25
28
  *
@@ -2,7 +2,7 @@
2
2
  import { Wrapper } from '../ui/internals.js';
3
3
  import { Failure, Help } from '../ui.js';
4
4
  /**
5
- * Program manages and executes {@linkcode Command} instances attached to it based on parsing command line arguments.
5
+ * Program manages and executes {@link Command} instances attached to it based on parsing command line arguments.
6
6
  */ export class Program {
7
7
  /** Program name. */ name;
8
8
  /** Program version. */ version;
@@ -15,7 +15,8 @@ import { Failure, Help } from '../ui.js';
15
15
  stdin: process.stdin,
16
16
  stdout: process.stdout
17
17
  };
18
- constructor({ name, version, description, bin }){
18
+ /** Custom error boundary fallback component */ ErrorBoundaryFallbackComponent;
19
+ constructor({ name, version, description, bin, ErrorBoundaryFallbackComponent }){
19
20
  if (name) {
20
21
  this.name = name;
21
22
  }
@@ -28,6 +29,11 @@ import { Failure, Help } from '../ui.js';
28
29
  if (bin) {
29
30
  this.bin = bin;
30
31
  }
32
+ if (ErrorBoundaryFallbackComponent) {
33
+ this.ErrorBoundaryFallbackComponent = ErrorBoundaryFallbackComponent;
34
+ } else {
35
+ this.ErrorBoundaryFallbackComponent = Failure;
36
+ }
31
37
  }
32
38
  /**
33
39
  * Adds command to the program.
@@ -62,8 +68,9 @@ import { Failure, Help } from '../ui.js';
62
68
  });
63
69
  } catch (error) {
64
70
  if (error instanceof Error) {
65
- await this.renderElement(createElement(Failure, {
66
- error
71
+ await this.renderElement(createElement(this.ErrorBoundaryFallbackComponent, {
72
+ error,
73
+ resetErrorBoundary: ()=>{}
67
74
  }));
68
75
  }
69
76
  } finally{
@@ -83,8 +90,9 @@ import { Failure, Help } from '../ui.js';
83
90
  if (parsedArgs.errors.length) {
84
91
  let { createElement } = await import('react');
85
92
  for (let error of parsedArgs.errors){
86
- await this.renderElement(createElement(Failure, {
87
- error
93
+ await this.renderElement(createElement(this.ErrorBoundaryFallbackComponent, {
94
+ error,
95
+ resetErrorBoundary: ()=>{}
88
96
  }));
89
97
  }
90
98
  } else {
@@ -93,8 +101,9 @@ import { Failure, Help } from '../ui.js';
93
101
  } catch (error) {
94
102
  let { createElement } = await import('react');
95
103
  if (error instanceof Error) {
96
- await this.renderElement(createElement(Failure, {
97
- error
104
+ await this.renderElement(createElement(this.ErrorBoundaryFallbackComponent, {
105
+ error,
106
+ resetErrorBoundary: ()=>{}
98
107
  }));
99
108
  }
100
109
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/program/Program.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any -- needed */\nimport {type ParametersConfig, type Argv, type OptionsConfig} from '@jakubmazanec/args';\n\nimport {type Command} from './Command.js';\nimport {ProgramError} from './ProgramError.js';\nimport {type ProgramOptions} from './ProgramOptions.js';\nimport {type ProgramStreams} from './ProgramStreams.js';\nimport {Wrapper} from '../ui/internals.js';\nimport {Failure, Help} from '../ui.js';\n\n/**\n * Program manages and executes {@linkcode Command} instances attached to it based on parsing command line arguments.\n */\nexport class Program {\n /** Program name. */\n readonly name?: string;\n\n /** Program version. */\n readonly version?: 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 constructor({name, version, description, bin}: ProgramOptions) {\n if (name) {\n this.name = name;\n }\n\n if (version) {\n this.version = version;\n }\n\n if (description) {\n this.description = description;\n }\n\n if (bin) {\n this.bin = bin;\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 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(createElement(Failure, {error}));\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 await this.renderElement(createElement(Failure, {error}));\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 await this.renderElement(createElement(Failure, {error}));\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"],"names":["ProgramError","Wrapper","Failure","Help","Program","name","version","description","bin","commands","isRendering","streams","stderr","process","stdin","stdout","constructor","addCommand","command","push","renderElement","element","render","createElement","program","exitOnCtrlC","patchConsole","error","Error","run","argv","hasCommandRun","parsedArgs","parseArguments","errors","length"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/program/Program.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any -- needed */\nimport {type ParametersConfig, type Argv, type OptionsConfig} from '@jakubmazanec/args';\nimport {type ComponentType} from 'react';\nimport {type FallbackProps} from 'react-error-boundary';\n\nimport {type Command} from './Command.js';\nimport {ProgramError} from './ProgramError.js';\nimport {type ProgramOptions} from './ProgramOptions.js';\nimport {type ProgramStreams} from './ProgramStreams.js';\nimport {Wrapper} from '../ui/internals.js';\nimport {Failure, Help} from '../ui.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 /** Program version. */\n readonly version?: 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 constructor({name, version, description, bin, ErrorBoundaryFallbackComponent}: ProgramOptions) {\n if (name) {\n this.name = name;\n }\n\n if (version) {\n this.version = version;\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 /**\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 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 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 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"],"names":["ProgramError","Wrapper","Failure","Help","Program","name","version","description","bin","commands","isRendering","streams","stderr","process","stdin","stdout","ErrorBoundaryFallbackComponent","constructor","addCommand","command","push","renderElement","element","render","createElement","program","exitOnCtrlC","patchConsole","error","Error","resetErrorBoundary","run","argv","hasCommandRun","parsedArgs","parseArguments","errors","length"],"mappings":"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"}
@@ -1,5 +1,7 @@
1
+ import { type ComponentType } from 'react';
2
+ import { type FallbackProps } from 'react-error-boundary';
1
3
  /**
2
- * Options for creating new {@linkcode Program} instance.
4
+ * Options for creating new {@link Program} instance.
3
5
  */
4
6
  export type ProgramOptions = {
5
7
  /** Program name. */
@@ -10,4 +12,6 @@ export type ProgramOptions = {
10
12
  description?: string | undefined;
11
13
  /** Program executable name. */
12
14
  bin?: string | undefined;
15
+ /** Custom error boundary fallback component */
16
+ ErrorBoundaryFallbackComponent?: ComponentType<FallbackProps>;
13
17
  };
@@ -1,5 +1,3 @@
1
- /**
2
- * Options for creating new {@linkcode Program} instance.
3
- */ export { };
1
+ export { };
4
2
 
5
3
  //# sourceMappingURL=ProgramOptions.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/program/ProgramOptions.ts"],"sourcesContent":["/**\n * Options for creating new {@linkcode Program} instance.\n */\nexport type ProgramOptions = {\n /** Program name. */\n name?: string | undefined;\n\n /** Program version. */\n version?: string | undefined;\n\n /** Program description. */\n description?: string | undefined;\n\n /** Program executable name. */\n bin?: string | undefined;\n};\n"],"names":[],"mappings":"AAAA;;CAEC,GACD,WAYE"}
1
+ {"version":3,"sources":["../../src/program/ProgramOptions.ts"],"sourcesContent":["import {type ComponentType} from 'react';\nimport {type FallbackProps} from 'react-error-boundary';\n\n/**\n * Options for creating new {@link Program} instance.\n */\nexport type ProgramOptions = {\n /** Program name. */\n name?: string | undefined;\n\n /** Program version. */\n version?: string | undefined;\n\n /** Program description. */\n description?: string | undefined;\n\n /** Program executable name. */\n bin?: string | undefined;\n\n /** Custom error boundary fallback component */\n ErrorBoundaryFallbackComponent?: ComponentType<FallbackProps>;\n};\n"],"names":[],"mappings":"AAAA,WAqBE"}
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" resolution-mode="require"/>
2
2
  /**
3
- * {@linkcode Program} streams;
3
+ * {@link Program} streams;
4
4
  */
5
5
  export type ProgramStreams = {
6
6
  stderr: NodeJS.WriteStream;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * {@linkcode Program} streams;
2
+ * {@link Program} streams;
3
3
  */ export { };
4
4
 
5
5
  //# sourceMappingURL=ProgramStreams.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/program/ProgramStreams.ts"],"sourcesContent":["/**\n * {@linkcode Program} streams;\n */\nexport type ProgramStreams = {\n stderr: NodeJS.WriteStream;\n stdin: NodeJS.ReadStream;\n stdout: NodeJS.WriteStream;\n};\n"],"names":[],"mappings":"AAAA;;CAEC,GACD,WAIE"}
1
+ {"version":3,"sources":["../../src/program/ProgramStreams.ts"],"sourcesContent":["/**\n * {@link Program} streams;\n */\nexport type ProgramStreams = {\n stderr: NodeJS.WriteStream;\n stdin: NodeJS.ReadStream;\n stdout: NodeJS.WriteStream;\n};\n"],"names":[],"mappings":"AAAA;;CAEC,GACD,WAIE"}
@@ -1,10 +1,10 @@
1
1
  import { type BoxProps } from 'ink';
2
2
  import { type ErrorDetail } from './ErrorDetail.js';
3
3
  /**
4
- * {@linkcode Failure} component props.
4
+ * {@link Failure} component props.
5
5
  */
6
6
  export type FailureProps = BoxProps & {
7
- /** Error that describes a failure state. Function {@linkcode 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. */
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. */
8
8
  error: Error;
9
9
  /** Information about the failure state. Overrides information retireved from `error` prop. */
10
10
  errorDetail?: ErrorDetail;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/ui/Failure.tsx"],"sourcesContent":["import {Box, Text, type BoxProps} 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 * {@linkcode Failure} component props.\n */\nexport type FailureProps = BoxProps & {\n /** Error that describes a failure state. Function {@linkcode 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: Error;\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\" marginTop={1} marginLeft={2}>\n <Text color={colors.muted}>{stack}</Text>\n </Box>\n ) : null}\n\n {cause ? (\n <>\n <Box flexDirection=\"column\" marginTop={1} marginLeft={2}>\n <Text color={colors.muted}>{cause.description}</Text>\n </Box>\n\n {cause.stack ? (\n <Box flexDirection=\"column\" marginTop={1} marginLeft={2}>\n <Text color={colors.muted}>{cause.stack}</Text>\n </Box>\n ) : null}\n </>\n ) : null}\n </Box>\n );\n}\n"],"names":["Box","Text","colors","getErrorDetail","Header","icons","Failure","error","errorDetail","boxProps","label","description","stack","cause","flexDirection","icon","color","highlighted","marginLeft","failure","marginTop","muted"],"mappings":";AAAA,SAAQA,GAAG,EAAEC,IAAI,QAAsB,MAAM;AAE7C,YAAYC,YAAY,cAAc;AAEtC,SAAQC,cAAc,QAAO,sBAAsB;AACnD,SAAQC,MAAM,QAAO,cAAc;AACnC,YAAYC,WAAW,aAAa;AAapC;;CAEC,GACD,OAAO,SAASC,QAAQ,EAACC,KAAK,EAAEC,WAAW,EAAE,GAAGC,UAAuB;IACrE,IAAI,EAACC,KAAK,EAAEC,WAAW,EAAEC,KAAK,EAAEC,KAAK,EAAC,GAAGL,eAAeL,eAAeI;IAEvE,qBACE,MAACP;QAAK,GAAGS,QAAQ;QAAEK,eAAc;;0BAC/B,KAACV;gBAAOW,MAAMV,MAAME,KAAK;0BACvB,cAAA,KAACN;oBAAKe,OAAOd,OAAOe,WAAW;8BAAGP;;;YAGnCC,4BACC,KAACX;gBAAIc,eAAc;gBAASI,YAAY;0BACtC,cAAA,KAACjB;oBAAKe,OAAOd,OAAOiB,OAAO;8BAAGR;;iBAE9B;YAEHC,sBACC,KAACZ;gBAAIc,eAAc;gBAASM,WAAW;gBAAGF,YAAY;0BACpD,cAAA,KAACjB;oBAAKe,OAAOd,OAAOmB,KAAK;8BAAGT;;iBAE5B;YAEHC,sBACC;;kCACE,KAACb;wBAAIc,eAAc;wBAASM,WAAW;wBAAGF,YAAY;kCACpD,cAAA,KAACjB;4BAAKe,OAAOd,OAAOmB,KAAK;sCAAGR,MAAMF,WAAW;;;oBAG9CE,MAAMD,KAAK,iBACV,KAACZ;wBAAIc,eAAc;wBAASM,WAAW;wBAAGF,YAAY;kCACpD,cAAA,KAACjB;4BAAKe,OAAOd,OAAOmB,KAAK;sCAAGR,MAAMD,KAAK;;yBAEvC;;iBAEJ;;;AAGV"}
1
+ {"version":3,"sources":["../../src/ui/Failure.tsx"],"sourcesContent":["import {Box, Text, type BoxProps} 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: Error;\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\" marginTop={1} marginLeft={2}>\n <Text color={colors.muted}>{stack}</Text>\n </Box>\n ) : null}\n\n {cause ? (\n <>\n <Box flexDirection=\"column\" marginTop={1} marginLeft={2}>\n <Text color={colors.muted}>{cause.description}</Text>\n </Box>\n\n {cause.stack ? (\n <Box flexDirection=\"column\" marginTop={1} marginLeft={2}>\n <Text color={colors.muted}>{cause.stack}</Text>\n </Box>\n ) : null}\n </>\n ) : null}\n </Box>\n );\n}\n"],"names":["Box","Text","colors","getErrorDetail","Header","icons","Failure","error","errorDetail","boxProps","label","description","stack","cause","flexDirection","icon","color","highlighted","marginLeft","failure","marginTop","muted"],"mappings":";AAAA,SAAQA,GAAG,EAAEC,IAAI,QAAsB,MAAM;AAE7C,YAAYC,YAAY,cAAc;AAEtC,SAAQC,cAAc,QAAO,sBAAsB;AACnD,SAAQC,MAAM,QAAO,cAAc;AACnC,YAAYC,WAAW,aAAa;AAapC;;CAEC,GACD,OAAO,SAASC,QAAQ,EAACC,KAAK,EAAEC,WAAW,EAAE,GAAGC,UAAuB;IACrE,IAAI,EAACC,KAAK,EAAEC,WAAW,EAAEC,KAAK,EAAEC,KAAK,EAAC,GAAGL,eAAeL,eAAeI;IAEvE,qBACE,MAACP;QAAK,GAAGS,QAAQ;QAAEK,eAAc;;0BAC/B,KAACV;gBAAOW,MAAMV,MAAME,KAAK;0BACvB,cAAA,KAACN;oBAAKe,OAAOd,OAAOe,WAAW;8BAAGP;;;YAGnCC,4BACC,KAACX;gBAAIc,eAAc;gBAASI,YAAY;0BACtC,cAAA,KAACjB;oBAAKe,OAAOd,OAAOiB,OAAO;8BAAGR;;iBAE9B;YAEHC,sBACC,KAACZ;gBAAIc,eAAc;gBAASM,WAAW;gBAAGF,YAAY;0BACpD,cAAA,KAACjB;oBAAKe,OAAOd,OAAOmB,KAAK;8BAAGT;;iBAE5B;YAEHC,sBACC;;kCACE,KAACb;wBAAIc,eAAc;wBAASM,WAAW;wBAAGF,YAAY;kCACpD,cAAA,KAACjB;4BAAKe,OAAOd,OAAOmB,KAAK;sCAAGR,MAAMF,WAAW;;;oBAG9CE,MAAMD,KAAK,iBACV,KAACZ;wBAAIc,eAAc;wBAASM,WAAW;wBAAGF,YAAY;kCACpD,cAAA,KAACjB;4BAAKe,OAAOd,OAAOmB,KAAK;sCAAGR,MAAMD,KAAK;;yBAEvC;;iBAEJ;;;AAGV"}
@@ -1,7 +1,7 @@
1
1
  import { type BoxProps } from 'ink';
2
2
  import { type PropsWithChildren } from 'react';
3
3
  /**
4
- * {@linkcode Header} component props.
4
+ * {@link Header} component props.
5
5
  */
6
6
  export type HeaderProps = BoxProps & {
7
7
  /** Icon (recommended is 1 character) to render before the header itself. */
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/ui/Header.tsx"],"sourcesContent":["import {Box, type BoxProps, Text} from 'ink';\nimport {type PropsWithChildren} from 'react';\n\nimport {Spinner} from './Spinner.js';\n\n/**\n * {@linkcode Header} component props.\n */\nexport type HeaderProps = BoxProps & {\n /** Icon (recommended is 1 character) to render before the header itself. */\n icon?: string;\n\n /** Show spinner instead of the icon. */\n showSpinner?: boolean;\n};\n\n/**\n * Header component.\n */\nexport function Header({\n children,\n icon,\n showSpinner = false,\n ...boxProps\n}: PropsWithChildren<HeaderProps>) {\n return (\n <Box {...boxProps}>\n {icon || showSpinner ? (\n <Box marginRight={1}>\n {showSpinner ? <Spinner /> : null}\n {!showSpinner && icon ? <Text>{icon}</Text> : null}\n </Box>\n ) : null}\n <Box>{children}</Box>\n </Box>\n );\n}\n"],"names":["Box","Text","Spinner","Header","children","icon","showSpinner","boxProps","marginRight"],"mappings":";AAAA,SAAQA,GAAG,EAAiBC,IAAI,QAAO,MAAM;AAG7C,SAAQC,OAAO,QAAO,eAAe;AAarC;;CAEC,GACD,OAAO,SAASC,OAAO,EACrBC,QAAQ,EACRC,IAAI,EACJC,cAAc,KAAK,EACnB,GAAGC,UAC4B;IAC/B,qBACE,MAACP;QAAK,GAAGO,QAAQ;;YACdF,QAAQC,4BACP,MAACN;gBAAIQ,aAAa;;oBACfF,4BAAc,KAACJ,eAAa;oBAC5B,CAACI,eAAeD,qBAAO,KAACJ;kCAAMI;yBAAe;;iBAE9C;0BACJ,KAACL;0BAAKI;;;;AAGZ"}
1
+ {"version":3,"sources":["../../src/ui/Header.tsx"],"sourcesContent":["import {Box, type BoxProps, Text} from 'ink';\nimport {type PropsWithChildren} from 'react';\n\nimport {Spinner} from './Spinner.js';\n\n/**\n * {@link Header} component props.\n */\nexport type HeaderProps = BoxProps & {\n /** Icon (recommended is 1 character) to render before the header itself. */\n icon?: string;\n\n /** Show spinner instead of the icon. */\n showSpinner?: boolean;\n};\n\n/**\n * Header component.\n */\nexport function Header({\n children,\n icon,\n showSpinner = false,\n ...boxProps\n}: PropsWithChildren<HeaderProps>) {\n return (\n <Box {...boxProps}>\n {icon || showSpinner ? (\n <Box marginRight={1}>\n {showSpinner ? <Spinner /> : null}\n {!showSpinner && icon ? <Text>{icon}</Text> : null}\n </Box>\n ) : null}\n <Box>{children}</Box>\n </Box>\n );\n}\n"],"names":["Box","Text","Spinner","Header","children","icon","showSpinner","boxProps","marginRight"],"mappings":";AAAA,SAAQA,GAAG,EAAiBC,IAAI,QAAO,MAAM;AAG7C,SAAQC,OAAO,QAAO,eAAe;AAarC;;CAEC,GACD,OAAO,SAASC,OAAO,EACrBC,QAAQ,EACRC,IAAI,EACJC,cAAc,KAAK,EACnB,GAAGC,UAC4B;IAC/B,qBACE,MAACP;QAAK,GAAGO,QAAQ;;YACdF,QAAQC,4BACP,MAACN;gBAAIQ,aAAa;;oBACfF,4BAAc,KAACJ,eAAa;oBAC5B,CAACI,eAAeD,qBAAO,KAACJ;kCAAMI;yBAAe;;iBAE9C;0BACJ,KAACL;0BAAKI;;;;AAGZ"}
package/dist/ui/Help.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import { type BoxProps } from 'ink';
2
2
  import { type Program } from '../program.js';
3
3
  /**
4
- * {@linkcode Help} component props.
4
+ * {@link Help} component props.
5
5
  */
6
6
  export type HelpProps = BoxProps & {
7
- /** {@linkcode Program} instance. */
7
+ /** {@link Program} instance. */
8
8
  program: Program;
9
9
  };
10
10
  /**
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/ui/Help.tsx"],"sourcesContent":["import chalk from 'chalk';\nimport {Box, Text, type BoxProps} from 'ink';\n\nimport * as colors from './colors.js';\nimport {Header} from './Header.js';\nimport * as icons from './icons.js';\nimport {type Program} from '../program.js';\n\n/**\n * {@linkcode Help} component props.\n */\nexport type HelpProps = BoxProps & {\n /** {@linkcode Program} instance. */\n program: Program;\n};\n\n/**\n * A component that renders help information.\n */\nexport function Help({program, ...boxProps}: HelpProps) {\n return (\n <Box {...boxProps} flexDirection=\"column\">\n <Text>{`${chalk[colors.notice](program.name ?? '?')} ${chalk[colors.muted](\n program.version ?? '?',\n )}`}</Text>\n <Text color={colors.body}>{program.description}</Text>\n\n {program.commands.length ? (\n <>\n <Header icon={icons.info} marginTop={1}>\n <Text color={colors.highlighted}>Usage</Text>\n </Header>\n {program.commands.map((command) => {\n let line = `${chalk[colors.muted](program.bin ?? '?')} ${command.name}`;\n\n if (command.parameters) {\n if (command.parameters.some((parameterConfig) => !!parameterConfig.required)) {\n line += ` ${chalk[colors.muted]('<parameters>')}`;\n } else {\n line += ` ${chalk[colors.muted]('[<parameters>]')}`;\n }\n }\n\n if (command.options) {\n if (\n Object.entries(command.options).some(([, optionConfig]) => !!optionConfig.required)\n ) {\n line += ` ${chalk[colors.muted]('<options>')}`;\n } else {\n line += ` ${chalk[colors.muted]('[<options>]')}`;\n }\n }\n\n if (command.description) {\n line += ` ${command.description}`;\n }\n\n return (\n <Box key={command.name} marginLeft={2} flexDirection=\"column\">\n <Text>{line}</Text>\n </Box>\n );\n })}\n </>\n ) : null}\n </Box>\n );\n}\n"],"names":["chalk","Box","Text","colors","Header","icons","Help","program","boxProps","flexDirection","notice","name","muted","version","color","body","description","commands","length","icon","info","marginTop","highlighted","map","command","line","bin","parameters","some","parameterConfig","required","options","Object","entries","optionConfig","marginLeft"],"mappings":";AAAA,OAAOA,WAAW,QAAQ;AAC1B,SAAQC,GAAG,EAAEC,IAAI,QAAsB,MAAM;AAE7C,YAAYC,YAAY,cAAc;AACtC,SAAQC,MAAM,QAAO,cAAc;AACnC,YAAYC,WAAW,aAAa;AAWpC;;CAEC,GACD,OAAO,SAASC,KAAK,EAACC,OAAO,EAAE,GAAGC,UAAoB;IACpD,qBACE,MAACP;QAAK,GAAGO,QAAQ;QAAEC,eAAc;;0BAC/B,KAACP;0BAAM,CAAC,EAAEF,KAAK,CAACG,OAAOO,MAAM,CAAC,CAACH,QAAQI,IAAI,IAAI,KAAK,CAAC,EAAEX,KAAK,CAACG,OAAOS,KAAK,CAAC,CACxEL,QAAQM,OAAO,IAAI,KACnB,CAAC;;0BACH,KAACX;gBAAKY,OAAOX,OAAOY,IAAI;0BAAGR,QAAQS,WAAW;;YAE7CT,QAAQU,QAAQ,CAACC,MAAM,iBACtB;;kCACE,KAACd;wBAAOe,MAAMd,MAAMe,IAAI;wBAAEC,WAAW;kCACnC,cAAA,KAACnB;4BAAKY,OAAOX,OAAOmB,WAAW;sCAAE;;;oBAElCf,QAAQU,QAAQ,CAACM,GAAG,CAAC,CAACC;wBACrB,IAAIC,OAAO,CAAC,EAAEzB,KAAK,CAACG,OAAOS,KAAK,CAAC,CAACL,QAAQmB,GAAG,IAAI,KAAK,CAAC,EAAEF,QAAQb,IAAI,CAAC,CAAC;wBAEvE,IAAIa,QAAQG,UAAU,EAAE;4BACtB,IAAIH,QAAQG,UAAU,CAACC,IAAI,CAAC,CAACC,kBAAoB,CAAC,CAACA,gBAAgBC,QAAQ,GAAG;gCAC5EL,QAAQ,CAAC,CAAC,EAAEzB,KAAK,CAACG,OAAOS,KAAK,CAAC,CAAC,gBAAgB,CAAC;4BACnD,OAAO;gCACLa,QAAQ,CAAC,CAAC,EAAEzB,KAAK,CAACG,OAAOS,KAAK,CAAC,CAAC,kBAAkB,CAAC;4BACrD;wBACF;wBAEA,IAAIY,QAAQO,OAAO,EAAE;4BACnB,IACEC,OAAOC,OAAO,CAACT,QAAQO,OAAO,EAAEH,IAAI,CAAC,CAAC,GAAGM,aAAa,GAAK,CAAC,CAACA,aAAaJ,QAAQ,GAClF;gCACAL,QAAQ,CAAC,CAAC,EAAEzB,KAAK,CAACG,OAAOS,KAAK,CAAC,CAAC,aAAa,CAAC;4BAChD,OAAO;gCACLa,QAAQ,CAAC,CAAC,EAAEzB,KAAK,CAACG,OAAOS,KAAK,CAAC,CAAC,eAAe,CAAC;4BAClD;wBACF;wBAEA,IAAIY,QAAQR,WAAW,EAAE;4BACvBS,QAAQ,CAAC,CAAC,EAAED,QAAQR,WAAW,CAAC,CAAC;wBACnC;wBAEA,qBACE,KAACf;4BAAuBkC,YAAY;4BAAG1B,eAAc;sCACnD,cAAA,KAACP;0CAAMuB;;2BADCD,QAAQb,IAAI;oBAI1B;;iBAEA;;;AAGV"}
1
+ {"version":3,"sources":["../../src/ui/Help.tsx"],"sourcesContent":["import chalk from 'chalk';\nimport {Box, Text, type BoxProps} from 'ink';\n\nimport * as colors from './colors.js';\nimport {Header} from './Header.js';\nimport * as icons from './icons.js';\nimport {type Program} from '../program.js';\n\n/**\n * {@link Help} component props.\n */\nexport type HelpProps = BoxProps & {\n /** {@link Program} instance. */\n program: Program;\n};\n\n/**\n * A component that renders help information.\n */\nexport function Help({program, ...boxProps}: HelpProps) {\n return (\n <Box {...boxProps} flexDirection=\"column\">\n <Text>{`${chalk[colors.notice](program.name ?? '?')} ${chalk[colors.muted](\n program.version ?? '?',\n )}`}</Text>\n <Text color={colors.body}>{program.description}</Text>\n\n {program.commands.length ? (\n <>\n <Header icon={icons.info} marginTop={1}>\n <Text color={colors.highlighted}>Usage</Text>\n </Header>\n {program.commands.map((command) => {\n let line = `${chalk[colors.muted](program.bin ?? '?')} ${command.name}`;\n\n if (command.parameters) {\n if (command.parameters.some((parameterConfig) => !!parameterConfig.required)) {\n line += ` ${chalk[colors.muted]('<parameters>')}`;\n } else {\n line += ` ${chalk[colors.muted]('[<parameters>]')}`;\n }\n }\n\n if (command.options) {\n if (\n Object.entries(command.options).some(([, optionConfig]) => !!optionConfig.required)\n ) {\n line += ` ${chalk[colors.muted]('<options>')}`;\n } else {\n line += ` ${chalk[colors.muted]('[<options>]')}`;\n }\n }\n\n if (command.description) {\n line += ` ${command.description}`;\n }\n\n return (\n <Box key={command.name} marginLeft={2} flexDirection=\"column\">\n <Text>{line}</Text>\n </Box>\n );\n })}\n </>\n ) : null}\n </Box>\n );\n}\n"],"names":["chalk","Box","Text","colors","Header","icons","Help","program","boxProps","flexDirection","notice","name","muted","version","color","body","description","commands","length","icon","info","marginTop","highlighted","map","command","line","bin","parameters","some","parameterConfig","required","options","Object","entries","optionConfig","marginLeft"],"mappings":";AAAA,OAAOA,WAAW,QAAQ;AAC1B,SAAQC,GAAG,EAAEC,IAAI,QAAsB,MAAM;AAE7C,YAAYC,YAAY,cAAc;AACtC,SAAQC,MAAM,QAAO,cAAc;AACnC,YAAYC,WAAW,aAAa;AAWpC;;CAEC,GACD,OAAO,SAASC,KAAK,EAACC,OAAO,EAAE,GAAGC,UAAoB;IACpD,qBACE,MAACP;QAAK,GAAGO,QAAQ;QAAEC,eAAc;;0BAC/B,KAACP;0BAAM,CAAC,EAAEF,KAAK,CAACG,OAAOO,MAAM,CAAC,CAACH,QAAQI,IAAI,IAAI,KAAK,CAAC,EAAEX,KAAK,CAACG,OAAOS,KAAK,CAAC,CACxEL,QAAQM,OAAO,IAAI,KACnB,CAAC;;0BACH,KAACX;gBAAKY,OAAOX,OAAOY,IAAI;0BAAGR,QAAQS,WAAW;;YAE7CT,QAAQU,QAAQ,CAACC,MAAM,iBACtB;;kCACE,KAACd;wBAAOe,MAAMd,MAAMe,IAAI;wBAAEC,WAAW;kCACnC,cAAA,KAACnB;4BAAKY,OAAOX,OAAOmB,WAAW;sCAAE;;;oBAElCf,QAAQU,QAAQ,CAACM,GAAG,CAAC,CAACC;wBACrB,IAAIC,OAAO,CAAC,EAAEzB,KAAK,CAACG,OAAOS,KAAK,CAAC,CAACL,QAAQmB,GAAG,IAAI,KAAK,CAAC,EAAEF,QAAQb,IAAI,CAAC,CAAC;wBAEvE,IAAIa,QAAQG,UAAU,EAAE;4BACtB,IAAIH,QAAQG,UAAU,CAACC,IAAI,CAAC,CAACC,kBAAoB,CAAC,CAACA,gBAAgBC,QAAQ,GAAG;gCAC5EL,QAAQ,CAAC,CAAC,EAAEzB,KAAK,CAACG,OAAOS,KAAK,CAAC,CAAC,gBAAgB,CAAC;4BACnD,OAAO;gCACLa,QAAQ,CAAC,CAAC,EAAEzB,KAAK,CAACG,OAAOS,KAAK,CAAC,CAAC,kBAAkB,CAAC;4BACrD;wBACF;wBAEA,IAAIY,QAAQO,OAAO,EAAE;4BACnB,IACEC,OAAOC,OAAO,CAACT,QAAQO,OAAO,EAAEH,IAAI,CAAC,CAAC,GAAGM,aAAa,GAAK,CAAC,CAACA,aAAaJ,QAAQ,GAClF;gCACAL,QAAQ,CAAC,CAAC,EAAEzB,KAAK,CAACG,OAAOS,KAAK,CAAC,CAAC,aAAa,CAAC;4BAChD,OAAO;gCACLa,QAAQ,CAAC,CAAC,EAAEzB,KAAK,CAACG,OAAOS,KAAK,CAAC,CAAC,eAAe,CAAC;4BAClD;wBACF;wBAEA,IAAIY,QAAQR,WAAW,EAAE;4BACvBS,QAAQ,CAAC,CAAC,EAAED,QAAQR,WAAW,CAAC,CAAC;wBACnC;wBAEA,qBACE,KAACf;4BAAuBkC,YAAY;4BAAG1B,eAAc;sCACnD,cAAA,KAACP;0CAAMuB;;2BADCD,QAAQb,IAAI;oBAI1B;;iBAEA;;;AAGV"}
@@ -25,5 +25,5 @@ type SelectInputProps = BoxProps & {
25
25
  /**
26
26
  * Select input component.
27
27
  */
28
- export declare function SelectInput({ label, items, focus, initialIndex, limit: customLimit, onSelect, onHighlight, marginTop, isComplete, ...boxProps }: SelectInputProps): JSX.Element;
28
+ export declare function SelectInput({ label, items, focus, initialIndex, limit: customLimit, onSelect, onHighlight, isComplete, ...boxProps }: SelectInputProps): JSX.Element;
29
29
  export {};
@@ -7,7 +7,7 @@ import * as icons from '../icons.js';
7
7
  import { rotate } from '../internals.js';
8
8
  /**
9
9
  * Select input component.
10
- */ export function SelectInput({ label, items = [], focus = true, initialIndex = 0, limit: customLimit, onSelect, onHighlight, marginTop = 0, isComplete, ...boxProps }) {
10
+ */ export function SelectInput({ label, items = [], focus = true, initialIndex = 0, limit: customLimit, onSelect, onHighlight, isComplete, ...boxProps }) {
11
11
  var _items_selectedIndex, _items_selectedIndex1;
12
12
  let [rotateIndex, setRotateIndex] = useState(0);
13
13
  let [selectedIndex, setSelectedIndex] = useState(initialIndex);
@@ -108,7 +108,7 @@ import { rotate } from '../internals.js';
108
108
  }),
109
109
  /*#__PURE__*/ _jsx(Text, {
110
110
  color: isSelected ? colors.highlighted : colors.muted,
111
- children: `${item.label}`
111
+ children: item.label
112
112
  })
113
113
  ]
114
114
  }, item.value);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/ui/form/SelectInput.tsx"],"sourcesContent":["import {Box, type BoxProps, Text, useInput, type Key} from 'ink';\nimport _ from 'lodash';\nimport {useState, useEffect, useRef, useCallback} from 'react';\n\nimport {type SelectInputItem} from './SelectInputItem.js';\nimport * as colors from '../colors.js';\nimport * as icons from '../icons.js';\nimport {rotate} from '../internals.js';\n\n/**\n * Select input 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 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 | 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: customLimit,\n onSelect,\n onHighlight,\n marginTop = 0,\n isComplete,\n ...boxProps\n}: SelectInputProps): JSX.Element {\n let [rotateIndex, setRotateIndex] = useState(0);\n let [selectedIndex, setSelectedIndex] = useState(initialIndex);\n let hasLimit = typeof customLimit === 'number' && items.length > customLimit;\n let limit = hasLimit ? Math.min(customLimit 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 setRotateIndex(0);\n setSelectedIndex(0);\n }\n\n previousItems.current = items;\n }, [items]);\n\n let inputHandler = useCallback(\n (input: string, key: Key) => {\n if (input === 'k' || key.upArrow) {\n let lastIndex = (hasLimit ? limit : items.length) - 1;\n let atFirstIndex = selectedIndex === 0;\n let nextIndex = hasLimit ? selectedIndex : lastIndex;\n let nextRotateIndex = atFirstIndex ? rotateIndex + 1 : rotateIndex;\n let nextSelectedIndex = atFirstIndex ? nextIndex : selectedIndex - 1;\n\n setRotateIndex(nextRotateIndex);\n setSelectedIndex(nextSelectedIndex);\n\n let slicedItems = hasLimit ? rotate(items, nextRotateIndex).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 nextRotateIndex = isAtLastIndex ? rotateIndex - 1 : rotateIndex;\n let nextSelectedIndex = isAtLastIndex ? nextIndex : selectedIndex + 1;\n\n setRotateIndex(nextRotateIndex);\n setSelectedIndex(nextSelectedIndex);\n\n let slicedItems = hasLimit ? rotate(items, nextRotateIndex).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, rotateIndex).slice(0, limit) : items;\n\n if (typeof onSelect === 'function') {\n onSelect(slicedItems[selectedIndex] as SelectInputItem);\n }\n }\n },\n [hasLimit, limit, rotateIndex, selectedIndex, items, onSelect, onHighlight],\n );\n\n useInput(inputHandler, {isActive: focus});\n\n let visibleItem: SelectInputItem[] = hasLimit\n ? rotate(items, rotateIndex).slice(0, limit)\n : 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 ) : (\n <Box flexDirection=\"column\">\n {visibleItem.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 ) : (\n <Text color={colors.unselected}>{icons.unselectedCircle}</Text>\n )}\n </Box>\n <Text\n color={isSelected ? colors.highlighted : colors.muted}\n >{`${item.label}`}</Text>\n </Box>\n );\n })}\n </Box>\n )}\n </Box>\n </Box>\n );\n}\n"],"names":["Box","Text","useInput","_","useState","useEffect","useRef","useCallback","colors","icons","rotate","SelectInput","label","items","focus","initialIndex","limit","customLimit","onSelect","onHighlight","marginTop","isComplete","boxProps","rotateIndex","setRotateIndex","selectedIndex","setSelectedIndex","hasLimit","length","Math","min","previousItems","isEqual","current","map","item","value","inputHandler","input","key","upArrow","lastIndex","atFirstIndex","nextIndex","nextRotateIndex","nextSelectedIndex","slicedItems","slice","downArrow","isAtLastIndex","return","isActive","visibleItem","marginRight","success","question","flexDirection","color","highlighted","body","String","index","isSelected","selected","selectedCircle","unselected","unselectedCircle","muted"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/ui/form/SelectInput.tsx"],"sourcesContent":["import {Box, type BoxProps, Text, useInput, type Key} from 'ink';\nimport _ from 'lodash';\nimport {useState, useEffect, useRef, useCallback} from 'react';\n\nimport {type SelectInputItem} from './SelectInputItem.js';\nimport * as colors from '../colors.js';\nimport * as icons from '../icons.js';\nimport {rotate} from '../internals.js';\n\n/**\n * Select input 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 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 | 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: customLimit,\n onSelect,\n onHighlight,\n isComplete,\n ...boxProps\n}: SelectInputProps): JSX.Element {\n let [rotateIndex, setRotateIndex] = useState(0);\n let [selectedIndex, setSelectedIndex] = useState(initialIndex);\n let hasLimit = typeof customLimit === 'number' && items.length > customLimit;\n let limit = hasLimit ? Math.min(customLimit 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 setRotateIndex(0);\n setSelectedIndex(0);\n }\n\n previousItems.current = items;\n }, [items]);\n\n let inputHandler = useCallback(\n (input: string, key: Key) => {\n if (input === 'k' || key.upArrow) {\n let lastIndex = (hasLimit ? limit : items.length) - 1;\n let atFirstIndex = selectedIndex === 0;\n let nextIndex = hasLimit ? selectedIndex : lastIndex;\n let nextRotateIndex = atFirstIndex ? rotateIndex + 1 : rotateIndex;\n let nextSelectedIndex = atFirstIndex ? nextIndex : selectedIndex - 1;\n\n setRotateIndex(nextRotateIndex);\n setSelectedIndex(nextSelectedIndex);\n\n let slicedItems = hasLimit ? rotate(items, nextRotateIndex).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 nextRotateIndex = isAtLastIndex ? rotateIndex - 1 : rotateIndex;\n let nextSelectedIndex = isAtLastIndex ? nextIndex : selectedIndex + 1;\n\n setRotateIndex(nextRotateIndex);\n setSelectedIndex(nextSelectedIndex);\n\n let slicedItems = hasLimit ? rotate(items, nextRotateIndex).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, rotateIndex).slice(0, limit) : items;\n\n if (typeof onSelect === 'function') {\n onSelect(slicedItems[selectedIndex] as SelectInputItem);\n }\n }\n },\n [hasLimit, limit, rotateIndex, selectedIndex, items, onSelect, onHighlight],\n );\n\n useInput(inputHandler, {isActive: focus});\n\n let visibleItem: SelectInputItem[] = hasLimit\n ? rotate(items, rotateIndex).slice(0, limit)\n : 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 ) : (\n <Box flexDirection=\"column\">\n {visibleItem.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 ) : (\n <Text color={colors.unselected}>{icons.unselectedCircle}</Text>\n )}\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"],"names":["Box","Text","useInput","_","useState","useEffect","useRef","useCallback","colors","icons","rotate","SelectInput","label","items","focus","initialIndex","limit","customLimit","onSelect","onHighlight","isComplete","boxProps","rotateIndex","setRotateIndex","selectedIndex","setSelectedIndex","hasLimit","length","Math","min","previousItems","isEqual","current","map","item","value","inputHandler","input","key","upArrow","lastIndex","atFirstIndex","nextIndex","nextRotateIndex","nextSelectedIndex","slicedItems","slice","downArrow","isAtLastIndex","return","isActive","visibleItem","marginRight","success","question","flexDirection","color","highlighted","body","String","index","isSelected","selected","selectedCircle","unselected","unselectedCircle","muted"],"mappings":"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"}
@@ -1,4 +1,6 @@
1
1
  import { ValidationError, ParsingError } from '@jakubmazanec/args';
2
+ import { zodIssuesToStrings } from '@jakubmazanec/zod-utils';
3
+ import { ZodError } from 'zod';
2
4
  /**
3
5
  * Creates detailed information about an error.
4
6
  */ export function getErrorDetail(error) {
@@ -37,6 +39,13 @@ import { ValidationError, ParsingError } from '@jakubmazanec/args';
37
39
  }
38
40
  return errorDetail;
39
41
  }
42
+ if (error instanceof ZodError) {
43
+ let errorDetail = {
44
+ label: 'Error',
45
+ description: zodIssuesToStrings(error.issues).join('\n')
46
+ };
47
+ return errorDetail;
48
+ }
40
49
  if (error instanceof Error) {
41
50
  let errorDetail = {
42
51
  label: 'Error',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/ui/getErrorDetail.ts"],"sourcesContent":["import {ValidationError, ParsingError} from '@jakubmazanec/args';\n\nimport {type ErrorDetail} from './ErrorDetail.js';\n\n/**\n * Creates detailed information about an error.\n */\nexport function getErrorDetail(error: unknown): ErrorDetail {\n // TODO: add all codes\n if (error instanceof ParsingError) {\n switch (error.code) {\n default: {\n return {\n label: 'Parsing error',\n description: error.message,\n };\n }\n }\n }\n\n // TODO: add all codes\n if (error instanceof ValidationError) {\n switch (error.code) {\n default: {\n return {\n label: 'Validation error',\n description: error.message,\n };\n }\n }\n }\n\n // TODO: add all built-in errors\n if (error instanceof ReferenceError) {\n let errorDetail: ErrorDetail = {\n label: 'Error',\n description: error.message,\n };\n\n if (error.stack) {\n errorDetail.stack = error.stack;\n }\n\n return errorDetail;\n }\n\n if (error instanceof Error) {\n let errorDetail: ErrorDetail = {\n label: 'Error',\n description: error.message,\n };\n\n if (error.stack) {\n errorDetail.stack = error.stack;\n }\n\n if (error.cause instanceof Error) {\n errorDetail.cause = {\n description: error.cause.message,\n };\n\n if (error.cause.stack) {\n errorDetail.cause.stack = error.cause.stack;\n }\n }\n\n return errorDetail;\n }\n\n return {\n label: 'Error',\n };\n}\n"],"names":["ValidationError","ParsingError","getErrorDetail","error","code","label","description","message","ReferenceError","errorDetail","stack","Error","cause"],"mappings":"AAAA,SAAQA,eAAe,EAAEC,YAAY,QAAO,qBAAqB;AAIjE;;CAEC,GACD,OAAO,SAASC,eAAeC,KAAc;IAC3C,sBAAsB;IACtB,IAAIA,iBAAiBF,cAAc;QACjC,OAAQE,MAAMC,IAAI;YAChB;gBAAS;oBACP,OAAO;wBACLC,OAAO;wBACPC,aAAaH,MAAMI,OAAO;oBAC5B;gBACF;QACF;IACF;IAEA,sBAAsB;IACtB,IAAIJ,iBAAiBH,iBAAiB;QACpC,OAAQG,MAAMC,IAAI;YAChB;gBAAS;oBACP,OAAO;wBACLC,OAAO;wBACPC,aAAaH,MAAMI,OAAO;oBAC5B;gBACF;QACF;IACF;IAEA,gCAAgC;IAChC,IAAIJ,iBAAiBK,gBAAgB;QACnC,IAAIC,cAA2B;YAC7BJ,OAAO;YACPC,aAAaH,MAAMI,OAAO;QAC5B;QAEA,IAAIJ,MAAMO,KAAK,EAAE;YACfD,YAAYC,KAAK,GAAGP,MAAMO,KAAK;QACjC;QAEA,OAAOD;IACT;IAEA,IAAIN,iBAAiBQ,OAAO;QAC1B,IAAIF,cAA2B;YAC7BJ,OAAO;YACPC,aAAaH,MAAMI,OAAO;QAC5B;QAEA,IAAIJ,MAAMO,KAAK,EAAE;YACfD,YAAYC,KAAK,GAAGP,MAAMO,KAAK;QACjC;QAEA,IAAIP,MAAMS,KAAK,YAAYD,OAAO;YAChCF,YAAYG,KAAK,GAAG;gBAClBN,aAAaH,MAAMS,KAAK,CAACL,OAAO;YAClC;YAEA,IAAIJ,MAAMS,KAAK,CAACF,KAAK,EAAE;gBACrBD,YAAYG,KAAK,CAACF,KAAK,GAAGP,MAAMS,KAAK,CAACF,KAAK;YAC7C;QACF;QAEA,OAAOD;IACT;IAEA,OAAO;QACLJ,OAAO;IACT;AACF"}
1
+ {"version":3,"sources":["../../src/ui/getErrorDetail.ts"],"sourcesContent":["import {ValidationError, ParsingError} from '@jakubmazanec/args';\nimport {zodIssuesToStrings} from '@jakubmazanec/zod-utils';\nimport {ZodError} from 'zod';\n\nimport {type ErrorDetail} from './ErrorDetail.js';\n\n/**\n * Creates detailed information about an error.\n */\nexport function getErrorDetail(error: unknown): ErrorDetail {\n // TODO: add all codes\n if (error instanceof ParsingError) {\n switch (error.code) {\n default: {\n return {\n label: 'Parsing error',\n description: error.message,\n };\n }\n }\n }\n\n // TODO: add all codes\n if (error instanceof ValidationError) {\n switch (error.code) {\n default: {\n return {\n label: 'Validation error',\n description: error.message,\n };\n }\n }\n }\n\n // TODO: add all built-in errors\n if (error instanceof ReferenceError) {\n let errorDetail: ErrorDetail = {\n label: 'Error',\n description: error.message,\n };\n\n if (error.stack) {\n errorDetail.stack = error.stack;\n }\n\n return errorDetail;\n }\n\n if (error instanceof ZodError) {\n let errorDetail: ErrorDetail = {\n label: 'Error',\n description: zodIssuesToStrings(error.issues).join('\\n'),\n };\n\n return errorDetail;\n }\n\n if (error instanceof Error) {\n let errorDetail: ErrorDetail = {\n label: 'Error',\n description: error.message,\n };\n\n if (error.stack) {\n errorDetail.stack = error.stack;\n }\n\n if (error.cause instanceof Error) {\n errorDetail.cause = {\n description: error.cause.message,\n };\n\n if (error.cause.stack) {\n errorDetail.cause.stack = error.cause.stack;\n }\n }\n\n return errorDetail;\n }\n\n return {\n label: 'Error',\n };\n}\n"],"names":["ValidationError","ParsingError","zodIssuesToStrings","ZodError","getErrorDetail","error","code","label","description","message","ReferenceError","errorDetail","stack","issues","join","Error","cause"],"mappings":"AAAA,SAAQA,eAAe,EAAEC,YAAY,QAAO,qBAAqB;AACjE,SAAQC,kBAAkB,QAAO,0BAA0B;AAC3D,SAAQC,QAAQ,QAAO,MAAM;AAI7B;;CAEC,GACD,OAAO,SAASC,eAAeC,KAAc;IAC3C,sBAAsB;IACtB,IAAIA,iBAAiBJ,cAAc;QACjC,OAAQI,MAAMC,IAAI;YAChB;gBAAS;oBACP,OAAO;wBACLC,OAAO;wBACPC,aAAaH,MAAMI,OAAO;oBAC5B;gBACF;QACF;IACF;IAEA,sBAAsB;IACtB,IAAIJ,iBAAiBL,iBAAiB;QACpC,OAAQK,MAAMC,IAAI;YAChB;gBAAS;oBACP,OAAO;wBACLC,OAAO;wBACPC,aAAaH,MAAMI,OAAO;oBAC5B;gBACF;QACF;IACF;IAEA,gCAAgC;IAChC,IAAIJ,iBAAiBK,gBAAgB;QACnC,IAAIC,cAA2B;YAC7BJ,OAAO;YACPC,aAAaH,MAAMI,OAAO;QAC5B;QAEA,IAAIJ,MAAMO,KAAK,EAAE;YACfD,YAAYC,KAAK,GAAGP,MAAMO,KAAK;QACjC;QAEA,OAAOD;IACT;IAEA,IAAIN,iBAAiBF,UAAU;QAC7B,IAAIQ,cAA2B;YAC7BJ,OAAO;YACPC,aAAaN,mBAAmBG,MAAMQ,MAAM,EAAEC,IAAI,CAAC;QACrD;QAEA,OAAOH;IACT;IAEA,IAAIN,iBAAiBU,OAAO;QAC1B,IAAIJ,cAA2B;YAC7BJ,OAAO;YACPC,aAAaH,MAAMI,OAAO;QAC5B;QAEA,IAAIJ,MAAMO,KAAK,EAAE;YACfD,YAAYC,KAAK,GAAGP,MAAMO,KAAK;QACjC;QAEA,IAAIP,MAAMW,KAAK,YAAYD,OAAO;YAChCJ,YAAYK,KAAK,GAAG;gBAClBR,aAAaH,MAAMW,KAAK,CAACP,OAAO;YAClC;YAEA,IAAIJ,MAAMW,KAAK,CAACJ,KAAK,EAAE;gBACrBD,YAAYK,KAAK,CAACJ,KAAK,GAAGP,MAAMW,KAAK,CAACJ,KAAK;YAC7C;QACF;QAEA,OAAOD;IACT;IAEA,OAAO;QACLJ,OAAO;IACT;AACF"}
@@ -1,12 +1,12 @@
1
1
  import { type FC, type PropsWithChildren } from 'react';
2
2
  import { type Program } from '../../program.js';
3
3
  /**
4
- * {@linkcode Wrapper} component props.
4
+ * {@link Wrapper} component props.
5
5
  */
6
6
  export type WrapperProps = {
7
7
  program: Program;
8
8
  };
9
9
  /**
10
- * A component that wraps anything {@linkcode Program} tries to render with an error boundary and all neccessary providers.
10
+ * A component that wraps anything {@link Program} tries to render with an error boundary and all neccessary providers.
11
11
  */
12
12
  export declare const Wrapper: FC<PropsWithChildren<WrapperProps>>;
@@ -5,7 +5,7 @@ import { ErrorBoundary } from 'react-error-boundary';
5
5
  import { programContext } from './programContext.js';
6
6
  import { Failure } from '../Failure.js';
7
7
  /**
8
- * A component that wraps anything {@linkcode Program} tries to render with an error boundary and all neccessary providers.
8
+ * A component that wraps anything {@link Program} tries to render with an error boundary and all neccessary providers.
9
9
  */ export const Wrapper = ({ program, children })=>{
10
10
  let programContextValue = useMemo(()=>({
11
11
  program
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/ui/internals/Wrapper.tsx"],"sourcesContent":["import {Box} from 'ink';\nimport {useMemo, type FC, type PropsWithChildren} from 'react';\nimport {ErrorBoundary} from 'react-error-boundary';\n\nimport {programContext} from './programContext.js';\nimport {type Program} from '../../program.js';\nimport {Failure} from '../Failure.js';\n\n/**\n * {@linkcode Wrapper} component props.\n */\nexport type WrapperProps = {\n program: Program;\n};\n\n/**\n * A component that wraps anything {@linkcode 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 <Box>{children}</Box>\n </programContext.Provider>\n </ErrorBoundary>\n );\n};\n"],"names":["Box","useMemo","ErrorBoundary","programContext","Failure","Wrapper","program","children","programContextValue","FallbackComponent","Provider","value"],"mappings":";AAAA,SAAQA,GAAG,QAAO,MAAM;AACxB,SAAQC,OAAO,QAAwC,QAAQ;AAC/D,SAAQC,aAAa,QAAO,uBAAuB;AAEnD,SAAQC,cAAc,QAAO,sBAAsB;AAEnD,SAAQC,OAAO,QAAO,gBAAgB;AAStC;;CAEC,GACD,OAAO,MAAMC,UAA+C,CAAC,EAACC,OAAO,EAAEC,QAAQ,EAAC;IAC9E,IAAIC,sBAAsBP,QACxB,IAAO,CAAA;YACLK;QACF,CAAA,GACA;QAACA;KAAQ;IAGX,qBACE,KAACJ;QAAcO,mBAAmBL;kBAChC,cAAA,KAACD,eAAeO,QAAQ;YAACC,OAAOH;sBAC9B,cAAA,KAACR;0BAAKO;;;;AAId,EAAE"}
1
+ {"version":3,"sources":["../../../src/ui/internals/Wrapper.tsx"],"sourcesContent":["import {Box} from 'ink';\nimport {useMemo, type FC, type PropsWithChildren} from 'react';\nimport {ErrorBoundary} from 'react-error-boundary';\n\nimport {programContext} from './programContext.js';\nimport {type Program} from '../../program.js';\nimport {Failure} from '../Failure.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 <Box>{children}</Box>\n </programContext.Provider>\n </ErrorBoundary>\n );\n};\n"],"names":["Box","useMemo","ErrorBoundary","programContext","Failure","Wrapper","program","children","programContextValue","FallbackComponent","Provider","value"],"mappings":";AAAA,SAAQA,GAAG,QAAO,MAAM;AACxB,SAAQC,OAAO,QAAwC,QAAQ;AAC/D,SAAQC,aAAa,QAAO,uBAAuB;AAEnD,SAAQC,cAAc,QAAO,sBAAsB;AAEnD,SAAQC,OAAO,QAAO,gBAAgB;AAStC;;CAEC,GACD,OAAO,MAAMC,UAA+C,CAAC,EAACC,OAAO,EAAEC,QAAQ,EAAC;IAC9E,IAAIC,sBAAsBP,QACxB,IAAO,CAAA;YACLK;QACF,CAAA,GACA;QAACA;KAAQ;IAGX,qBACE,KAACJ;QAAcO,mBAAmBL;kBAChC,cAAA,KAACD,eAAeO,QAAQ;YAACC,OAAOH;sBAC9B,cAAA,KAACR;0BAAKO;;;;AAId,EAAE"}
@@ -4,6 +4,6 @@ export type ProgramContext = {
4
4
  program: Program;
5
5
  };
6
6
  /**
7
- * A React context that stores {@linkcode Program} instance.
7
+ * A React context that stores {@link Program} instance.
8
8
  */
9
9
  export declare const programContext: React.Context<ProgramContext>;
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  /**
3
- * A React context that stores {@linkcode Program} instance.
3
+ * A React context that stores {@link Program} instance.
4
4
  */ export const programContext = React.createContext({});
5
5
 
6
6
  //# sourceMappingURL=programContext.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/ui/internals/programContext.ts"],"sourcesContent":["import React from 'react';\n\nimport {type Program} from '../../program/Program.js';\n\nexport type ProgramContext = {\n program: Program;\n};\n\n/**\n * A React context that stores {@linkcode Program} instance.\n */\nexport const programContext = React.createContext<ProgramContext>({} as ProgramContext);\n"],"names":["React","programContext","createContext"],"mappings":"AAAA,OAAOA,WAAW,QAAQ;AAQ1B;;CAEC,GACD,OAAO,MAAMC,iBAAiBD,MAAME,aAAa,CAAiB,CAAC,GAAqB"}
1
+ {"version":3,"sources":["../../../src/ui/internals/programContext.ts"],"sourcesContent":["import React from 'react';\n\nimport {type Program} from '../../program/Program.js';\n\nexport type ProgramContext = {\n program: Program;\n};\n\n/**\n * A React context that stores {@link Program} instance.\n */\nexport const programContext = React.createContext<ProgramContext>({} as ProgramContext);\n"],"names":["React","programContext","createContext"],"mappings":"AAAA,OAAOA,WAAW,QAAQ;AAQ1B;;CAEC,GACD,OAAO,MAAMC,iBAAiBD,MAAME,aAAa,CAAiB,CAAC,GAAqB"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * A React hook for accessing {@linkcode Program} instance and `exit` function that is used for showing 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.
3
3
  */
4
4
  export declare function useProgram(): {
5
5
  program: import("../program.js").Program;
@@ -3,7 +3,7 @@ import { useCallback, useContext } from 'react';
3
3
  import { useErrorBoundary } from 'react-error-boundary';
4
4
  import { programContext } from './internals.js';
5
5
  /**
6
- * A React hook for accessing {@linkcode Program} instance and `exit` function that is used for showing an error (via an error boundary) and exiting.
6
+ * A React hook for accessing {@link Program} instance and `exit` function that is used for showing an error (via an error boundary) and exiting.
7
7
  */ export function useProgram() {
8
8
  let { showBoundary } = useErrorBoundary();
9
9
  let { exit: appExit } = useApp();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/ui/useProgram.ts"],"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 {@linkcode 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 showBoundary(error);\n appExit(error as Error);\n },\n [appExit, showBoundary],\n );\n\n return {program, exit};\n}\n"],"names":["useApp","useCallback","useContext","useErrorBoundary","programContext","useProgram","showBoundary","exit","appExit","program","error"],"mappings":"AAAA,SAAQA,MAAM,QAAO,MAAM;AAC3B,SAAQC,WAAW,EAAEC,UAAU,QAAO,QAAQ;AAC9C,SAAQC,gBAAgB,QAAO,uBAAuB;AAEtD,SAAQC,cAAc,QAAO,iBAAiB;AAE9C;;CAEC,GACD,OAAO,SAASC;IACd,IAAI,EAACC,YAAY,EAAC,GAAGH;IACrB,IAAI,EAACI,MAAMC,OAAO,EAAC,GAAGR;IACtB,IAAI,EAACS,OAAO,EAAC,GAAGP,WAAWE;IAE3B,IAAIG,OAAON,YACT,CAACS;QACCJ,aAAaI;QACbF,QAAQE;IACV,GACA;QAACF;QAASF;KAAa;IAGzB,OAAO;QAACG;QAASF;IAAI;AACvB"}
1
+ {"version":3,"sources":["../../src/ui/useProgram.ts"],"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 showBoundary(error);\n appExit(error as Error);\n },\n [appExit, showBoundary],\n );\n\n return {program, exit};\n}\n"],"names":["useApp","useCallback","useContext","useErrorBoundary","programContext","useProgram","showBoundary","exit","appExit","program","error"],"mappings":"AAAA,SAAQA,MAAM,QAAO,MAAM;AAC3B,SAAQC,WAAW,EAAEC,UAAU,QAAO,QAAQ;AAC9C,SAAQC,gBAAgB,QAAO,uBAAuB;AAEtD,SAAQC,cAAc,QAAO,iBAAiB;AAE9C;;CAEC,GACD,OAAO,SAASC;IACd,IAAI,EAACC,YAAY,EAAC,GAAGH;IACrB,IAAI,EAACI,MAAMC,OAAO,EAAC,GAAGR;IACtB,IAAI,EAACS,OAAO,EAAC,GAAGP,WAAWE;IAE3B,IAAIG,OAAON,YACT,CAACS;QACCJ,aAAaI;QACbF,QAAQE;IACV,GACA;QAACF;QAASF;KAAa;IAGzB,OAAO;QAACG;QAASF;IAAI;AACvB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jakubmazanec/cli",
3
- "version": "0.1.0-593aae1",
3
+ "version": "0.1.0-5f6d70c",
4
4
  "description": "TypeScript-first library for building CLIs.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -27,13 +27,14 @@
27
27
  "typecheck": "tsc --project tsconfig.typecheck.json"
28
28
  },
29
29
  "dependencies": {
30
- "@jakubmazanec/args": "1.0.1-593aae1",
31
- "@jakubmazanec/error": "2.0.1-593aae1",
32
- "@jakubmazanec/ts-utils": "2.1.0-593aae1",
33
- "@jakubmazanec/zod-utils": "1.0.0-593aae1",
30
+ "@jakubmazanec/args": "1.0.1-5f6d70c",
31
+ "@jakubmazanec/error": "2.0.1-5f6d70c",
32
+ "@jakubmazanec/ts-utils": "2.1.0-5f6d70c",
33
+ "@jakubmazanec/zod-utils": "1.0.0-5f6d70c",
34
34
  "chalk": "^5.2.0",
35
35
  "lodash": "^4.17.21",
36
- "react-error-boundary": "^4.0.7"
36
+ "react-error-boundary": "^4.0.7",
37
+ "zod": "^3.14.4"
37
38
  },
38
39
  "devDependencies": {
39
40
  "@jest/globals": "^29.5.0",
@@ -12,7 +12,7 @@ import {type Program} from './Program.js';
12
12
  // import {type ProgramCommand} from './ProgramCommand.js';
13
13
 
14
14
  /**
15
- * Command encapsulates piece of a CLI's logic and is executed when {@linkcode Program} instance parses that command from the command line arguments.
15
+ * Command encapsulates piece of a CLI's logic and is executed when {@link Program} instance parses that command from the command line arguments.
16
16
  */
17
17
  export class Command<
18
18
  A extends string,
@@ -104,7 +104,7 @@ export class Command<
104
104
  }
105
105
 
106
106
  /**
107
- * Executes command action with provided parsed arguments and {@linkcode Program} instance.
107
+ * Executes command action with provided parsed arguments and {@link Program} instance.
108
108
  */
109
109
  async run(
110
110
  parsedArgs: Arguments<{
@@ -1,5 +1,7 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any -- needed */
2
2
  import {type ParametersConfig, type Argv, type OptionsConfig} from '@jakubmazanec/args';
3
+ import {type ComponentType} from 'react';
4
+ import {type FallbackProps} from 'react-error-boundary';
3
5
 
4
6
  import {type Command} from './Command.js';
5
7
  import {ProgramError} from './ProgramError.js';
@@ -9,7 +11,7 @@ import {Wrapper} from '../ui/internals.js';
9
11
  import {Failure, Help} from '../ui.js';
10
12
 
11
13
  /**
12
- * Program manages and executes {@linkcode Command} instances attached to it based on parsing command line arguments.
14
+ * Program manages and executes {@link Command} instances attached to it based on parsing command line arguments.
13
15
  */
14
16
  export class Program {
15
17
  /** Program name. */
@@ -37,7 +39,10 @@ export class Program {
37
39
  stdout: process.stdout,
38
40
  };
39
41
 
40
- constructor({name, version, description, bin}: ProgramOptions) {
42
+ /** Custom error boundary fallback component */
43
+ ErrorBoundaryFallbackComponent: ComponentType<FallbackProps>;
44
+
45
+ constructor({name, version, description, bin, ErrorBoundaryFallbackComponent}: ProgramOptions) {
41
46
  if (name) {
42
47
  this.name = name;
43
48
  }
@@ -53,6 +58,12 @@ export class Program {
53
58
  if (bin) {
54
59
  this.bin = bin;
55
60
  }
61
+
62
+ if (ErrorBoundaryFallbackComponent) {
63
+ this.ErrorBoundaryFallbackComponent = ErrorBoundaryFallbackComponent;
64
+ } else {
65
+ this.ErrorBoundaryFallbackComponent = Failure;
66
+ }
56
67
  }
57
68
 
58
69
  /**
@@ -92,7 +103,9 @@ export class Program {
92
103
  });
93
104
  } catch (error: unknown) {
94
105
  if (error instanceof Error) {
95
- await this.renderElement(createElement(Failure, {error}));
106
+ await this.renderElement(
107
+ createElement(this.ErrorBoundaryFallbackComponent, {error, resetErrorBoundary: () => {}}),
108
+ );
96
109
  }
97
110
  } finally {
98
111
  this.isRendering = false;
@@ -117,7 +130,12 @@ export class Program {
117
130
  let {createElement} = await import('react');
118
131
 
119
132
  for (let error of parsedArgs.errors) {
120
- await this.renderElement(createElement(Failure, {error}));
133
+ await this.renderElement(
134
+ createElement(this.ErrorBoundaryFallbackComponent, {
135
+ error,
136
+ resetErrorBoundary: () => {},
137
+ }),
138
+ );
121
139
  }
122
140
  } else {
123
141
  try {
@@ -126,7 +144,12 @@ export class Program {
126
144
  let {createElement} = await import('react');
127
145
 
128
146
  if (error instanceof Error) {
129
- await this.renderElement(createElement(Failure, {error}));
147
+ await this.renderElement(
148
+ createElement(this.ErrorBoundaryFallbackComponent, {
149
+ error,
150
+ resetErrorBoundary: () => {},
151
+ }),
152
+ );
130
153
  }
131
154
  }
132
155
 
@@ -1,5 +1,8 @@
1
+ import {type ComponentType} from 'react';
2
+ import {type FallbackProps} from 'react-error-boundary';
3
+
1
4
  /**
2
- * Options for creating new {@linkcode Program} instance.
5
+ * Options for creating new {@link Program} instance.
3
6
  */
4
7
  export type ProgramOptions = {
5
8
  /** Program name. */
@@ -13,4 +16,7 @@ export type ProgramOptions = {
13
16
 
14
17
  /** Program executable name. */
15
18
  bin?: string | undefined;
19
+
20
+ /** Custom error boundary fallback component */
21
+ ErrorBoundaryFallbackComponent?: ComponentType<FallbackProps>;
16
22
  };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * {@linkcode Program} streams;
2
+ * {@link Program} streams;
3
3
  */
4
4
  export type ProgramStreams = {
5
5
  stderr: NodeJS.WriteStream;
@@ -7,10 +7,10 @@ import {Header} from './Header.js';
7
7
  import * as icons from './icons.js';
8
8
 
9
9
  /**
10
- * {@linkcode Failure} component props.
10
+ * {@link Failure} component props.
11
11
  */
12
12
  export type FailureProps = BoxProps & {
13
- /** Error that describes a failure state. Function {@linkcode 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. */
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. */
14
14
  error: Error;
15
15
 
16
16
  /** Information about the failure state. Overrides information retireved from `error` prop. */
package/src/ui/Header.tsx CHANGED
@@ -4,7 +4,7 @@ import {type PropsWithChildren} from 'react';
4
4
  import {Spinner} from './Spinner.js';
5
5
 
6
6
  /**
7
- * {@linkcode Header} component props.
7
+ * {@link Header} component props.
8
8
  */
9
9
  export type HeaderProps = BoxProps & {
10
10
  /** Icon (recommended is 1 character) to render before the header itself. */
package/src/ui/Help.tsx CHANGED
@@ -7,10 +7,10 @@ import * as icons from './icons.js';
7
7
  import {type Program} from '../program.js';
8
8
 
9
9
  /**
10
- * {@linkcode Help} component props.
10
+ * {@link Help} component props.
11
11
  */
12
12
  export type HelpProps = BoxProps & {
13
- /** {@linkcode Program} instance. */
13
+ /** {@link Program} instance. */
14
14
  program: Program;
15
15
  };
16
16
 
@@ -47,7 +47,6 @@ export function SelectInput({
47
47
  limit: customLimit,
48
48
  onSelect,
49
49
  onHighlight,
50
- marginTop = 0,
51
50
  isComplete,
52
51
  ...boxProps
53
52
  }: SelectInputProps): JSX.Element {
@@ -151,9 +150,7 @@ export function SelectInput({
151
150
  <Text color={colors.unselected}>{icons.unselectedCircle}</Text>
152
151
  )}
153
152
  </Box>
154
- <Text
155
- color={isSelected ? colors.highlighted : colors.muted}
156
- >{`${item.label}`}</Text>
153
+ <Text color={isSelected ? colors.highlighted : colors.muted}>{item.label}</Text>
157
154
  </Box>
158
155
  );
159
156
  })}
@@ -1,4 +1,6 @@
1
1
  import {ValidationError, ParsingError} from '@jakubmazanec/args';
2
+ import {zodIssuesToStrings} from '@jakubmazanec/zod-utils';
3
+ import {ZodError} from 'zod';
2
4
 
3
5
  import {type ErrorDetail} from './ErrorDetail.js';
4
6
 
@@ -44,6 +46,15 @@ export function getErrorDetail(error: unknown): ErrorDetail {
44
46
  return errorDetail;
45
47
  }
46
48
 
49
+ if (error instanceof ZodError) {
50
+ let errorDetail: ErrorDetail = {
51
+ label: 'Error',
52
+ description: zodIssuesToStrings(error.issues).join('\n'),
53
+ };
54
+
55
+ return errorDetail;
56
+ }
57
+
47
58
  if (error instanceof Error) {
48
59
  let errorDetail: ErrorDetail = {
49
60
  label: 'Error',
@@ -7,14 +7,14 @@ import {type Program} from '../../program.js';
7
7
  import {Failure} from '../Failure.js';
8
8
 
9
9
  /**
10
- * {@linkcode Wrapper} component props.
10
+ * {@link Wrapper} component props.
11
11
  */
12
12
  export type WrapperProps = {
13
13
  program: Program;
14
14
  };
15
15
 
16
16
  /**
17
- * A component that wraps anything {@linkcode Program} tries to render with an error boundary and all neccessary providers.
17
+ * A component that wraps anything {@link Program} tries to render with an error boundary and all neccessary providers.
18
18
  */
19
19
  export const Wrapper: FC<PropsWithChildren<WrapperProps>> = ({program, children}) => {
20
20
  let programContextValue = useMemo(
@@ -7,6 +7,6 @@ export type ProgramContext = {
7
7
  };
8
8
 
9
9
  /**
10
- * A React context that stores {@linkcode Program} instance.
10
+ * A React context that stores {@link Program} instance.
11
11
  */
12
12
  export const programContext = React.createContext<ProgramContext>({} as ProgramContext);
@@ -5,7 +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 {@linkcode Program} instance and `exit` function that is used for showing 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.
9
9
  */
10
10
  export function useProgram() {
11
11
  let {showBoundary} = useErrorBoundary();