@jakubmazanec/cli 0.3.4 → 0.3.5-next.0f7252e

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.
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  import fs from "fs-extra";
3
3
  import fetchLatestVersion from "latest-version";
4
- import path from "path";
4
+ import path from "node:path";
5
5
  import { CACHE_PATH } from "../constants.js";
6
6
  import { Failure, Help } from "../ui.js";
7
7
  import { Wrapper } from "../ui/internals.js";
@@ -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 '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"],
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
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,11 +1,11 @@
1
1
  export * from './program/Command.js';
2
- export * from './program/CommandAction.js';
3
- export * from './program/CommandArguments.js';
4
- export * from './program/CommandOptions.js';
2
+ export type * from './program/CommandAction.js';
3
+ export type * from './program/CommandArguments.js';
4
+ export type * from './program/CommandOptions.js';
5
5
  export * from './program/getProgramDetail.js';
6
6
  export * from './program/Program.js';
7
- export * from './program/ProgramCreateOptions.js';
8
- export * from './program/ProgramDetail.js';
7
+ export type * from './program/ProgramCreateOptions.js';
8
+ export type * from './program/ProgramDetail.js';
9
9
  export * from './program/ProgramError.js';
10
- export * from './program/ProgramOptions.js';
11
- export * from './program/ProgramStreams.js';
10
+ export type * from './program/ProgramOptions.js';
11
+ export type * from './program/ProgramStreams.js';
package/build/program.js CHANGED
@@ -1,13 +1,6 @@
1
1
  "use strict";
2
2
  export * from "./program/Command.js";
3
- export * from "./program/CommandAction.js";
4
- export * from "./program/CommandArguments.js";
5
- export * from "./program/CommandOptions.js";
6
3
  export * from "./program/getProgramDetail.js";
7
4
  export * from "./program/Program.js";
8
- export * from "./program/ProgramCreateOptions.js";
9
- export * from "./program/ProgramDetail.js";
10
5
  export * from "./program/ProgramError.js";
11
- export * from "./program/ProgramOptions.js";
12
- export * from "./program/ProgramStreams.js";
13
6
  //# sourceMappingURL=program.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../source/program.ts"],
4
- "sourcesContent": ["export * from './program/Command.js';\nexport * from './program/CommandAction.js';\nexport * from './program/CommandArguments.js';\nexport * from './program/CommandOptions.js';\nexport * from './program/getProgramDetail.js';\nexport * from './program/Program.js';\nexport * from './program/ProgramCreateOptions.js';\nexport * from './program/ProgramDetail.js';\nexport * from './program/ProgramError.js';\nexport * from './program/ProgramOptions.js';\nexport * from './program/ProgramStreams.js';\n"],
5
- "mappings": ";AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
4
+ "sourcesContent": ["export * from './program/Command.js';\nexport type * from './program/CommandAction.js';\nexport type * from './program/CommandArguments.js';\nexport type * from './program/CommandOptions.js';\nexport * from './program/getProgramDetail.js';\nexport * from './program/Program.js';\nexport type * from './program/ProgramCreateOptions.js';\nexport type * from './program/ProgramDetail.js';\nexport * from './program/ProgramError.js';\nexport type * from './program/ProgramOptions.js';\nexport type * from './program/ProgramStreams.js';\n"],
5
+ "mappings": ";AAAA,cAAc;AAId,cAAc;AACd,cAAc;AAGd,cAAc;",
6
6
  "names": []
7
7
  }
@@ -10,10 +10,10 @@ export function Failure({ error, errorDetail, ...boxProps }) {
10
10
  return /* @__PURE__ */ jsxs(Box, { ...boxProps, flexDirection: "column", children: [
11
11
  /* @__PURE__ */ jsx(Header, { icon: icons.error, children: /* @__PURE__ */ jsx(Text, { color: colors.highlighted, children: label }) }),
12
12
  description ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginLeft: 2, children: /* @__PURE__ */ jsx(Text, { color: colors.failure, children: description }) }) : null,
13
- stack ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, marginLeft: 2, children: /* @__PURE__ */ jsx(Text, { color: colors.muted, children: stack }) }) : null,
13
+ stack ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginLeft: 2, marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: colors.muted, children: stack }) }) : null,
14
14
  cause ? /* @__PURE__ */ jsxs(Fragment, { children: [
15
- /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, marginLeft: 2, children: /* @__PURE__ */ jsx(Text, { color: colors.muted, children: cause.description }) }),
16
- cause.stack ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, marginLeft: 2, children: /* @__PURE__ */ jsx(Text, { color: colors.muted, children: cause.stack }) }) : null
15
+ /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginLeft: 2, marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: colors.muted, children: cause.description }) }),
16
+ cause.stack ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginLeft: 2, marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: colors.muted, children: cause.stack }) }) : null
17
17
  ] }) : null
18
18
  ] });
19
19
  }
@@ -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 /** 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"],
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,WAAW,GAAG,YAAY,GACpD,8BAAC,QAAK,OAAO,OAAO,OAAQ,iBAAM,GACpC,IACA;AAAA,IAED,QACC,iCACE;AAAA,0BAAC,OAAI,eAAc,UAAS,WAAW,GAAG,YAAY,GACpD,8BAAC,QAAK,OAAO,OAAO,OAAQ,gBAAM,aAAY,GAChD;AAAA,MAEC,MAAM,QACL,oBAAC,OAAI,eAAc,UAAS,WAAW,GAAG,YAAY,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: 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\" 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
  }
package/build/ui/Help.js CHANGED
@@ -30,7 +30,7 @@ export function Help({ program, ...boxProps }) {
30
30
  if (command.description) {
31
31
  line += ` ${command.description}`;
32
32
  }
33
- return /* @__PURE__ */ jsx(Box, { marginLeft: 2, flexDirection: "column", children: /* @__PURE__ */ jsx(Text, { children: line }) }, command.name);
33
+ return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginLeft: 2, children: /* @__PURE__ */ jsx(Text, { children: line }) }, command.name);
34
34
  })
35
35
  ] }) : null
36
36
  ] });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../source/ui/Help.tsx"],
4
- "sourcesContent": ["import chalk from 'chalk';\nimport {Box, type BoxProps, Text} from 'ink';\n\nimport {type Program} from '../program.js';\nimport * as colors from './colors.js';\nimport {Header} from './Header.js';\nimport * as icons from './icons.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.displayName ?? program.name ?? '?')} ${chalk[\n colors.muted\n ](program.version ?? '?')}`}</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"],
5
- "mappings": ";AAsBM,SAME,UANF,KAME,YANF;AAtBN,OAAO,WAAW;AAClB,SAAQ,KAAoB,YAAW;AAGvC,YAAY,YAAY;AACxB,SAAQ,cAAa;AACrB,YAAY,WAAW;AAahB,gBAAS,KAAK,EAAC,SAAS,GAAG,SAAQ,GAAc;AACtD,SACE,qBAAC,OAAK,GAAG,UAAU,eAAc,UAC/B;AAAA,wBAAC,QAAM,aAAG,MAAM,OAAO,MAAM,EAAE,QAAQ,eAAe,QAAQ,QAAQ,GAAG,CAAC,IAAI,MAC5E,OAAO,KACT,EAAE,QAAQ,WAAW,GAAG,CAAC,IAAG;AAAA,IAC5B,oBAAC,QAAK,OAAO,OAAO,MAAO,kBAAQ,aAAY;AAAA,IAE9C,QAAQ,SAAS,SAChB,iCACE;AAAA,0BAAC,UAAO,MAAM,MAAM,MAAM,WAAW,GACnC,8BAAC,QAAK,OAAO,OAAO,aAAa,mBAAK,GACxC;AAAA,MACC,QAAQ,SAAS,IAAI,CAAC,YAAY;AACjC,YAAI,OAAO,GAAG,MAAM,OAAO,KAAK,EAAE,QAAQ,OAAO,GAAG,CAAC,IAAI,QAAQ,IAAI;AAErE,YAAI,QAAQ,YAAY;AACtB,cAAI,QAAQ,WAAW,KAAK,CAAC,oBAAoB,CAAC,CAAC,gBAAgB,QAAQ,GAAG;AAC5E,oBAAQ,IAAI,MAAM,OAAO,KAAK,EAAE,cAAc,CAAC;AAAA,UACjD,OAAO;AACL,oBAAQ,IAAI,MAAM,OAAO,KAAK,EAAE,gBAAgB,CAAC;AAAA,UACnD;AAAA,QACF;AAEA,YAAI,QAAQ,SAAS;AACnB,cACE,OAAO,QAAQ,QAAQ,OAAO,EAAE,KAAK,CAAC,CAAC,EAAE,YAAY,MAAM,CAAC,CAAC,aAAa,QAAQ,GAClF;AACA,oBAAQ,IAAI,MAAM,OAAO,KAAK,EAAE,WAAW,CAAC;AAAA,UAC9C,OAAO;AACL,oBAAQ,IAAI,MAAM,OAAO,KAAK,EAAE,aAAa,CAAC;AAAA,UAChD;AAAA,QACF;AAEA,YAAI,QAAQ,aAAa;AACvB,kBAAQ,IAAI,QAAQ,WAAW;AAAA,QACjC;AAEA,eACE,oBAAC,OAAuB,YAAY,GAAG,eAAc,UACnD,8BAAC,QAAM,gBAAK,KADJ,QAAQ,IAElB;AAAA,MAEJ,CAAC;AAAA,OACH,IACA;AAAA,KACJ;AAEJ;",
4
+ "sourcesContent": ["import chalk from 'chalk';\nimport {Box, type BoxProps, Text} from 'ink';\n\nimport {type Program} from '../program.js';\nimport * as colors from './colors.js';\nimport {Header} from './Header.js';\nimport * as icons from './icons.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.displayName ?? program.name ?? '?')} ${chalk[\n colors.muted\n ](program.version ?? '?')}`}</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} flexDirection=\"column\" marginLeft={2}>\n <Text>{line}</Text>\n </Box>\n );\n })}\n </>\n : null}\n </Box>\n );\n}\n"],
5
+ "mappings": ";AAsBM,SAME,UANF,KAME,YANF;AAtBN,OAAO,WAAW;AAClB,SAAQ,KAAoB,YAAW;AAGvC,YAAY,YAAY;AACxB,SAAQ,cAAa;AACrB,YAAY,WAAW;AAahB,gBAAS,KAAK,EAAC,SAAS,GAAG,SAAQ,GAAc;AACtD,SACE,qBAAC,OAAK,GAAG,UAAU,eAAc,UAC/B;AAAA,wBAAC,QAAM,aAAG,MAAM,OAAO,MAAM,EAAE,QAAQ,eAAe,QAAQ,QAAQ,GAAG,CAAC,IAAI,MAC5E,OAAO,KACT,EAAE,QAAQ,WAAW,GAAG,CAAC,IAAG;AAAA,IAC5B,oBAAC,QAAK,OAAO,OAAO,MAAO,kBAAQ,aAAY;AAAA,IAE9C,QAAQ,SAAS,SAChB,iCACE;AAAA,0BAAC,UAAO,MAAM,MAAM,MAAM,WAAW,GACnC,8BAAC,QAAK,OAAO,OAAO,aAAa,mBAAK,GACxC;AAAA,MACC,QAAQ,SAAS,IAAI,CAAC,YAAY;AACjC,YAAI,OAAO,GAAG,MAAM,OAAO,KAAK,EAAE,QAAQ,OAAO,GAAG,CAAC,IAAI,QAAQ,IAAI;AAErE,YAAI,QAAQ,YAAY;AACtB,cAAI,QAAQ,WAAW,KAAK,CAAC,oBAAoB,CAAC,CAAC,gBAAgB,QAAQ,GAAG;AAC5E,oBAAQ,IAAI,MAAM,OAAO,KAAK,EAAE,cAAc,CAAC;AAAA,UACjD,OAAO;AACL,oBAAQ,IAAI,MAAM,OAAO,KAAK,EAAE,gBAAgB,CAAC;AAAA,UACnD;AAAA,QACF;AAEA,YAAI,QAAQ,SAAS;AACnB,cACE,OAAO,QAAQ,QAAQ,OAAO,EAAE,KAAK,CAAC,CAAC,EAAE,YAAY,MAAM,CAAC,CAAC,aAAa,QAAQ,GAClF;AACA,oBAAQ,IAAI,MAAM,OAAO,KAAK,EAAE,WAAW,CAAC;AAAA,UAC9C,OAAO;AACL,oBAAQ,IAAI,MAAM,OAAO,KAAK,EAAE,aAAa,CAAC;AAAA,UAChD;AAAA,QACF;AAEA,YAAI,QAAQ,aAAa;AACvB,kBAAQ,IAAI,QAAQ,WAAW;AAAA,QACjC;AAEA,eACE,oBAAC,OAAuB,eAAc,UAAS,YAAY,GACzD,8BAAC,QAAM,gBAAK,KADJ,QAAQ,IAElB;AAAA,MAEJ,CAAC;AAAA,OACH,IACA;AAAA,KACJ;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -33,37 +33,41 @@ export function FormRow({
33
33
  [rowName, onComplete]
34
34
  );
35
35
  switch (config.type) {
36
- case "text": {
36
+ case "confirm": {
37
+ return null;
38
+ }
39
+ case "select": {
37
40
  return /* @__PURE__ */ jsx(
38
- TextInput,
41
+ SelectInput,
39
42
  {
40
- label: config.label ?? "",
41
- validate: config.validate,
42
- value,
43
+ items: rows ? rows[rowName].choices : [],
43
44
  focus,
44
45
  isComplete,
45
- onChange: handleChange,
46
- onSubmit: handleFinish,
46
+ label: config.label ?? "",
47
+ onSelect: handleSelectFinish,
47
48
  ...boxProps
48
49
  },
49
50
  String(rowName)
50
51
  );
51
52
  }
52
- case "select": {
53
+ case "text": {
53
54
  return /* @__PURE__ */ jsx(
54
- SelectInput,
55
+ TextInput,
55
56
  {
56
- label: config.label ?? "",
57
- items: rows ? rows[rowName].choices : [],
58
57
  focus,
59
58
  isComplete,
60
- onSelect: handleSelectFinish,
59
+ label: config.label ?? "",
60
+ validate: config.validate,
61
+ value,
62
+ onChange: handleChange,
63
+ onSubmit: handleFinish,
61
64
  ...boxProps
62
65
  },
63
66
  String(rowName)
64
67
  );
65
68
  }
66
69
  default: {
70
+ config;
67
71
  return null;
68
72
  }
69
73
  }
@@ -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 /** 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 'text': {\n return (\n <TextInput\n key={String(rowName)}\n label={config.label ?? ''}\n validate={config.validate}\n value={value as string}\n focus={focus}\n isComplete={isComplete}\n onChange={handleChange}\n onSubmit={handleFinish}\n {...boxProps}\n />\n );\n }\n case 'select': {\n return (\n <SelectInput\n key={String(rowName)}\n label={config.label ?? ''}\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 onSelect={handleSelectFinish}\n {...boxProps}\n />\n );\n }\n default: {\n return null;\n }\n }\n}\n"],
5
- "mappings": ";AA8EQ;AA7ER,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,QAAQ;AACX,aACE;AAAA,QAAC;AAAA;AAAA,UAEC,OAAO,OAAO,SAAS;AAAA,UACvB,UAAU,OAAO;AAAA,UACjB;AAAA,UACA;AAAA,UACA;AAAA,UACA,UAAU;AAAA,UACV,UAAU;AAAA,UACT,GAAG;AAAA;AAAA,QARC,OAAO,OAAO;AAAA,MASrB;AAAA,IAEJ;AAAA,IACA,KAAK,UAAU;AACb,aACE;AAAA,QAAC;AAAA;AAAA,UAEC,OAAO,OAAO,SAAS;AAAA,UACvB,OACE,OAGM,KAGA,OAAiB,EACnB,UACF,CAAC;AAAA,UAEL;AAAA,UACA;AAAA,UACA,UAAU;AAAA,UACT,GAAG;AAAA;AAAA,QAhBC,OAAO,OAAO;AAAA,MAiBrB;AAAA,IAEJ;AAAA,IACA,SAAS;AACP,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
  }
@@ -91,11 +91,11 @@ export function TextInput({
91
91
  }
92
92
  } else if (key.backspace || key.delete) {
93
93
  if (state.cursorOffset > 0) {
94
- nextValue = originalValue.slice(0, state.cursorOffset - 1) + originalValue.slice(state.cursorOffset, originalValue.length);
94
+ nextValue = originalValue.slice(0, state.cursorOffset - 1) + originalValue.slice(state.cursorOffset);
95
95
  nextCursorOffset -= 1;
96
96
  }
97
97
  } else {
98
- nextValue = originalValue.slice(0, state.cursorOffset) + input + originalValue.slice(state.cursorOffset, originalValue.length);
98
+ nextValue = originalValue.slice(0, state.cursorOffset) + input + originalValue.slice(state.cursorOffset);
99
99
  nextCursorOffset += input.length;
100
100
  if (input.length > 1) {
101
101
  nextCursorWidth = input.length;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../source/ui/form/TextInput.tsx"],
4
- "sourcesContent": ["// TODO: resolve\n/* eslint-disable complexity -- TODO */\nimport 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, originalValue.length);\n\n nextCursorOffset -= 1;\n }\n } else {\n nextValue =\n originalValue.slice(0, state.cursorOffset) +\n input +\n originalValue.slice(state.cursorOffset, originalValue.length);\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
  }
@@ -51,12 +51,12 @@ export function createForm(formConfig) {
51
51
  /* @__PURE__ */ jsx(
52
52
  FormRow,
53
53
  {
54
- marginTop: inputElements.length === 0 ? 0 : 1,
54
+ config: input,
55
55
  focus: rowName === activeInputName,
56
56
  isComplete: results[rowName].isComplete,
57
- config: input,
58
- rows,
57
+ marginTop: inputElements.length === 0 ? 0 : 1,
59
58
  rowName,
59
+ rows,
60
60
  value: results[rowName].value,
61
61
  onChange: handleChange,
62
62
  onComplete: handleFinish
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../source/ui/form/createForm.tsx"],
4
- "sourcesContent": ["import {Box, type BoxProps} from 'ink';\nimport {useCallback} from 'react';\n\nimport {type Form} from './Form.js';\nimport {type FormConfig} from './FormConfig.js';\nimport {type FormProps} from './FormProps.js';\nimport {FormRow} from './FormRow.js';\n\n/**\n * Creates form component that contains individual rows with inputs based on the provided config.\n *\n * @param formConfig Form configuration.\n * @returns Form component.\n */\nexport function createForm<C extends FormConfig>(formConfig: C): Form<C> {\n let Form = ({\n rows,\n values: results,\n onChange,\n onComplete: onFinish,\n ...boxProps\n }: FormProps<C>) => {\n let handleChange = useCallback(\n (value: unknown, rowName: keyof C['rows']) => {\n if (onChange) {\n onChange({\n ...results,\n [rowName]: {\n ...results[rowName],\n value,\n },\n });\n }\n },\n [onChange, results],\n );\n\n let handleFinish = useCallback(\n (value: unknown, rowName: keyof C['rows']) => {\n onFinish({\n ...results,\n [rowName]: {\n value,\n isComplete: true,\n },\n });\n },\n [onFinish, results],\n );\n\n let inputElements = [];\n let activeInputName: string | null = null;\n\n for (let [rowName] of Object.entries(formConfig.rows)) {\n if (!results[rowName as keyof C['rows']].isComplete) {\n activeInputName = String(rowName);\n\n break;\n }\n }\n\n for (let [rowName, input] of Object.entries(formConfig.rows)) {\n if (results[rowName as keyof C['rows']].isComplete || rowName === activeInputName) {\n inputElements.push(\n <FormRow\n key={rowName}\n marginTop={inputElements.length === 0 ? 0 : 1}\n focus={rowName === activeInputName}\n isComplete={results[rowName as keyof C['rows']].isComplete}\n config={input}\n rows={rows}\n rowName={rowName}\n value={results[rowName as keyof C['rows']].value}\n onChange={handleChange}\n onComplete={handleFinish}\n />,\n );\n }\n }\n\n return (\n <Box {...(boxProps as BoxProps)} flexDirection=\"column\">\n {inputElements}\n </Box>\n );\n };\n\n return Object.assign(Form, {config: formConfig});\n}\n"],
5
- "mappings": ";AAgEU;AAhEV,SAAQ,WAAyB;AACjC,SAAQ,mBAAkB;AAK1B,SAAQ,eAAc;AAQf,gBAAS,WAAiC,YAAwB;AACvE,MAAI,OAAO,CAAC;AAAA,IACV;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA,YAAY;AAAA,IACZ,GAAG;AAAA,EACL,MAAoB;AAClB,QAAI,eAAe;AAAA,MACjB,CAAC,OAAgB,YAA6B;AAC5C,YAAI,UAAU;AACZ,mBAAS;AAAA,YACP,GAAG;AAAA,YACH,CAAC,OAAO,GAAG;AAAA,cACT,GAAG,QAAQ,OAAO;AAAA,cAClB;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAAA,MACA,CAAC,UAAU,OAAO;AAAA,IACpB;AAEA,QAAI,eAAe;AAAA,MACjB,CAAC,OAAgB,YAA6B;AAC5C,iBAAS;AAAA,UACP,GAAG;AAAA,UACH,CAAC,OAAO,GAAG;AAAA,YACT;AAAA,YACA,YAAY;AAAA,UACd;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MACA,CAAC,UAAU,OAAO;AAAA,IACpB;AAEA,QAAI,gBAAgB,CAAC;AACrB,QAAI,kBAAiC;AAErC,aAAS,CAAC,OAAO,KAAK,OAAO,QAAQ,WAAW,IAAI,GAAG;AACrD,UAAI,CAAC,QAAQ,OAA0B,EAAE,YAAY;AACnD,0BAAkB,OAAO,OAAO;AAEhC;AAAA,MACF;AAAA,IACF;AAEA,aAAS,CAAC,SAAS,KAAK,KAAK,OAAO,QAAQ,WAAW,IAAI,GAAG;AAC5D,UAAI,QAAQ,OAA0B,EAAE,cAAc,YAAY,iBAAiB;AACjF,sBAAc;AAAA,UACZ;AAAA,YAAC;AAAA;AAAA,cAEC,WAAW,cAAc,WAAW,IAAI,IAAI;AAAA,cAC5C,OAAO,YAAY;AAAA,cACnB,YAAY,QAAQ,OAA0B,EAAE;AAAA,cAChD,QAAQ;AAAA,cACR;AAAA,cACA;AAAA,cACA,OAAO,QAAQ,OAA0B,EAAE;AAAA,cAC3C,UAAU;AAAA,cACV,YAAY;AAAA;AAAA,YATP;AAAA,UAUP;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WACE,oBAAC,OAAK,GAAI,UAAuB,eAAc,UAC5C,yBACH;AAAA,EAEJ;AAEA,SAAO,OAAO,OAAO,MAAM,EAAC,QAAQ,WAAU,CAAC;AACjD;",
4
+ "sourcesContent": ["import {Box, type BoxProps} from 'ink';\nimport {useCallback} from 'react';\n\nimport {type Form} from './Form.js';\nimport {type FormConfig} from './FormConfig.js';\nimport {type FormProps} from './FormProps.js';\nimport {FormRow} from './FormRow.js';\n\n/**\n * Creates form component that contains individual rows with inputs based on the provided config.\n *\n * @param formConfig Form configuration.\n * @returns Form component.\n */\nexport function createForm<C extends FormConfig>(formConfig: C): Form<C> {\n let Form = ({\n rows,\n values: results,\n onChange,\n onComplete: onFinish,\n ...boxProps\n }: FormProps<C>) => {\n let handleChange = useCallback(\n (value: unknown, rowName: keyof C['rows']) => {\n if (onChange) {\n onChange({\n ...results,\n [rowName]: {\n ...results[rowName],\n value,\n },\n });\n }\n },\n [onChange, results],\n );\n\n let handleFinish = useCallback(\n (value: unknown, rowName: keyof C['rows']) => {\n onFinish({\n ...results,\n [rowName]: {\n value,\n isComplete: true,\n },\n });\n },\n [onFinish, results],\n );\n\n let inputElements = [];\n let activeInputName: string | null = null;\n\n for (let [rowName] of Object.entries(formConfig.rows)) {\n if (!results[rowName as keyof C['rows']].isComplete) {\n activeInputName = String(rowName);\n\n break;\n }\n }\n\n for (let [rowName, input] of Object.entries(formConfig.rows)) {\n if (results[rowName as keyof C['rows']].isComplete || rowName === activeInputName) {\n inputElements.push(\n <FormRow\n key={rowName}\n config={input}\n focus={rowName === activeInputName}\n isComplete={results[rowName as keyof C['rows']].isComplete}\n marginTop={inputElements.length === 0 ? 0 : 1}\n rowName={rowName}\n rows={rows}\n value={results[rowName as keyof C['rows']].value}\n onChange={handleChange}\n onComplete={handleFinish}\n />,\n );\n }\n }\n\n return (\n <Box {...(boxProps as BoxProps)} flexDirection=\"column\">\n {inputElements}\n </Box>\n );\n };\n\n return Object.assign(Form, {config: formConfig});\n}\n"],
5
+ "mappings": ";AAgEU;AAhEV,SAAQ,WAAyB;AACjC,SAAQ,mBAAkB;AAK1B,SAAQ,eAAc;AAQf,gBAAS,WAAiC,YAAwB;AACvE,MAAI,OAAO,CAAC;AAAA,IACV;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA,YAAY;AAAA,IACZ,GAAG;AAAA,EACL,MAAoB;AAClB,QAAI,eAAe;AAAA,MACjB,CAAC,OAAgB,YAA6B;AAC5C,YAAI,UAAU;AACZ,mBAAS;AAAA,YACP,GAAG;AAAA,YACH,CAAC,OAAO,GAAG;AAAA,cACT,GAAG,QAAQ,OAAO;AAAA,cAClB;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAAA,MACA,CAAC,UAAU,OAAO;AAAA,IACpB;AAEA,QAAI,eAAe;AAAA,MACjB,CAAC,OAAgB,YAA6B;AAC5C,iBAAS;AAAA,UACP,GAAG;AAAA,UACH,CAAC,OAAO,GAAG;AAAA,YACT;AAAA,YACA,YAAY;AAAA,UACd;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MACA,CAAC,UAAU,OAAO;AAAA,IACpB;AAEA,QAAI,gBAAgB,CAAC;AACrB,QAAI,kBAAiC;AAErC,aAAS,CAAC,OAAO,KAAK,OAAO,QAAQ,WAAW,IAAI,GAAG;AACrD,UAAI,CAAC,QAAQ,OAA0B,EAAE,YAAY;AACnD,0BAAkB,OAAO,OAAO;AAEhC;AAAA,MACF;AAAA,IACF;AAEA,aAAS,CAAC,SAAS,KAAK,KAAK,OAAO,QAAQ,WAAW,IAAI,GAAG;AAC5D,UAAI,QAAQ,OAA0B,EAAE,cAAc,YAAY,iBAAiB;AACjF,sBAAc;AAAA,UACZ;AAAA,YAAC;AAAA;AAAA,cAEC,QAAQ;AAAA,cACR,OAAO,YAAY;AAAA,cACnB,YAAY,QAAQ,OAA0B,EAAE;AAAA,cAChD,WAAW,cAAc,WAAW,IAAI,IAAI;AAAA,cAC5C;AAAA,cACA;AAAA,cACA,OAAO,QAAQ,OAA0B,EAAE;AAAA,cAC3C,UAAU;AAAA,cACV,YAAY;AAAA;AAAA,YATP;AAAA,UAUP;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WACE,oBAAC,OAAK,GAAI,UAAuB,eAAc,UAC5C,yBACH;AAAA,EAEJ;AAEA,SAAO,OAAO,OAAO,MAAM,EAAC,QAAQ,WAAU,CAAC;AACjD;",
6
6
  "names": []
7
7
  }
@@ -1,13 +1,13 @@
1
1
  export * from './form/createForm.js';
2
- export * from './form/Form.js';
3
- export * from './form/FormConfig.js';
4
- export * from './form/FormProps.js';
5
- export * from './form/FormResult.js';
2
+ export type * from './form/Form.js';
3
+ export type * from './form/FormConfig.js';
4
+ export type * from './form/FormProps.js';
5
+ export type * from './form/FormResult.js';
6
6
  export * from './form/FormRow.js';
7
- export * from './form/FormRowConfig.js';
8
- export * from './form/FormRowsConfig.js';
9
- export * from './form/FormValue.js';
10
- export * from './form/FormValues.js';
7
+ export type * from './form/FormRowConfig.js';
8
+ export type * from './form/FormRowsConfig.js';
9
+ export type * from './form/FormValue.js';
10
+ export type * from './form/FormValues.js';
11
11
  export * from './form/SelectInput.js';
12
- export * from './form/SelectInputItem.js';
12
+ export type * from './form/SelectInputItem.js';
13
13
  export * from './form/TextInput.js';
package/build/ui/form.js CHANGED
@@ -1,15 +1,6 @@
1
1
  "use strict";
2
2
  export * from "./form/createForm.js";
3
- export * from "./form/Form.js";
4
- export * from "./form/FormConfig.js";
5
- export * from "./form/FormProps.js";
6
- export * from "./form/FormResult.js";
7
3
  export * from "./form/FormRow.js";
8
- export * from "./form/FormRowConfig.js";
9
- export * from "./form/FormRowsConfig.js";
10
- export * from "./form/FormValue.js";
11
- export * from "./form/FormValues.js";
12
4
  export * from "./form/SelectInput.js";
13
- export * from "./form/SelectInputItem.js";
14
5
  export * from "./form/TextInput.js";
15
6
  //# sourceMappingURL=form.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../source/ui/form.ts"],
4
- "sourcesContent": ["export * from './form/createForm.js';\nexport * from './form/Form.js';\nexport * from './form/FormConfig.js';\nexport * from './form/FormProps.js';\nexport * from './form/FormResult.js';\nexport * from './form/FormRow.js';\nexport * from './form/FormRowConfig.js';\nexport * from './form/FormRowsConfig.js';\nexport * from './form/FormValue.js';\nexport * from './form/FormValues.js';\nexport * from './form/SelectInput.js';\nexport * from './form/SelectInputItem.js';\nexport * from './form/TextInput.js';\n"],
5
- "mappings": ";AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
4
+ "sourcesContent": ["export * from './form/createForm.js';\nexport type * from './form/Form.js';\nexport type * from './form/FormConfig.js';\nexport type * from './form/FormProps.js';\nexport type * from './form/FormResult.js';\nexport * from './form/FormRow.js';\nexport type * from './form/FormRowConfig.js';\nexport type * from './form/FormRowsConfig.js';\nexport type * from './form/FormValue.js';\nexport type * from './form/FormValues.js';\nexport * from './form/SelectInput.js';\nexport type * from './form/SelectInputItem.js';\nexport * from './form/TextInput.js';\n"],
5
+ "mappings": ";AAAA,cAAc;AAKd,cAAc;AAKd,cAAc;AAEd,cAAc;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../source/ui/getErrorDetail.ts"],
4
- "sourcesContent": ["import {ParsingError, ValidationError} 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"],
5
- "mappings": ";AAAA,SAAQ,cAAc,uBAAsB;AAC5C,SAAQ,0BAAyB;AACjC,SAAQ,gBAAe;AAOhB,gBAAS,eAAe,OAA6B;AAE1D,MAAI,iBAAiB,cAAc;AACjC,YAAQ,MAAM,MAAM;AAAA,MAClB,SAAS;AACP,eAAO;AAAA,UACL,OAAO;AAAA,UACP,aAAa,MAAM;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,iBAAiB,iBAAiB;AACpC,YAAQ,MAAM,MAAM;AAAA,MAClB,SAAS;AACP,eAAO;AAAA,UACL,OAAO;AAAA,UACP,aAAa,MAAM;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,iBAAiB,gBAAgB;AACnC,QAAI,cAA2B;AAAA,MAC7B,OAAO;AAAA,MACP,aAAa,MAAM;AAAA,IACrB;AAEA,QAAI,MAAM,OAAO;AACf,kBAAY,QAAQ,MAAM;AAAA,IAC5B;AAEA,WAAO;AAAA,EACT;AAEA,MAAI,iBAAiB,UAAU;AAC7B,QAAI,cAA2B;AAAA,MAC7B,OAAO;AAAA,MACP,aAAa,mBAAmB,MAAM,MAAM,EAAE,KAAK,IAAI;AAAA,IACzD;AAEA,WAAO;AAAA,EACT;AAEA,MAAI,iBAAiB,OAAO;AAC1B,QAAI,cAA2B;AAAA,MAC7B,OAAO;AAAA,MACP,aAAa,MAAM;AAAA,IACrB;AAEA,QAAI,MAAM,OAAO;AACf,kBAAY,QAAQ,MAAM;AAAA,IAC5B;AAEA,QAAI,MAAM,iBAAiB,OAAO;AAChC,kBAAY,QAAQ;AAAA,QAClB,aAAa,MAAM,MAAM;AAAA,MAC3B;AAEA,UAAI,MAAM,MAAM,OAAO;AACrB,oBAAY,MAAM,QAAQ,MAAM,MAAM;AAAA,MACxC;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,OAAO;AAAA,EACT;AACF;",
4
+ "sourcesContent": ["import {ParsingError, ValidationError} 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 // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- remove this when the TODO comment above is resolved\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 // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- remove this when the TODO comment above is resolved\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"],
5
+ "mappings": ";AAAA,SAAQ,cAAc,uBAAsB;AAC5C,SAAQ,0BAAyB;AACjC,SAAQ,gBAAe;AAOhB,gBAAS,eAAe,OAA6B;AAE1D,MAAI,iBAAiB,cAAc;AAEjC,YAAQ,MAAM,MAAM;AAAA,MAClB,SAAS;AACP,eAAO;AAAA,UACL,OAAO;AAAA,UACP,aAAa,MAAM;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,iBAAiB,iBAAiB;AAEpC,YAAQ,MAAM,MAAM;AAAA,MAClB,SAAS;AACP,eAAO;AAAA,UACL,OAAO;AAAA,UACP,aAAa,MAAM;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,iBAAiB,gBAAgB;AACnC,QAAI,cAA2B;AAAA,MAC7B,OAAO;AAAA,MACP,aAAa,MAAM;AAAA,IACrB;AAEA,QAAI,MAAM,OAAO;AACf,kBAAY,QAAQ,MAAM;AAAA,IAC5B;AAEA,WAAO;AAAA,EACT;AAEA,MAAI,iBAAiB,UAAU;AAC7B,QAAI,cAA2B;AAAA,MAC7B,OAAO;AAAA,MACP,aAAa,mBAAmB,MAAM,MAAM,EAAE,KAAK,IAAI;AAAA,IACzD;AAEA,WAAO;AAAA,EACT;AAEA,MAAI,iBAAiB,OAAO;AAC1B,QAAI,cAA2B;AAAA,MAC7B,OAAO;AAAA,MACP,aAAa,MAAM;AAAA,IACrB;AAEA,QAAI,MAAM,OAAO;AACf,kBAAY,QAAQ,MAAM;AAAA,IAC5B;AAEA,QAAI,MAAM,iBAAiB,OAAO;AAChC,kBAAY,QAAQ;AAAA,QAClB,aAAa,MAAM,MAAM;AAAA,MAC3B;AAEA,UAAI,MAAM,MAAM,OAAO;AACrB,oBAAY,MAAM,QAAQ,MAAM,MAAM;AAAA,MACxC;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,OAAO;AAAA,EACT;AACF;",
6
6
  "names": []
7
7
  }
@@ -18,14 +18,14 @@ export const Wrapper = ({ program, children }) => {
18
18
  /* @__PURE__ */ jsxs(
19
19
  Box,
20
20
  {
21
- flexDirection: "column",
22
21
  borderColor: notice,
23
22
  borderStyle: "round",
23
+ flexDirection: "column",
24
24
  margin: 1,
25
- paddingTop: 1,
26
- paddingRight: 4,
27
25
  paddingBottom: 1,
28
26
  paddingLeft: 4,
27
+ paddingRight: 4,
28
+ paddingTop: 1,
29
29
  children: [
30
30
  /* @__PURE__ */ jsxs(Text, { children: [
31
31
  "New version ",
@@ -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 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 flexDirection=\"column\"\n borderColor={notice}\n borderStyle=\"round\"\n margin={1}\n paddingTop={1}\n paddingRight={4}\n paddingBottom={1}\n paddingLeft={4}\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,eAAc;AAAA,UACd,aAAa;AAAA,UACb,aAAY;AAAA,UACZ,QAAQ;AAAA,UACR,YAAY;AAAA,UACZ,cAAc;AAAA,UACd,eAAe;AAAA,UACf,aAAa;AAAA,UAEb;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,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 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;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,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 // TODO: remove when this is fixed: https://github.com/facebook/react/issues/31544\n // eslint-disable-next-line react-compiler/react-compiler -- false positive\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;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;AAGlB,cAAQ,WAAW;AAEnB,mBAAa,KAAK;AAClB,cAAQ,KAAc;AAAA,IACxB;AAAA,IACA,CAAC,SAAS,YAAY;AAAA,EACxB;AAEA,SAAO,EAAC,SAAS,KAAI;AACvB;",
6
6
  "names": []
7
7
  }
package/build/ui.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export * as colors from './ui/colors.js';
2
- export * from './ui/ErrorDetail.js';
2
+ export type * from './ui/ErrorDetail.js';
3
3
  export * from './ui/Failure.js';
4
4
  export * from './ui/form.js';
5
5
  export * from './ui/getErrorDetail.js';
package/build/ui.js CHANGED
@@ -1,6 +1,5 @@
1
1
  "use strict";
2
2
  export * as colors from "./ui/colors.js";
3
- export * from "./ui/ErrorDetail.js";
4
3
  export * from "./ui/Failure.js";
5
4
  export * from "./ui/form.js";
6
5
  export * from "./ui/getErrorDetail.js";
package/build/ui.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../source/ui.ts"],
4
- "sourcesContent": ["export * as colors from './ui/colors.js';\nexport * from './ui/ErrorDetail.js';\nexport * from './ui/Failure.js';\nexport * from './ui/form.js';\nexport * from './ui/getErrorDetail.js';\nexport * from './ui/Header.js';\nexport * from './ui/Help.js';\nexport * as icons from './ui/icons.js';\nexport * from './ui/Spinner.js';\nexport * from './ui/useProgram.js';\n"],
5
- "mappings": ";AAAA,YAAY,YAAY;AACxB,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,YAAY,WAAW;AACvB,cAAc;AACd,cAAc;",
4
+ "sourcesContent": ["export * as colors from './ui/colors.js';\nexport type * from './ui/ErrorDetail.js';\nexport * from './ui/Failure.js';\nexport * from './ui/form.js';\nexport * from './ui/getErrorDetail.js';\nexport * from './ui/Header.js';\nexport * from './ui/Help.js';\nexport * as icons from './ui/icons.js';\nexport * from './ui/Spinner.js';\nexport * from './ui/useProgram.js';\n"],
5
+ "mappings": ";AAAA,YAAY,YAAY;AAExB,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,YAAY,WAAW;AACvB,cAAc;AACd,cAAc;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jakubmazanec/cli",
3
- "version": "0.3.4",
3
+ "version": "0.3.5-next.0f7252e",
4
4
  "description": "TypeScript-first library for building CLIs.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -27,10 +27,10 @@
27
27
  "typecheck": "tsc --project tsconfig.typecheck.json"
28
28
  },
29
29
  "dependencies": {
30
- "@jakubmazanec/args": "^2.0.0",
31
- "@jakubmazanec/error": "^3.0.0",
32
- "@jakubmazanec/ts-utils": "^3.0.0",
33
- "@jakubmazanec/zod-utils": "^2.0.0",
30
+ "@jakubmazanec/args": "2.0.5-next.0f7252e",
31
+ "@jakubmazanec/error": "3.0.5-next.0f7252e",
32
+ "@jakubmazanec/ts-utils": "3.0.5-next.0f7252e",
33
+ "@jakubmazanec/zod-utils": "2.0.5-next.0f7252e",
34
34
  "chalk": "^5.3.0",
35
35
  "fs-extra": "^11.2.0",
36
36
  "latest-version": "^9.0.0",
@@ -39,27 +39,27 @@
39
39
  "zod": "^3.23.8"
40
40
  },
41
41
  "devDependencies": {
42
- "@jakubmazanec/eslint-config": "^3.2.0",
42
+ "@jakubmazanec/eslint-config": "4.0.0-next.0f7252e",
43
43
  "@types/fs-extra": "^11.0.4",
44
44
  "@types/lodash": "^4.17.13",
45
45
  "@types/node": "^22.9.0",
46
- "@types/react": "^18.2.63",
47
- "@vitest/coverage-v8": "^2.1.4",
46
+ "@types/react": "^18.3.12",
47
+ "@vitest/coverage-v8": "^2.1.5",
48
48
  "concurrently": "^9.1.0",
49
49
  "cross-env": "^7.0.3",
50
50
  "del-cli": "^6.0.0",
51
51
  "esbuild": "^0.24.0",
52
- "eslint": "^8.56.0",
52
+ "eslint": "^9.15.0",
53
53
  "ink": "^5.0.1",
54
54
  "ink-testing-library": "^4.0.0",
55
55
  "lodash": "^4.17.21",
56
56
  "prettier": "^3.3.3",
57
57
  "prettier-plugin-packagejson": "^2.5.3",
58
- "react": "^18.2.0",
58
+ "react": "^18.3.1",
59
59
  "typedoc": "^0.26.11",
60
60
  "typedoc-plugin-markdown": "^4.2.10",
61
61
  "typescript": "^5.6.3",
62
- "vitest": "^2.1.4"
62
+ "vitest": "^2.1.5"
63
63
  },
64
64
  "peerDependencies": {
65
65
  "ink": "5.x",
@@ -2,7 +2,7 @@
2
2
  import {type Argv, type OptionsConfig, type ParametersConfig} from '@jakubmazanec/args';
3
3
  import fs from 'fs-extra';
4
4
  import fetchLatestVersion from 'latest-version';
5
- import path from 'path';
5
+ import path from 'node:path';
6
6
  import {type ComponentType} from 'react';
7
7
  import {type FallbackProps} from 'react-error-boundary';
8
8
 
package/source/program.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  export * from './program/Command.js';
2
- export * from './program/CommandAction.js';
3
- export * from './program/CommandArguments.js';
4
- export * from './program/CommandOptions.js';
2
+ export type * from './program/CommandAction.js';
3
+ export type * from './program/CommandArguments.js';
4
+ export type * from './program/CommandOptions.js';
5
5
  export * from './program/getProgramDetail.js';
6
6
  export * from './program/Program.js';
7
- export * from './program/ProgramCreateOptions.js';
8
- export * from './program/ProgramDetail.js';
7
+ export type * from './program/ProgramCreateOptions.js';
8
+ export type * from './program/ProgramDetail.js';
9
9
  export * from './program/ProgramError.js';
10
- export * from './program/ProgramOptions.js';
11
- export * from './program/ProgramStreams.js';
10
+ export type * from './program/ProgramOptions.js';
11
+ export type * from './program/ProgramStreams.js';
@@ -36,19 +36,19 @@ export function Failure({error, errorDetail, ...boxProps}: FailureProps) {
36
36
  : null}
37
37
 
38
38
  {stack ?
39
- <Box flexDirection="column" marginTop={1} marginLeft={2}>
39
+ <Box flexDirection="column" marginLeft={2} marginTop={1}>
40
40
  <Text color={colors.muted}>{stack}</Text>
41
41
  </Box>
42
42
  : null}
43
43
 
44
44
  {cause ?
45
45
  <>
46
- <Box flexDirection="column" marginTop={1} marginLeft={2}>
46
+ <Box flexDirection="column" marginLeft={2} marginTop={1}>
47
47
  <Text color={colors.muted}>{cause.description}</Text>
48
48
  </Box>
49
49
 
50
50
  {cause.stack ?
51
- <Box flexDirection="column" marginTop={1} marginLeft={2}>
51
+ <Box flexDirection="column" marginLeft={2} marginTop={1}>
52
52
  <Text color={colors.muted}>{cause.stack}</Text>
53
53
  </Box>
54
54
  : null}
@@ -56,7 +56,7 @@ export function Help({program, ...boxProps}: HelpProps) {
56
56
  }
57
57
 
58
58
  return (
59
- <Box key={command.name} marginLeft={2} flexDirection="column">
59
+ <Box key={command.name} flexDirection="column" marginLeft={2}>
60
60
  <Text>{line}</Text>
61
61
  </Box>
62
62
  );
@@ -74,26 +74,13 @@ export function FormRow<C extends FormConfig>({
74
74
  );
75
75
 
76
76
  switch (config.type) {
77
- case 'text': {
78
- return (
79
- <TextInput
80
- key={String(rowName)}
81
- label={config.label ?? ''}
82
- validate={config.validate}
83
- value={value as string}
84
- focus={focus}
85
- isComplete={isComplete}
86
- onChange={handleChange}
87
- onSubmit={handleFinish}
88
- {...boxProps}
89
- />
90
- );
77
+ case 'confirm': {
78
+ return null;
91
79
  }
92
80
  case 'select': {
93
81
  return (
94
82
  <SelectInput
95
83
  key={String(rowName)}
96
- label={config.label ?? ''}
97
84
  items={
98
85
  rows ?
99
86
  (
@@ -107,12 +94,30 @@ export function FormRow<C extends FormConfig>({
107
94
  }
108
95
  focus={focus}
109
96
  isComplete={isComplete}
97
+ label={config.label ?? ''}
110
98
  onSelect={handleSelectFinish}
111
99
  {...boxProps}
112
100
  />
113
101
  );
114
102
  }
103
+ case 'text': {
104
+ return (
105
+ <TextInput
106
+ key={String(rowName)}
107
+ focus={focus}
108
+ isComplete={isComplete}
109
+ label={config.label ?? ''}
110
+ validate={config.validate}
111
+ value={value as string}
112
+ onChange={handleChange}
113
+ onSubmit={handleFinish}
114
+ {...boxProps}
115
+ />
116
+ );
117
+ }
115
118
  default: {
119
+ config satisfies never;
120
+
116
121
  return null;
117
122
  }
118
123
  }
@@ -1,5 +1,3 @@
1
- // TODO: resolve
2
- /* eslint-disable complexity -- TODO */
3
1
  import chalk from 'chalk';
4
2
  import {Box, type BoxProps, Text, useInput} from 'ink';
5
3
  import {useEffect, useState} from 'react';
@@ -158,7 +156,7 @@ export function TextInput({
158
156
  if (state.cursorOffset > 0) {
159
157
  nextValue =
160
158
  originalValue.slice(0, state.cursorOffset - 1) +
161
- originalValue.slice(state.cursorOffset, originalValue.length);
159
+ originalValue.slice(state.cursorOffset);
162
160
 
163
161
  nextCursorOffset -= 1;
164
162
  }
@@ -166,7 +164,7 @@ export function TextInput({
166
164
  nextValue =
167
165
  originalValue.slice(0, state.cursorOffset) +
168
166
  input +
169
- originalValue.slice(state.cursorOffset, originalValue.length);
167
+ originalValue.slice(state.cursorOffset);
170
168
 
171
169
  nextCursorOffset += input.length;
172
170
 
@@ -64,12 +64,12 @@ export function createForm<C extends FormConfig>(formConfig: C): Form<C> {
64
64
  inputElements.push(
65
65
  <FormRow
66
66
  key={rowName}
67
- marginTop={inputElements.length === 0 ? 0 : 1}
67
+ config={input}
68
68
  focus={rowName === activeInputName}
69
69
  isComplete={results[rowName as keyof C['rows']].isComplete}
70
- config={input}
71
- rows={rows}
70
+ marginTop={inputElements.length === 0 ? 0 : 1}
72
71
  rowName={rowName}
72
+ rows={rows}
73
73
  value={results[rowName as keyof C['rows']].value}
74
74
  onChange={handleChange}
75
75
  onComplete={handleFinish}
package/source/ui/form.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  export * from './form/createForm.js';
2
- export * from './form/Form.js';
3
- export * from './form/FormConfig.js';
4
- export * from './form/FormProps.js';
5
- export * from './form/FormResult.js';
2
+ export type * from './form/Form.js';
3
+ export type * from './form/FormConfig.js';
4
+ export type * from './form/FormProps.js';
5
+ export type * from './form/FormResult.js';
6
6
  export * from './form/FormRow.js';
7
- export * from './form/FormRowConfig.js';
8
- export * from './form/FormRowsConfig.js';
9
- export * from './form/FormValue.js';
10
- export * from './form/FormValues.js';
7
+ export type * from './form/FormRowConfig.js';
8
+ export type * from './form/FormRowsConfig.js';
9
+ export type * from './form/FormValue.js';
10
+ export type * from './form/FormValues.js';
11
11
  export * from './form/SelectInput.js';
12
- export * from './form/SelectInputItem.js';
12
+ export type * from './form/SelectInputItem.js';
13
13
  export * from './form/TextInput.js';
@@ -10,6 +10,7 @@ import {type ErrorDetail} from './ErrorDetail.js';
10
10
  export function getErrorDetail(error: unknown): ErrorDetail {
11
11
  // TODO: add all codes
12
12
  if (error instanceof ParsingError) {
13
+ // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- remove this when the TODO comment above is resolved
13
14
  switch (error.code) {
14
15
  default: {
15
16
  return {
@@ -22,6 +23,7 @@ export function getErrorDetail(error: unknown): ErrorDetail {
22
23
 
23
24
  // TODO: add all codes
24
25
  if (error instanceof ValidationError) {
26
+ // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- remove this when the TODO comment above is resolved
25
27
  switch (error.code) {
26
28
  default: {
27
29
  return {
@@ -31,14 +31,14 @@ export const Wrapper: FC<PropsWithChildren<WrapperProps>> = ({program, children}
31
31
  {program.latestVersion && program.latestVersion !== program.version ?
32
32
  <Box>
33
33
  <Box
34
- flexDirection="column"
35
34
  borderColor={notice}
36
35
  borderStyle="round"
36
+ flexDirection="column"
37
37
  margin={1}
38
- paddingTop={1}
39
- paddingRight={4}
40
38
  paddingBottom={1}
41
39
  paddingLeft={4}
40
+ paddingRight={4}
41
+ paddingTop={1}
42
42
  >
43
43
  <Text>
44
44
  New version <Text color={highlighted}>{program.latestVersion}</Text> is available!
@@ -14,6 +14,8 @@ export function useProgram() {
14
14
 
15
15
  let exit = useCallback(
16
16
  (error: unknown) => {
17
+ // TODO: remove when this is fixed: https://github.com/facebook/react/issues/31544
18
+ // eslint-disable-next-line react-compiler/react-compiler -- false positive
17
19
  process.exitCode = 1;
18
20
 
19
21
  showBoundary(error);
package/source/ui.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export * as colors from './ui/colors.js';
2
- export * from './ui/ErrorDetail.js';
2
+ export type * from './ui/ErrorDetail.js';
3
3
  export * from './ui/Failure.js';
4
4
  export * from './ui/form.js';
5
5
  export * from './ui/getErrorDetail.js';