@pristine-ts/cli 2.0.16 → 2.0.18

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 (142) hide show
  1. package/dist/lib/cjs/bin.js +0 -0
  2. package/dist/lib/cjs/cli.configuration-keys.js +6 -0
  3. package/dist/lib/cjs/cli.configuration-keys.js.map +1 -1
  4. package/dist/lib/cjs/cli.module.js +13 -0
  5. package/dist/lib/cjs/cli.module.js.map +1 -1
  6. package/dist/lib/cjs/errors/cli-error-code.enum.js +10 -0
  7. package/dist/lib/cjs/errors/cli-error-code.enum.js.map +1 -1
  8. package/dist/lib/cjs/interfaces/command-parameter-choice.interface.js +3 -0
  9. package/dist/lib/cjs/interfaces/command-parameter-choice.interface.js.map +1 -0
  10. package/dist/lib/cjs/interfaces/command-parameter-choices-context.interface.js +3 -0
  11. package/dist/lib/cjs/interfaces/command-parameter-choices-context.interface.js.map +1 -0
  12. package/dist/lib/cjs/interfaces/command-parameter-choices-provider.interface.js +3 -0
  13. package/dist/lib/cjs/interfaces/command-parameter-choices-provider.interface.js.map +1 -0
  14. package/dist/lib/cjs/interfaces/interfaces.js +3 -0
  15. package/dist/lib/cjs/interfaces/interfaces.js.map +1 -1
  16. package/dist/lib/cjs/reporters/cli-error.reporter.js +11 -3
  17. package/dist/lib/cjs/reporters/cli-error.reporter.js.map +1 -1
  18. package/dist/lib/cjs/services/command-argument-error-formatter.js +146 -0
  19. package/dist/lib/cjs/services/command-argument-error-formatter.js.map +1 -0
  20. package/dist/lib/cjs/services/command-argument-resolver.js +1 -1
  21. package/dist/lib/cjs/services/command-argument-resolver.js.map +1 -1
  22. package/dist/lib/cjs/services/command-options-resolver.js +30 -37
  23. package/dist/lib/cjs/services/command-options-resolver.js.map +1 -1
  24. package/dist/lib/cjs/services/command-parameter-prompter.js +118 -38
  25. package/dist/lib/cjs/services/command-parameter-prompter.js.map +1 -1
  26. package/dist/lib/cjs/services/command-usage-renderer.js +81 -0
  27. package/dist/lib/cjs/services/command-usage-renderer.js.map +1 -0
  28. package/dist/lib/cjs/services/program-name-resolver.js +98 -0
  29. package/dist/lib/cjs/services/program-name-resolver.js.map +1 -0
  30. package/dist/lib/cjs/services/services.js +3 -0
  31. package/dist/lib/cjs/services/services.js.map +1 -1
  32. package/dist/lib/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  33. package/dist/lib/cjs/types/command-parameter-choices-list.type.js +3 -0
  34. package/dist/lib/cjs/types/command-parameter-choices-list.type.js.map +1 -0
  35. package/dist/lib/cjs/types/command-parameter-choices-resolver.type.js +3 -0
  36. package/dist/lib/cjs/types/command-parameter-choices-resolver.type.js.map +1 -0
  37. package/dist/lib/cjs/types/command-parameter-choices.type.js +3 -0
  38. package/dist/lib/cjs/types/command-parameter-choices.type.js.map +1 -0
  39. package/dist/lib/cjs/types/types.js +3 -0
  40. package/dist/lib/cjs/types/types.js.map +1 -1
  41. package/dist/lib/esm/cli.configuration-keys.js +6 -0
  42. package/dist/lib/esm/cli.configuration-keys.js.map +1 -1
  43. package/dist/lib/esm/cli.module.js +13 -0
  44. package/dist/lib/esm/cli.module.js.map +1 -1
  45. package/dist/lib/esm/errors/cli-error-code.enum.js +10 -0
  46. package/dist/lib/esm/errors/cli-error-code.enum.js.map +1 -1
  47. package/dist/lib/esm/interfaces/command-parameter-choice.interface.js +2 -0
  48. package/dist/lib/esm/interfaces/command-parameter-choice.interface.js.map +1 -0
  49. package/dist/lib/esm/interfaces/command-parameter-choices-context.interface.js +2 -0
  50. package/dist/lib/esm/interfaces/command-parameter-choices-context.interface.js.map +1 -0
  51. package/dist/lib/esm/interfaces/command-parameter-choices-provider.interface.js +2 -0
  52. package/dist/lib/esm/interfaces/command-parameter-choices-provider.interface.js.map +1 -0
  53. package/dist/lib/esm/interfaces/interfaces.js +3 -0
  54. package/dist/lib/esm/interfaces/interfaces.js.map +1 -1
  55. package/dist/lib/esm/reporters/cli-error.reporter.js +11 -3
  56. package/dist/lib/esm/reporters/cli-error.reporter.js.map +1 -1
  57. package/dist/lib/esm/services/command-argument-error-formatter.js +143 -0
  58. package/dist/lib/esm/services/command-argument-error-formatter.js.map +1 -0
  59. package/dist/lib/esm/services/command-argument-resolver.js +1 -1
  60. package/dist/lib/esm/services/command-argument-resolver.js.map +1 -1
  61. package/dist/lib/esm/services/command-options-resolver.js +31 -38
  62. package/dist/lib/esm/services/command-options-resolver.js.map +1 -1
  63. package/dist/lib/esm/services/command-parameter-prompter.js +120 -40
  64. package/dist/lib/esm/services/command-parameter-prompter.js.map +1 -1
  65. package/dist/lib/esm/services/command-usage-renderer.js +78 -0
  66. package/dist/lib/esm/services/command-usage-renderer.js.map +1 -0
  67. package/dist/lib/esm/services/program-name-resolver.js +62 -0
  68. package/dist/lib/esm/services/program-name-resolver.js.map +1 -0
  69. package/dist/lib/esm/services/services.js +3 -0
  70. package/dist/lib/esm/services/services.js.map +1 -1
  71. package/dist/lib/esm/tsconfig.tsbuildinfo +1 -1
  72. package/dist/lib/esm/types/command-parameter-choices-list.type.js +2 -0
  73. package/dist/lib/esm/types/command-parameter-choices-list.type.js.map +1 -0
  74. package/dist/lib/esm/types/command-parameter-choices-resolver.type.js +2 -0
  75. package/dist/lib/esm/types/command-parameter-choices-resolver.type.js.map +1 -0
  76. package/dist/lib/esm/types/command-parameter-choices.type.js +2 -0
  77. package/dist/lib/esm/types/command-parameter-choices.type.js.map +1 -0
  78. package/dist/lib/esm/types/types.js +3 -0
  79. package/dist/lib/esm/types/types.js.map +1 -1
  80. package/dist/types/cli.configuration-keys.d.ts +7 -0
  81. package/dist/types/errors/cli-error-code.enum.d.ts +10 -0
  82. package/dist/types/interfaces/command-parameter-choice.interface.d.ts +14 -0
  83. package/dist/types/interfaces/command-parameter-choices-context.interface.d.ts +17 -0
  84. package/dist/types/interfaces/command-parameter-choices-provider.interface.d.ts +20 -0
  85. package/dist/types/interfaces/interfaces.d.ts +3 -0
  86. package/dist/types/options/command-parameter.options.d.ts +30 -0
  87. package/dist/types/services/command-argument-error-formatter.d.ts +64 -0
  88. package/dist/types/services/command-options-resolver.d.ts +23 -13
  89. package/dist/types/services/command-parameter-prompter.d.ts +60 -31
  90. package/dist/types/services/command-usage-renderer.d.ts +35 -0
  91. package/dist/types/services/program-name-resolver.d.ts +21 -0
  92. package/dist/types/services/services.d.ts +3 -0
  93. package/dist/types/types/command-parameter-choices-list.type.d.ts +6 -0
  94. package/dist/types/types/command-parameter-choices-resolver.type.d.ts +9 -0
  95. package/dist/types/types/command-parameter-choices.type.d.ts +19 -0
  96. package/dist/types/types/types.d.ts +3 -0
  97. package/package.json +12 -12
  98. package/dist/lib/cjs/bootstrap/app-module-cache.js +0 -71
  99. package/dist/lib/cjs/bootstrap/app-module-cache.js.map +0 -1
  100. package/dist/lib/cjs/bootstrap/app-module-discoverer.js +0 -119
  101. package/dist/lib/cjs/bootstrap/app-module-discoverer.js.map +0 -1
  102. package/dist/lib/cjs/bootstrap/app-module-discovery-candidate.js +0 -21
  103. package/dist/lib/cjs/bootstrap/app-module-discovery-candidate.js.map +0 -1
  104. package/dist/lib/cjs/bootstrap/app-module-discovery-reason.enum.js +0 -15
  105. package/dist/lib/cjs/bootstrap/app-module-discovery-reason.enum.js.map +0 -1
  106. package/dist/lib/cjs/bootstrap/app-module-prompt.js +0 -78
  107. package/dist/lib/cjs/bootstrap/app-module-prompt.js.map +0 -1
  108. package/dist/lib/cjs/commands/config-init.command.js +0 -133
  109. package/dist/lib/cjs/commands/config-init.command.js.map +0 -1
  110. package/dist/lib/cjs/enums/exit-code.enum.js +0 -9
  111. package/dist/lib/cjs/enums/exit-code.enum.js.map +0 -1
  112. package/dist/lib/cjs/managers/console.manager.js +0 -277
  113. package/dist/lib/cjs/managers/console.manager.js.map +0 -1
  114. package/dist/lib/cjs/managers/repl-session.js +0 -251
  115. package/dist/lib/cjs/managers/repl-session.js.map +0 -1
  116. package/dist/lib/esm/bootstrap/app-module-cache.js +0 -65
  117. package/dist/lib/esm/bootstrap/app-module-cache.js.map +0 -1
  118. package/dist/lib/esm/bootstrap/app-module-discoverer.js +0 -113
  119. package/dist/lib/esm/bootstrap/app-module-discoverer.js.map +0 -1
  120. package/dist/lib/esm/bootstrap/app-module-discovery-candidate.js +0 -17
  121. package/dist/lib/esm/bootstrap/app-module-discovery-candidate.js.map +0 -1
  122. package/dist/lib/esm/bootstrap/app-module-discovery-reason.enum.js +0 -12
  123. package/dist/lib/esm/bootstrap/app-module-discovery-reason.enum.js.map +0 -1
  124. package/dist/lib/esm/bootstrap/app-module-prompt.js +0 -75
  125. package/dist/lib/esm/bootstrap/app-module-prompt.js.map +0 -1
  126. package/dist/lib/esm/commands/config-init.command.js +0 -127
  127. package/dist/lib/esm/commands/config-init.command.js.map +0 -1
  128. package/dist/lib/esm/enums/exit-code.enum.js +0 -6
  129. package/dist/lib/esm/enums/exit-code.enum.js.map +0 -1
  130. package/dist/lib/esm/managers/console.manager.js +0 -241
  131. package/dist/lib/esm/managers/console.manager.js.map +0 -1
  132. package/dist/lib/esm/managers/repl-session.js +0 -215
  133. package/dist/lib/esm/managers/repl-session.js.map +0 -1
  134. package/dist/types/bootstrap/app-module-cache.d.ts +0 -15
  135. package/dist/types/bootstrap/app-module-discoverer.d.ts +0 -30
  136. package/dist/types/bootstrap/app-module-discovery-candidate.d.ts +0 -18
  137. package/dist/types/bootstrap/app-module-discovery-reason.enum.d.ts +0 -10
  138. package/dist/types/bootstrap/app-module-prompt.d.ts +0 -20
  139. package/dist/types/commands/config-init.command.d.ts +0 -18
  140. package/dist/types/enums/exit-code.enum.d.ts +0 -4
  141. package/dist/types/managers/console.manager.d.ts +0 -93
  142. package/dist/types/managers/repl-session.d.ts +0 -62
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=command-parameter-choices-list.type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-parameter-choices-list.type.js","sourceRoot":"","sources":["../../../../src/types/command-parameter-choices-list.type.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=command-parameter-choices-resolver.type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-parameter-choices-resolver.type.js","sourceRoot":"","sources":["../../../../src/types/command-parameter-choices-resolver.type.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=command-parameter-choices.type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-parameter-choices.type.js","sourceRoot":"","sources":["../../../../src/types/command-parameter-choices.type.ts"],"names":[],"mappings":""}
@@ -1,4 +1,7 @@
1
1
  export * from "./command-event.type";
2
2
  export * from "./command-event-response.type";
3
+ export * from "./command-parameter-choices-list.type";
4
+ export * from "./command-parameter-choices-resolver.type";
5
+ export * from "./command-parameter-choices.type";
3
6
  export * from "./start-repl-event-response.type";
4
7
  //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/types/types.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,kCAAkC,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/types/types.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uCAAuC,CAAC;AACtD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,kCAAkC,CAAC;AACjD,cAAc,kCAAkC,CAAC"}
@@ -17,6 +17,12 @@ export declare const CliConfigurationKeys: {
17
17
  * input is not an interactive terminal, regardless of this value.
18
18
  */
19
19
  readonly InteractiveParameters: "pristine.cli.interactiveParameters";
20
+ /**
21
+ * Explicit program name shown in generated `Usage:` lines (e.g. `myapp`). Optional: when unset,
22
+ * the CLI derives the name from `argv[1]`, falling back to `pristine`. Set it for launch shapes
23
+ * where `argv[1]` isn't the friendly name (e.g. `node dist/bin/cli.cjs`).
24
+ */
25
+ readonly BinName: "pristine.cli.binName";
20
26
  };
21
27
  /**
22
28
  * The expected runtime types for each configuration value defined by `@pristine-ts/cli`. The
@@ -25,6 +31,7 @@ export declare const CliConfigurationKeys: {
25
31
  */
26
32
  export interface CliConfigurationValueMap {
27
33
  "pristine.cli.interactiveParameters": boolean;
34
+ "pristine.cli.binName": string;
28
35
  }
29
36
  declare module "@pristine-ts/common" {
30
37
  interface PristineConfigurationValueMap extends CliConfigurationValueMap {
@@ -9,6 +9,16 @@ export declare enum CliErrorCode {
9
9
  CommandNotFound = "COMMAND_NOT_FOUND",
10
10
  ArgumentMappingFailed = "ARGUMENT_MAPPING_FAILED",
11
11
  ArgumentValidationFailed = "ARGUMENT_VALIDATION_FAILED",
12
+ /**
13
+ * A required command-line argument was missing. Reported with the command's `Usage:` synopsis
14
+ * (exit 64). Distinct from a value supplied but invalid (`InvalidArgument`).
15
+ */
16
+ MissingRequiredArgument = "MISSING_REQUIRED_ARGUMENT",
17
+ /**
18
+ * A supplied command-line argument failed validation. Reported as a clean
19
+ * `Invalid <flag> '<value>'. …` line (exit 64).
20
+ */
21
+ InvalidArgument = "INVALID_ARGUMENT",
12
22
  /**
13
23
  * Two `@commandParameter` properties on the same options class resolve to the same flag.
14
24
  * A programming error in the command's options definition, not bad user input.
@@ -0,0 +1,14 @@
1
+ /**
2
+ * A single selectable choice for a `@commandParameter` whose value comes from a fixed or
3
+ * runtime-resolved set. `name` is what the interactive menu shows; `value` is what gets bound
4
+ * to the parameter (and validated) when the choice is picked.
5
+ *
6
+ * A bare `string` is accepted anywhere a `CommandParameterChoice` is — it expands to
7
+ * `{name: value, value: value}`.
8
+ */
9
+ export interface CommandParameterChoice {
10
+ /** Human-readable label rendered in the selection menu. */
11
+ name: string;
12
+ /** Value bound to the parameter when this choice is selected. */
13
+ value: string;
14
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Passed to a dynamic choices resolver (a function or a
3
+ * `CommandParameterChoicesProviderInterface`) so it can compute the allowed values from the
4
+ * arguments resolved so far — e.g. list the tables of whichever `--database` was already
5
+ * answered.
6
+ */
7
+ export interface CommandParameterChoicesContext {
8
+ /**
9
+ * The arguments known so far: flags passed on the command line plus any values already
10
+ * answered interactively earlier in the same prompt pass. Keyed by property name.
11
+ */
12
+ args: Record<string, any>;
13
+ /** The options-class property whose choices are being resolved. */
14
+ propertyKey: string;
15
+ /** The effective CLI flag for that property (the `flag` override, or the property name). */
16
+ flag: string;
17
+ }
@@ -0,0 +1,20 @@
1
+ import { CommandParameterChoicesContext } from "./command-parameter-choices-context.interface";
2
+ import { CommandParameterChoicesList } from "../types/command-parameter-choices-list.type";
3
+ /**
4
+ * A dependency-injected provider of dynamic `@commandParameter` choices. Reference the
5
+ * provider *class* from `@commandParameter({choices: MyProvider})`; the CLI resolves it from
6
+ * the container at prompt time (so it can inject a `FileManager`, `HttpClient`, …) and calls
7
+ * `getChoices`. Use this form when choice resolution needs framework services; use a plain
8
+ * resolver function when it doesn't.
9
+ *
10
+ * The provider class must be registered with DI (`@injectable()`, and `@moduleScoped` to the
11
+ * consuming module as usual).
12
+ */
13
+ export interface CommandParameterChoicesProviderInterface {
14
+ /**
15
+ * Returns the allowed choices, optionally narrowed by the already-resolved arguments in
16
+ * `context`. May be async (the resolver awaits it). Returning an empty list disables the
17
+ * menu — the value then falls through to the normal free-text prompt + validation.
18
+ */
19
+ getChoices(context: CommandParameterChoicesContext): CommandParameterChoicesList | Promise<CommandParameterChoicesList>;
20
+ }
@@ -1,2 +1,5 @@
1
1
  export * from "./command.interface";
2
+ export * from "./command-parameter-choice.interface";
3
+ export * from "./command-parameter-choices-context.interface";
4
+ export * from "./command-parameter-choices-provider.interface";
2
5
  export * from "./terminal-key.interface";
@@ -1,3 +1,4 @@
1
+ import { CommandParameterChoices } from "../types/command-parameter-choices.type";
1
2
  /**
2
3
  * Options accepted by the `@commandParameter` decorator. Every field is optional: an empty
3
4
  * `@commandParameter()` is valid and simply marks the property as a known command-line
@@ -26,4 +27,33 @@ export interface CommandParameterOptions {
26
27
  * never trimmed or printed back in any re-ask/validation feedback.
27
28
  */
28
29
  sensitive?: boolean;
30
+ /**
31
+ * The set of allowed values for this parameter (single-select). When present and the value is
32
+ * asked for interactively, the CLI shows an arrow-key menu instead of a free-text prompt.
33
+ *
34
+ * Three shapes:
35
+ * - a **static** list — `["dev", "staging", "prod"]` or `[{name, value}, …]`;
36
+ * - a **resolver function** — `(ctx) => […]` (sync or async), for values computed at prompt
37
+ * time with no framework services;
38
+ * - a **provider class** — a `CommandParameterChoicesProviderInterface` constructor, resolved
39
+ * from DI so it can inject services (e.g. list files, query an API).
40
+ *
41
+ * Dynamic choices (function / provider) drive the interactive menu only; a value passed as a
42
+ * flag is taken as-is (the resolver isn't run off the prompt path). Pair with `@IsIn(...)` if a
43
+ * dynamic value must also be validated when supplied non-interactively. A *static* list is not
44
+ * itself a validator — add `@IsIn(...)` / `@IsEnum(...)` to enforce it everywhere.
45
+ */
46
+ choices?: CommandParameterChoices;
47
+ /**
48
+ * The placeholder shown for this parameter in the generated `Usage:` line — e.g. `key-or-file`
49
+ * renders `[--pubkey=<key-or-file>]`. Defaults to the property name.
50
+ */
51
+ valueHint?: string;
52
+ /**
53
+ * Overrides the *entire* message shown when a supplied value fails validation — used verbatim,
54
+ * with `%value%` and `%flag%` placeholders substituted (the value is `<hidden>` for a
55
+ * `sensitive` parameter). When omitted, the message is generated as
56
+ * `Invalid <flag> '<value>'. <validator message>`.
57
+ */
58
+ errorMessage?: string;
29
59
  }
@@ -0,0 +1,64 @@
1
+ import { ClassConstructor } from "class-transformer";
2
+ import { UsageError } from "@pristine-ts/common";
3
+ import { CommandUsageRenderer } from "./command-usage-renderer";
4
+ /**
5
+ * Turns `@pristine-ts/class-validator`'s raw per-property validation output into a single,
6
+ * clean, user-facing `UsageError` (exit 64, rendered verbatim via `options.plain`) instead of
7
+ * a `[CONSTRAINT_KEY]`-prefixed dump:
8
+ *
9
+ * - if any *required* parameter is missing → the command's `Usage:` synopsis, so the user
10
+ * sees what to pass (and not a wall of "is not a string" noise for an absent value);
11
+ * - otherwise (values present but invalid) → one line per offending value: the parameter's
12
+ * `errorMessage` (verbatim, `%value%`/`%flag%` filled), or a generated
13
+ * `Invalid <flag> '<value>'. <validator message>` with the constraint-key prefix and
14
+ * definedness noise stripped.
15
+ *
16
+ * Returns the error rather than throwing it, so the resolver keeps the `throw` (clean control
17
+ * flow) and tests can assert on the built error directly.
18
+ */
19
+ export declare class CommandArgumentErrorFormatter {
20
+ private readonly usageRenderer;
21
+ /**
22
+ * Constraint keynames that only trip because a value is *absent*. For a present-but-invalid
23
+ * value these never fire, so we drop them and surface the semantic constraint (e.g.
24
+ * `MATCHES`) the user actually needs — never "is not a string" for a value they gave.
25
+ */
26
+ private static readonly DefinednessConstraints;
27
+ constructor(usageRenderer: CommandUsageRenderer);
28
+ /**
29
+ * Builds the `UsageError` for a set of validation errors. `mapped` is the (failed) options
30
+ * instance — read to get each property's effective value and to tell "missing" (undefined /
31
+ * empty) from "present but invalid".
32
+ */
33
+ buildValidationError(optionsType: ClassConstructor<any>, mapped: Record<string, any>, validationErrors: any[], context: {
34
+ commandName: string;
35
+ binName: string;
36
+ }): UsageError;
37
+ /** A value counts as "missing" when it never arrived — undefined/null or an empty string. */
38
+ private isMissing;
39
+ /**
40
+ * One line for an offending value. A parameter's `errorMessage` is the *entire* line, used
41
+ * verbatim (with `%value%`/`%flag%` filled); otherwise we generate
42
+ * `Invalid <flag> '<value>'. <validator message>`. Sensitive parameters never echo the value
43
+ * (it is `<hidden>`, even inside a custom template).
44
+ * @private
45
+ */
46
+ private invalidLine;
47
+ /**
48
+ * The validator's own message for a present-but-invalid value: the first *semantic* constraint
49
+ * message (definedness noise dropped), falling back to the first message present.
50
+ * @private
51
+ */
52
+ private validatorMessage;
53
+ /**
54
+ * Splits an error's constraint messages into the first *semantic* one (not a definedness
55
+ * constraint) and a plain first-seen fallback. Reads `@pristine-ts/class-validator`'s
56
+ * `{keyname, message}` constraint objects defensively.
57
+ * @private
58
+ */
59
+ private constraintMessages;
60
+ /** Pulls the human message out of a `{keyname, message}` constraint (or a bare string). */
61
+ private extractMessage;
62
+ private optionsFor;
63
+ private flagFor;
64
+ }
@@ -2,15 +2,17 @@ import { ClassConstructor } from "class-transformer";
2
2
  import { Validator } from "@pristine-ts/class-validator";
3
3
  import { DataMapper } from "@pristine-ts/data-mapping";
4
4
  import { CommandParameterPrompter } from "./command-parameter-prompter";
5
+ import { CommandArgumentErrorFormatter } from "./command-argument-error-formatter";
6
+ import { ProgramNameResolver } from "./program-name-resolver";
5
7
  /**
6
8
  * Resolves a typed, validated options instance from raw arguments: it fills any missing
7
- * `@commandParameter` values by prompting, maps the result onto a real `optionsType`
8
- * instance (prototype + decorator metadata intact, so `class-validator` finds its rules),
9
- * and validates it.
9
+ * `@commandParameter` values by prompting, maps the result onto a real `optionsType` instance
10
+ * (prototype + decorator metadata intact, so `class-validator` finds its rules), and validates
11
+ * it.
10
12
  *
11
- * This is the reusable core behind command dispatch — `CommandArgumentResolver` delegates
12
- * here — exposed so commands and dynamic flows can fill an options class from prompts on
13
- * demand, including ones not tied to a registered command:
13
+ * This is the reusable core behind command dispatch — `CommandArgumentResolver` delegates here
14
+ * — exposed so commands and dynamic flows can fill an options class from prompts on demand,
15
+ * including ones not tied to a registered command:
14
16
  *
15
17
  * ```ts
16
18
  * constructor(private readonly optionsResolver: CommandOptionsResolver) {}
@@ -18,18 +20,26 @@ import { CommandParameterPrompter } from "./command-parameter-prompter";
18
20
  * const options = await this.optionsResolver.resolve(MyOptions, {region: "us"});
19
21
  * ```
20
22
  *
21
- * Throws `UsageError` for mapping failures and `ValidationError` for validation failures —
22
- * both carry structured `details` for `CliErrorReporter`.
23
+ * Argument problems throw a `UsageError` (exit 64): mapping failures directly, and validation
24
+ * failures via `CommandArgumentErrorFormatter`, which renders a clean `Usage:` synopsis (for a
25
+ * missing required value) or `Invalid <flag> '<value>'. …` lines (for a supplied-but-invalid
26
+ * value) rather than a raw constraint dump.
23
27
  */
24
28
  export declare class CommandOptionsResolver {
25
29
  private readonly validator;
26
30
  private readonly dataMapper;
27
31
  private readonly commandParameterPrompter;
28
- constructor(validator: Validator, dataMapper: DataMapper, commandParameterPrompter: CommandParameterPrompter);
32
+ private readonly argumentErrorFormatter;
33
+ private readonly programNameResolver;
34
+ constructor(validator: Validator, dataMapper: DataMapper, commandParameterPrompter: CommandParameterPrompter, argumentErrorFormatter: CommandArgumentErrorFormatter, programNameResolver: ProgramNameResolver);
29
35
  /**
30
- * Prompts for any missing parameters declared on `optionsType`, then maps `rawArgs` (plus
31
- * the prompted answers) onto a real instance and validates it. `rawArgs` seeds the values
32
- * already known — anything absent that carries a `question` is asked for interactively.
36
+ * Prompts for any missing parameters declared on `optionsType`, then maps `rawArgs` (plus the
37
+ * prompted answers) onto a real instance and validates it. `rawArgs` seeds the values already
38
+ * known — anything absent that carries a `question` is asked for interactively.
39
+ * `context.commandName` is woven into the `Usage:` line shown when a required value is missing
40
+ * (defaults to a neutral placeholder for direct, command-less callers).
33
41
  */
34
- resolve<T>(optionsType: ClassConstructor<T>, rawArgs?: Record<string, any>): Promise<T>;
42
+ resolve<T>(optionsType: ClassConstructor<T>, rawArgs?: Record<string, any>, context?: {
43
+ commandName?: string;
44
+ }): Promise<T>;
35
45
  }
@@ -1,25 +1,27 @@
1
1
  import "reflect-metadata";
2
+ import { DependencyContainer } from "tsyringe";
2
3
  import { ClassConstructor } from "class-transformer";
3
4
  import { Validator } from "@pristine-ts/class-validator";
4
5
  import { DataMapper } from "@pristine-ts/data-mapping";
5
6
  import { CliPrompt } from "../managers/cli-prompt.manager";
6
7
  import { CliOutput } from "../managers/cli-output.manager";
7
8
  /**
8
- * Applies a command's `@commandParameter` metadata to its raw, parsed arguments before they
9
- * are mapped onto the options instance and validated. Two things happen here:
9
+ * Applies a command's `@commandParameter` metadata to its raw, parsed arguments before they are
10
+ * mapped onto the options instance and validated. Two things happen here:
10
11
  *
11
- * 1. **Flag binding** — a parameter whose `flag` differs from its property name is copied
12
- * from the flag key onto the property key, so the by-property-name data mapper picks it
13
- * up. Two parameters resolving to the same flag is a programming error and throws.
14
- * 2. **Interactive fill** — a parameter that is absent and declares a `question` is asked
15
- * for interactively. Answers are rendered and checked against the property's declared
16
- * type (booleans as `(y/n)`, enum-constrained values list their choices) and coerced +
17
- * validated through the same mapper/validator the command pipeline uses, re-asking on an
18
- * invalid answer. Gated by the `InteractiveParameters` configuration and only run against
19
- * an interactive terminal; otherwise the absent value is left for validation to report.
12
+ * 1. **Flag binding** — a parameter whose `flag` differs from its property name is copied from
13
+ * the flag key onto the property key, so the by-property-name data mapper picks it up. Two
14
+ * parameters resolving to the same flag is a programming error and throws.
15
+ * 2. **Interactive fill** — a parameter that is absent and declares a `question` is asked for
16
+ * interactively. Values constrained to a set an explicit `choices`, or an `@IsIn` /
17
+ * `@IsEnum` — are picked from an arrow-key menu; booleans answer `(y/n)`; everything else is
18
+ * a free-text answer coerced + validated through the same mapper/validator the command
19
+ * pipeline uses, re-asking on an invalid answer. Gated by the `InteractiveParameters`
20
+ * configuration and only run against an interactive terminal; otherwise the absent value is
21
+ * left for validation to report.
20
22
  *
21
- * Parameters without a `@commandParameter` decorator are untouched, so commands that don't
22
- * use it pay nothing.
23
+ * Parameters without a `@commandParameter` decorator are untouched, so commands that don't use
24
+ * it pay nothing.
23
25
  */
24
26
  export declare class CommandParameterPrompter {
25
27
  private readonly cliPrompt;
@@ -27,6 +29,7 @@ export declare class CommandParameterPrompter {
27
29
  private readonly validator;
28
30
  private readonly dataMapper;
29
31
  private readonly interactiveParametersEnabled;
32
+ private readonly container;
30
33
  /**
31
34
  * `@pristine-ts/class-validator` stores its instantiated validators (one per `@IsX`
32
35
  * decorator) as an array under this property-metadata key. We read it only to surface enum
@@ -39,35 +42,62 @@ export declare class CommandParameterPrompter {
39
42
  * unbounded loop) keeps a misconfigured validator that can never pass from hanging the CLI.
40
43
  */
41
44
  private static readonly MaxAttempts;
42
- constructor(cliPrompt: CliPrompt, cliOutput: CliOutput, validator: Validator, dataMapper: DataMapper, interactiveParametersEnabled: boolean);
45
+ constructor(cliPrompt: CliPrompt, cliOutput: CliOutput, validator: Validator, dataMapper: DataMapper, interactiveParametersEnabled: boolean, container: DependencyContainer);
43
46
  /**
44
47
  * Returns a copy of `rawArgs` with aliased flags bound to their property and any missing,
45
- * question-carrying parameters filled in interactively. The input object is never mutated
46
- * the original command event payload stays intact.
48
+ * question-carrying parameters filled in interactively. The input object is never mutated
49
+ * the original command event payload stays intact.
47
50
  */
48
51
  fillMissingParameters(optionsType: ClassConstructor<any>, rawArgs: Record<string, any>): Promise<Record<string, any>>;
49
52
  /**
50
- * Reads every `@commandParameter` off `optionsType`, resolving each to its effective flag
51
- * and detecting two parameters that would claim the same flag (a programming error).
53
+ * Reads every `@commandParameter` off `optionsType`, resolving each to its effective flag and
54
+ * detecting two parameters that would claim the same flag (a programming error).
52
55
  * @private
53
56
  */
54
57
  private collectParameters;
55
58
  /**
56
- * Asks for a single parameter's value, rendering and validating it according to the
57
- * property's declared type:
59
+ * Asks for a single parameter's value, rendering and validating it according to the property's
60
+ * declared type:
58
61
  *
59
62
  * - sensitive values are read with the input masked and never trimmed;
63
+ * - a constrained value (explicit `choices`, or `@IsIn` / `@IsEnum`) is picked from an
64
+ * arrow-key menu, then coerced + validated like any typed value;
60
65
  * - booleans render as `(y/n)` and accept y/yes/true/1 & n/no/false/0;
61
- * - enum-constrained values (`@IsIn` / `@IsEnum`) list their choices;
62
66
  * - every other answer is coerced (via the data mapper) and validated (via the validator)
63
67
  * exactly as a typed flag would be, re-asking with the real constraint message when it
64
68
  * doesn't pass.
65
69
  *
66
- * Returns the coerced value, or `undefined` when the user enters nothing or the attempt
67
- * budget is exhausted — in which case the absent value falls through to validation.
70
+ * Returns the coerced value, or `undefined` when the user enters nothing or the attempt budget
71
+ * is exhausted — in which case the absent value falls through to validation.
68
72
  * @private
69
73
  */
70
74
  private promptForValue;
75
+ /**
76
+ * Resolves this parameter's selectable choices to a `{name, value}[]` menu, or `undefined`
77
+ * when it has none (free-text). Sources, in order: an explicit `@commandParameter({choices})`
78
+ * — a static list, a resolver function, or a DI provider class — else the `@IsIn` / `@IsEnum`
79
+ * set. An empty result is treated as "no menu".
80
+ * @private
81
+ */
82
+ private resolveChoices;
83
+ /**
84
+ * The raw choices list from the declared `choices` (static array / resolver function / DI
85
+ * provider class), falling back to the enum/`@IsIn` set when none is declared. Dynamic
86
+ * resolution failures degrade to free-text rather than crashing the prompt.
87
+ * @private
88
+ */
89
+ private resolveChoicesList;
90
+ /**
91
+ * Whether `candidate` is a provider *class* (vs a plain resolver function): a class carries a
92
+ * prototype with a `getChoices` method; an arrow/plain resolver does not.
93
+ * @private
94
+ */
95
+ private isChoicesProviderClass;
96
+ /**
97
+ * The menu heading: the parameter's `question` when set, else a neutral `Select <flag>`.
98
+ * @private
99
+ */
100
+ private menuMessage;
71
101
  /**
72
102
  * Maps a single raw answer onto a probe instance of `optionsType` and validates just that
73
103
  * property, returning the coerced value when it passes or the constraint messages when it
@@ -77,18 +107,17 @@ export declare class CommandParameterPrompter {
77
107
  */
78
108
  private coerceAndValidate;
79
109
  /**
80
- * Flattens `class-validator`'s per-property constraint objects into plain, user-facing
81
- * lines. `@pristine-ts/class-validator` stores each constraint as `{keyname, message}`
82
- * rather than a bare string, so prefer `.message`, falling back so we never print
83
- * `[object Object]`.
110
+ * Flattens `class-validator`'s per-property constraint objects into plain, user-facing lines.
111
+ * `@pristine-ts/class-validator` stores each constraint as `{keyname, message}` rather than a
112
+ * bare string, so prefer `.message`, falling back so we never print `[object Object]`.
84
113
  * @private
85
114
  */
86
115
  private describeErrors;
87
116
  /**
88
117
  * The allowed values declared by an `@IsIn([...])` or `@IsEnum(Enum)` on the property, for
89
118
  * display in the prompt. Reads `@pristine-ts/class-validator`'s stored validator instances
90
- * defensively — any shape mismatch just yields no menu (validation still rejects bad input
91
- * and re-asks). Returns undefined when the property isn't enum-constrained.
119
+ * defensively — any shape mismatch just yields no menu (validation still rejects bad input and
120
+ * re-asks). Returns undefined when the property isn't enum-constrained.
92
121
  * @private
93
122
  */
94
123
  private getChoices;
@@ -105,8 +134,8 @@ export declare class CommandParameterPrompter {
105
134
  */
106
135
  private isInputInteractive;
107
136
  /**
108
- * Ensures the rendered question ends with a trailing space so the typed answer doesn't butt
109
- * up against the prompt text.
137
+ * Ensures the rendered question ends with a trailing space so the typed answer doesn't butt up
138
+ * against the prompt text.
110
139
  * @private
111
140
  */
112
141
  private formatQuestion;
@@ -0,0 +1,35 @@
1
+ import "reflect-metadata";
2
+ import { ClassConstructor } from "class-transformer";
3
+ /**
4
+ * Builds the one-line `Usage:` synopsis for a command from its options class, e.g.
5
+ *
6
+ * Usage: myapp key:add --name=<name> [--pubkey=<key-or-file>] [--rotate]
7
+ *
8
+ * Every declared option property becomes a token: required values render as `--flag=<hint>`,
9
+ * optional values as `[--flag=<hint>]`, and booleans as `[--flag]` (presence flags take no
10
+ * value). The placeholder defaults to the property name and can be overridden per parameter
11
+ * with `@commandParameter({valueHint})`; the flag honors `@commandParameter({flag})`.
12
+ *
13
+ * "Required" means the absence of an `@IsOptional()` condition on the property — the same
14
+ * signal the validator uses to decide whether a missing value is an error.
15
+ */
16
+ export declare class CommandUsageRenderer {
17
+ /** `@pristine-ts/class-validator` stores each `@IsOptional()` as a condition here. */
18
+ private static readonly ConditionMetadataKey;
19
+ /**
20
+ * Renders `Usage: <bin> <command> <tokens…>`. `binName` is the resolved program name (see
21
+ * `ProgramNameResolver`); `commandName` is the command's `name`.
22
+ */
23
+ render(optionsType: ClassConstructor<any>, commandName: string, binName: string): string;
24
+ /**
25
+ * One synopsis token per declared option property, in declaration order.
26
+ * @private
27
+ */
28
+ private collectTokens;
29
+ /**
30
+ * A property is required unless it carries an `@IsOptional()` condition. Read defensively: an
31
+ * unexpected metadata shape is treated as required (the safer default for a usage hint).
32
+ * @private
33
+ */
34
+ private isRequired;
35
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Resolves the program name shown in generated `Usage:` lines — the name the user actually
3
+ * typed, e.g. `myapp`, not the framework's `pristine`. Resolution is a hybrid, in priority
4
+ * order:
5
+ *
6
+ * 1. the `pristine.cli.binName` configuration, when set (an explicit override for odd launch
7
+ * shapes like `node dist/bin/cli.cjs`, where argv carries a file name);
8
+ * 2. otherwise `basename(argv[1])` with any `.cjs`/`.js`/`.mjs` extension stripped — the bin
9
+ * the user invoked, robust across global installs, `npx`, and local `.bin` shims;
10
+ * 3. otherwise the framework default `pristine`.
11
+ */
12
+ export declare class ProgramNameResolver {
13
+ private readonly configuredBinName;
14
+ private static readonly Fallback;
15
+ constructor(configuredBinName: string);
16
+ /**
17
+ * Returns the resolved program name. `argv` defaults to `process.argv`; it is a parameter so
18
+ * the REPL (and tests) can resolve a name from a synthetic argv.
19
+ */
20
+ resolve(argv?: readonly string[]): string;
21
+ }
@@ -1,3 +1,6 @@
1
+ export * from "./command-argument-error-formatter";
1
2
  export * from "./command-argument-resolver";
2
3
  export * from "./command-options-resolver";
3
4
  export * from "./command-parameter-prompter";
5
+ export * from "./command-usage-renderer";
6
+ export * from "./program-name-resolver";
@@ -0,0 +1,6 @@
1
+ import { CommandParameterChoice } from "../interfaces/command-parameter-choice.interface";
2
+ /**
3
+ * The result of resolving a parameter's choices: an ordered list where each entry is either a
4
+ * `{name, value}` pair or a bare `string` (shorthand for `{name: s, value: s}`).
5
+ */
6
+ export type CommandParameterChoicesList = ReadonlyArray<string | CommandParameterChoice>;
@@ -0,0 +1,9 @@
1
+ import { CommandParameterChoicesContext } from "../interfaces/command-parameter-choices-context.interface";
2
+ import { CommandParameterChoicesList } from "./command-parameter-choices-list.type";
3
+ /**
4
+ * A plain function that computes a parameter's choices at prompt time, optionally narrowed by
5
+ * the already-resolved arguments. Use this when resolution needs no framework services (env
6
+ * vars, a captured closure, simple computation); reach for
7
+ * `CommandParameterChoicesProviderInterface` when it needs DI.
8
+ */
9
+ export type CommandParameterChoicesResolver = (context: CommandParameterChoicesContext) => CommandParameterChoicesList | Promise<CommandParameterChoicesList>;
@@ -0,0 +1,19 @@
1
+ import { ClassConstructor } from "class-transformer";
2
+ import { CommandParameterChoicesList } from "./command-parameter-choices-list.type";
3
+ import { CommandParameterChoicesResolver } from "./command-parameter-choices-resolver.type";
4
+ import { CommandParameterChoicesProviderInterface } from "../interfaces/command-parameter-choices-provider.interface";
5
+ /**
6
+ * What `@commandParameter({choices})` accepts. Three shapes, one behavior (single-select):
7
+ *
8
+ * - **static** — a `CommandParameterChoicesList` (array of `{name, value}` or bare strings)
9
+ * known at decoration time;
10
+ * - **dynamic, no DI** — a `CommandParameterChoicesResolver` function resolved at prompt
11
+ * time;
12
+ * - **dynamic, with DI** — the *class* of a `CommandParameterChoicesProviderInterface`,
13
+ * resolved from the container at prompt time so it can inject framework services.
14
+ *
15
+ * Dynamic choices are resolved only on the interactive path (an arrow-key menu); a value
16
+ * passed as a flag is taken as-is. Add `@IsIn(...)` if a dynamic value must also be validated
17
+ * when supplied non-interactively.
18
+ */
19
+ export type CommandParameterChoices = CommandParameterChoicesList | CommandParameterChoicesResolver | ClassConstructor<CommandParameterChoicesProviderInterface>;
@@ -1,3 +1,6 @@
1
1
  export * from "./command-event.type";
2
2
  export * from "./command-event-response.type";
3
+ export * from "./command-parameter-choices-list.type";
4
+ export * from "./command-parameter-choices-resolver.type";
5
+ export * from "./command-parameter-choices.type";
3
6
  export * from "./start-repl-event-response.type";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pristine-ts/cli",
3
- "version": "2.0.16",
3
+ "version": "2.0.18",
4
4
  "description": "",
5
5
  "module": "dist/lib/esm/cli.module.js",
6
6
  "main": "dist/lib/cjs/cli.module.js",
@@ -27,17 +27,17 @@
27
27
  "access": "public"
28
28
  },
29
29
  "dependencies": {
30
- "@pristine-ts/common": "^2.0.16",
31
- "@pristine-ts/configuration": "^2.0.16",
32
- "@pristine-ts/core": "^2.0.16",
33
- "@pristine-ts/data-mapping": "^2.0.16",
34
- "@pristine-ts/data-mapping-common": "^2.0.16",
35
- "@pristine-ts/file": "^2.0.16",
36
- "@pristine-ts/logging": "^2.0.16",
30
+ "@pristine-ts/common": "^2.0.18",
31
+ "@pristine-ts/configuration": "^2.0.18",
32
+ "@pristine-ts/core": "^2.0.18",
33
+ "@pristine-ts/data-mapping": "^2.0.18",
34
+ "@pristine-ts/data-mapping-common": "^2.0.18",
35
+ "@pristine-ts/file": "^2.0.18",
36
+ "@pristine-ts/logging": "^2.0.18",
37
37
  "@pristine-ts/metadata": "^1.0.16",
38
- "@pristine-ts/observability": "^2.0.16",
39
- "@pristine-ts/telemetry": "^2.0.16",
40
- "@pristine-ts/validation": "^2.0.16"
38
+ "@pristine-ts/observability": "^2.0.18",
39
+ "@pristine-ts/telemetry": "^2.0.18",
40
+ "@pristine-ts/validation": "^2.0.18"
41
41
  },
42
42
  "devDependencies": {
43
43
  "esbuild": "^0.24.0"
@@ -76,7 +76,7 @@
76
76
  "src/*.{js,ts}"
77
77
  ]
78
78
  },
79
- "gitHead": "a55d7d59862672a8cbbca4088fed090779b37705",
79
+ "gitHead": "2a2c5dbb9b5060b30528335ad17a174fae43f87c",
80
80
  "repository": {
81
81
  "type": "git",
82
82
  "url": "https://github.com/magieno/pristine-ts.git",