@ollie-shop/cli 0.3.0 → 0.3.3

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 (139) hide show
  1. package/.turbo/turbo-build.log +14 -2
  2. package/CHANGELOG.md +48 -0
  3. package/__tests__/mocks/core.ts +1 -1
  4. package/dist/index.d.ts +0 -2
  5. package/dist/index.js +40631 -75
  6. package/package.json +7 -6
  7. package/src/actions/component.actions.ts +148 -204
  8. package/src/actions/function.actions.ts +78 -171
  9. package/src/actions/project.actions.ts +16 -11
  10. package/src/commands/__tests__/component.test.ts +4 -7
  11. package/src/commands/__tests__/function.test.ts +1 -1
  12. package/src/commands/__tests__/store-version.test.ts +1 -4
  13. package/src/commands/component.ts +0 -10
  14. package/src/commands/function.ts +5 -56
  15. package/src/schemas/command.schema.ts +296 -6
  16. package/src/utils/__tests__/rich-progress.test.ts +22 -11
  17. package/src/utils/cli-progress-reporter.ts +2 -2
  18. package/src/utils/command-parser.ts +0 -5
  19. package/src/utils/console.ts +33 -4
  20. package/src/utils/constants.ts +32 -0
  21. package/src/utils/deploy-helpers.ts +357 -0
  22. package/src/utils/errors.ts +133 -2
  23. package/src/utils/interactive-builder.ts +61 -7
  24. package/src/utils/rich-progress.ts +25 -14
  25. package/src/utils/validation-helpers.ts +145 -12
  26. package/tsup.config.ts +15 -0
  27. package/dist/__tests__/helpers/cli-test-helper.d.ts +0 -89
  28. package/dist/__tests__/helpers/cli-test-helper.d.ts.map +0 -1
  29. package/dist/__tests__/helpers/cli-test-helper.js +0 -220
  30. package/dist/__tests__/mocks/index.d.ts +0 -69
  31. package/dist/__tests__/mocks/index.d.ts.map +0 -1
  32. package/dist/__tests__/mocks/index.js +0 -77
  33. package/dist/actions/component.actions.d.ts +0 -14
  34. package/dist/actions/component.actions.d.ts.map +0 -1
  35. package/dist/actions/component.actions.js +0 -273
  36. package/dist/actions/function.actions.d.ts +0 -15
  37. package/dist/actions/function.actions.d.ts.map +0 -1
  38. package/dist/actions/function.actions.js +0 -254
  39. package/dist/actions/project.actions.d.ts +0 -17
  40. package/dist/actions/project.actions.d.ts.map +0 -1
  41. package/dist/actions/project.actions.js +0 -97
  42. package/dist/actions/version.actions.d.ts +0 -19
  43. package/dist/actions/version.actions.d.ts.map +0 -1
  44. package/dist/actions/version.actions.js +0 -216
  45. package/dist/commands/component.d.ts +0 -3
  46. package/dist/commands/component.d.ts.map +0 -1
  47. package/dist/commands/component.js +0 -192
  48. package/dist/commands/docs.d.ts +0 -3
  49. package/dist/commands/docs.d.ts.map +0 -1
  50. package/dist/commands/docs.js +0 -16
  51. package/dist/commands/function.d.ts +0 -3
  52. package/dist/commands/function.d.ts.map +0 -1
  53. package/dist/commands/function.js +0 -243
  54. package/dist/commands/help.d.ts +0 -3
  55. package/dist/commands/help.d.ts.map +0 -1
  56. package/dist/commands/help.js +0 -20
  57. package/dist/commands/index.d.ts +0 -3
  58. package/dist/commands/index.d.ts.map +0 -1
  59. package/dist/commands/index.js +0 -26
  60. package/dist/commands/login.d.ts +0 -3
  61. package/dist/commands/login.d.ts.map +0 -1
  62. package/dist/commands/login.js +0 -175
  63. package/dist/commands/project.d.ts +0 -3
  64. package/dist/commands/project.d.ts.map +0 -1
  65. package/dist/commands/project.js +0 -78
  66. package/dist/commands/store-version.d.ts +0 -3
  67. package/dist/commands/store-version.d.ts.map +0 -1
  68. package/dist/commands/store-version.js +0 -241
  69. package/dist/commands/version.d.ts +0 -3
  70. package/dist/commands/version.d.ts.map +0 -1
  71. package/dist/commands/version.js +0 -46
  72. package/dist/commands/whoami.d.ts +0 -3
  73. package/dist/commands/whoami.d.ts.map +0 -1
  74. package/dist/commands/whoami.js +0 -41
  75. package/dist/index.d.ts.map +0 -1
  76. package/dist/prompts/component.prompts.d.ts +0 -14
  77. package/dist/prompts/component.prompts.d.ts.map +0 -1
  78. package/dist/prompts/component.prompts.js +0 -75
  79. package/dist/prompts/function.prompts.d.ts +0 -21
  80. package/dist/prompts/function.prompts.d.ts.map +0 -1
  81. package/dist/prompts/function.prompts.js +0 -127
  82. package/dist/schemas/command.schema.d.ts +0 -516
  83. package/dist/schemas/command.schema.d.ts.map +0 -1
  84. package/dist/schemas/command.schema.js +0 -267
  85. package/dist/types/index.d.ts +0 -147
  86. package/dist/types/index.d.ts.map +0 -1
  87. package/dist/types/index.js +0 -18
  88. package/dist/utils/auth.d.ts +0 -4
  89. package/dist/utils/auth.d.ts.map +0 -1
  90. package/dist/utils/auth.js +0 -26
  91. package/dist/utils/cli-progress-reporter.d.ts +0 -12
  92. package/dist/utils/cli-progress-reporter.d.ts.map +0 -1
  93. package/dist/utils/cli-progress-reporter.js +0 -77
  94. package/dist/utils/command-builder.d.ts +0 -22
  95. package/dist/utils/command-builder.d.ts.map +0 -1
  96. package/dist/utils/command-builder.js +0 -268
  97. package/dist/utils/command-helpers.d.ts +0 -19
  98. package/dist/utils/command-helpers.d.ts.map +0 -1
  99. package/dist/utils/command-helpers.js +0 -79
  100. package/dist/utils/command-parser.d.ts +0 -146
  101. package/dist/utils/command-parser.d.ts.map +0 -1
  102. package/dist/utils/command-parser.js +0 -179
  103. package/dist/utils/command-suggestions.d.ts +0 -35
  104. package/dist/utils/command-suggestions.d.ts.map +0 -1
  105. package/dist/utils/command-suggestions.js +0 -152
  106. package/dist/utils/console.d.ts +0 -44
  107. package/dist/utils/console.d.ts.map +0 -1
  108. package/dist/utils/console.js +0 -233
  109. package/dist/utils/constants.d.ts +0 -8
  110. package/dist/utils/constants.d.ts.map +0 -1
  111. package/dist/utils/constants.js +0 -10
  112. package/dist/utils/context-detector.d.ts +0 -12
  113. package/dist/utils/context-detector.d.ts.map +0 -1
  114. package/dist/utils/context-detector.js +0 -155
  115. package/dist/utils/enhanced-error-handler.d.ts +0 -47
  116. package/dist/utils/enhanced-error-handler.d.ts.map +0 -1
  117. package/dist/utils/enhanced-error-handler.js +0 -221
  118. package/dist/utils/error-handler.d.ts +0 -3
  119. package/dist/utils/error-handler.d.ts.map +0 -1
  120. package/dist/utils/error-handler.js +0 -55
  121. package/dist/utils/errors.d.ts +0 -44
  122. package/dist/utils/errors.d.ts.map +0 -1
  123. package/dist/utils/errors.js +0 -76
  124. package/dist/utils/interactive-builder.d.ts +0 -22
  125. package/dist/utils/interactive-builder.d.ts.map +0 -1
  126. package/dist/utils/interactive-builder.js +0 -246
  127. package/dist/utils/rich-progress.d.ts +0 -59
  128. package/dist/utils/rich-progress.d.ts.map +0 -1
  129. package/dist/utils/rich-progress.js +0 -234
  130. package/dist/utils/store.d.ts +0 -11
  131. package/dist/utils/store.d.ts.map +0 -1
  132. package/dist/utils/store.js +0 -19
  133. package/dist/utils/validation-error-formatter.d.ts +0 -25
  134. package/dist/utils/validation-error-formatter.d.ts.map +0 -1
  135. package/dist/utils/validation-error-formatter.js +0 -258
  136. package/dist/utils/validation-helpers.d.ts +0 -60
  137. package/dist/utils/validation-helpers.d.ts.map +0 -1
  138. package/dist/utils/validation-helpers.js +0 -152
  139. package/src/commands/__tests__/version.test.ts +0 -71
@@ -1,6 +1,7 @@
1
1
  import chalk from "chalk";
2
2
  import cliProgress from "cli-progress";
3
3
  import type { ProgressParams, ProgressPayload, Spinner } from "../types";
4
+ import type { CliConsole } from "./console";
4
5
 
5
6
  // Enhanced build progress type for CLI display
6
7
  interface CLIBuildProgress {
@@ -40,8 +41,10 @@ export class RichProgressReporter {
40
41
  dependencies?: number;
41
42
  removedExports?: number;
42
43
  } = {};
44
+ private cliConsole: CliConsole;
43
45
 
44
- constructor() {
46
+ constructor(cliConsole: CliConsole) {
47
+ this.cliConsole = cliConsole;
45
48
  // Create a formatter function that matches cli-progress expectations
46
49
  const formatter = (
47
50
  options: Record<string, unknown>,
@@ -88,13 +91,17 @@ export class RichProgressReporter {
88
91
  return this.formatBar(formatOptions, progressParams, progressPayload);
89
92
  };
90
93
 
91
- // Cast formatter to unknown first to bypass TypeScript's structural typing check
92
- // cli-progress expects a GenericFormatter but the type definitions don't match exactly
93
- const formatFunction = formatter as unknown;
94
+ // Create a type-safe wrapper for the cli-progress formatter
95
+ // This ensures our formatter function matches the expected signature
96
+ const formatFunction: cliProgress.GenericFormatter = (
97
+ options: Record<string, unknown>,
98
+ params: Record<string, unknown>,
99
+ payload: Record<string, unknown>,
100
+ ) => formatter(options, params, payload);
94
101
 
95
102
  this.multibar = new cliProgress.MultiBar(
96
103
  {
97
- format: formatFunction as cliProgress.GenericFormatter,
104
+ format: formatFunction,
98
105
  barCompleteChar: "\u2588",
99
106
  barIncompleteChar: "\u2591",
100
107
  hideCursor: true,
@@ -149,7 +156,7 @@ export class RichProgressReporter {
149
156
  * Start progress tracking
150
157
  */
151
158
  start(): void {
152
- console.log(chalk.blue.bold("\n🚀 Starting deployment...\n"));
159
+ this.cliConsole.info(chalk.blue.bold("\n🚀 Starting deployment...\n"));
153
160
 
154
161
  // Create bars for each step
155
162
  for (const step of this.steps) {
@@ -238,7 +245,7 @@ export class RichProgressReporter {
238
245
  if (success) {
239
246
  this.showSuccessSummary();
240
247
  } else {
241
- console.log(chalk.red("\n❌ Deployment failed\n"));
248
+ this.cliConsole.error(chalk.red("\n❌ Deployment failed\n"));
242
249
  }
243
250
  }
244
251
 
@@ -248,33 +255,37 @@ export class RichProgressReporter {
248
255
  private showSuccessSummary(): void {
249
256
  const duration = ((Date.now() - this.startTime) / 1000).toFixed(1);
250
257
 
251
- console.log(chalk.green.bold("\n✅ Deployment completed successfully!\n"));
258
+ this.cliConsole.success(
259
+ chalk.green.bold("\n✅ Deployment completed successfully!\n"),
260
+ );
252
261
 
253
262
  if (Object.keys(this.stats).length > 0) {
254
- console.log(chalk.blue("📊 Build Stats:"));
263
+ this.cliConsole.info(chalk.blue("📊 Build Stats:"));
255
264
 
256
265
  if (this.stats.bundleSize) {
257
266
  const sizeKB = (this.stats.bundleSize / 1024).toFixed(1);
258
267
  const gzipKB = this.stats.gzippedSize
259
268
  ? (this.stats.gzippedSize / 1024).toFixed(1)
260
269
  : "?";
261
- console.log(` • Bundle size: ${sizeKB}KB (gzipped: ${gzipKB}KB)`);
270
+ this.cliConsole.info(
271
+ ` • Bundle size: ${sizeKB}KB (gzipped: ${gzipKB}KB)`,
272
+ );
262
273
  }
263
274
 
264
275
  if (this.stats.removedExports) {
265
- console.log(
276
+ this.cliConsole.info(
266
277
  ` • Tree shaking: Removed ${this.stats.removedExports} unused exports`,
267
278
  );
268
279
  }
269
280
 
270
281
  if (this.stats.dependencies) {
271
- console.log(` • Dependencies: ${this.stats.dependencies}`);
282
+ this.cliConsole.info(` • Dependencies: ${this.stats.dependencies}`);
272
283
  }
273
284
 
274
- console.log("");
285
+ this.cliConsole.info("");
275
286
  }
276
287
 
277
- console.log(chalk.dim(`Total time: ${duration}s`));
288
+ this.cliConsole.info(chalk.dim(`Total time: ${duration}s`));
278
289
  }
279
290
  }
280
291
 
@@ -9,19 +9,42 @@ import {
9
9
  } from "../schemas/command.schema";
10
10
  import type { CliConsole } from "./console";
11
11
 
12
+ /**
13
+ * Result of a validation operation
14
+ * @interface ValidationResult
15
+ * @property {boolean} valid - Whether the validation passed
16
+ * @property {Array<{message?: string} | string>} [errors] - List of validation errors
17
+ * @property {Array<{message?: string} | string>} [warnings] - List of validation warnings
18
+ */
12
19
  export interface ValidationResult {
13
20
  valid: boolean;
14
21
  errors?: Array<{ message?: string } | string>;
15
22
  warnings?: Array<{ message?: string } | string>;
16
23
  }
17
24
 
25
+ /**
26
+ * Interface for managing spinner states
27
+ * @interface SpinnerManager
28
+ * @property {Function} succeed - Mark spinner as successful with message
29
+ * @property {Function} fail - Mark spinner as failed with message
30
+ */
18
31
  export interface SpinnerManager {
19
32
  succeed: (text: string) => void;
20
33
  fail: (text: string) => void;
21
34
  }
22
35
 
23
36
  /**
24
- * Validate component name format using Zod schema
37
+ * Validates a component name against naming conventions
38
+ * Component names must be lowercase, use hyphens, and follow kebab-case
39
+ *
40
+ * @param {string} name - The component name to validate
41
+ * @returns {true | string} Returns true if valid, or an error message string if invalid
42
+ * @example
43
+ * ```typescript
44
+ * validateComponentName("my-header") // returns true
45
+ * validateComponentName("MyHeader") // returns "Component name must be lowercase"
46
+ * validateComponentName("my_header") // returns "Use hyphens instead of underscores"
47
+ * ```
25
48
  */
26
49
  export function validateComponentName(name: string): true | string {
27
50
  const result = ComponentNameSchema.safeParse(name);
@@ -31,7 +54,17 @@ export function validateComponentName(name: string): true | string {
31
54
  }
32
55
 
33
56
  /**
34
- * Validate function name format using Zod schema
57
+ * Validates a function name against naming conventions
58
+ * Function names must be lowercase, use hyphens, and follow kebab-case
59
+ *
60
+ * @param {string} name - The function name to validate
61
+ * @returns {true | string} Returns true if valid, or an error message string if invalid
62
+ * @example
63
+ * ```typescript
64
+ * validateFunctionName("validate-cart") // returns true
65
+ * validateFunctionName("validateCart") // returns "Function name must be lowercase"
66
+ * validateFunctionName("validate cart") // returns "No spaces allowed in function names"
67
+ * ```
35
68
  */
36
69
  export function validateFunctionName(name: string): true | string {
37
70
  const result = FunctionNameSchema.safeParse(name);
@@ -41,7 +74,15 @@ export function validateFunctionName(name: string): true | string {
41
74
  }
42
75
 
43
76
  /**
44
- * Validate store ID format using Zod schema
77
+ * Validates a store ID is in proper UUID v4 format
78
+ *
79
+ * @param {string} storeId - The store ID to validate
80
+ * @returns {true | string} Returns true if valid UUID, or an error message if invalid
81
+ * @example
82
+ * ```typescript
83
+ * validateStoreId("123e4567-e89b-12d3-a456-426614174000") // returns true
84
+ * validateStoreId("invalid-id") // returns "Invalid store ID format"
85
+ * ```
45
86
  */
46
87
  export function validateStoreId(storeId: string): true | string {
47
88
  const result = StoreIdSchema.safeParse(storeId);
@@ -51,7 +92,17 @@ export function validateStoreId(storeId: string): true | string {
51
92
  }
52
93
 
53
94
  /**
54
- * Validate version name using Zod schema
95
+ * Validates a version name meets requirements
96
+ * Version names must be 1-100 characters long
97
+ *
98
+ * @param {string} name - The version name to validate
99
+ * @returns {true | string} Returns true if valid, or an error message if invalid
100
+ * @example
101
+ * ```typescript
102
+ * validateVersionName("Production v2.0") // returns true
103
+ * validateVersionName("") // returns "Version name is required"
104
+ * validateVersionName("a".repeat(101)) // returns "Version name is too long (max 100 characters)"
105
+ * ```
55
106
  */
56
107
  export function validateVersionName(name: string): true | string {
57
108
  const result = VersionNameSchema.safeParse(name);
@@ -61,7 +112,19 @@ export function validateVersionName(name: string): true | string {
61
112
  }
62
113
 
63
114
  /**
64
- * Validate priority value using Zod schema
115
+ * Validates a priority value is within acceptable range
116
+ * Priority must be an integer between 0 and 100 (inclusive)
117
+ *
118
+ * @param {number} priority - The priority value to validate
119
+ * @returns {true | string} Returns true if valid, or an error message if invalid
120
+ * @example
121
+ * ```typescript
122
+ * validatePriority(50) // returns true
123
+ * validatePriority(0) // returns true (minimum)
124
+ * validatePriority(100) // returns true (maximum)
125
+ * validatePriority(150) // returns "Priority must be between 0 and 100"
126
+ * validatePriority(50.5) // returns "Priority must be a whole number"
127
+ * ```
65
128
  */
66
129
  export function validatePriority(priority: number): true | string {
67
130
  const result = PrioritySchema.safeParse(priority);
@@ -71,7 +134,19 @@ export function validatePriority(priority: number): true | string {
71
134
  }
72
135
 
73
136
  /**
74
- * Validate URL or URL pattern using Zod schema
137
+ * Validates a URL or URL pattern for functions
138
+ * Supports both full URLs (http/https) and path patterns (e.g., /api/*)
139
+ *
140
+ * @param {string} url - The URL or pattern to validate
141
+ * @returns {true | string} Returns true if valid, or an error message if invalid
142
+ * @example
143
+ * ```typescript
144
+ * validateUrl("https://api.example.com/webhook") // returns true
145
+ * validateUrl("/api/cart/*") // returns true (path pattern)
146
+ * validateUrl("/*") // returns true (wildcard pattern)
147
+ * validateUrl("ftp://example.com") // returns "URL must be a valid URL or path pattern"
148
+ * validateUrl("") // returns "URL is required"
149
+ * ```
75
150
  */
76
151
  export function validateUrl(url: string): true | string {
77
152
  const result = UrlSchema.safeParse(url);
@@ -81,7 +156,18 @@ export function validateUrl(url: string): true | string {
81
156
  }
82
157
 
83
158
  /**
84
- * Validate semantic version using Zod schema
159
+ * Validates a semantic version string
160
+ * Must follow semver format: MAJOR.MINOR.PATCH (e.g., 1.0.0)
161
+ *
162
+ * @param {string} version - The version string to validate
163
+ * @returns {true | string} Returns true if valid semver, or an error message if invalid
164
+ * @example
165
+ * ```typescript
166
+ * validateSemver("1.0.0") // returns true
167
+ * validateSemver("2.4.6") // returns true
168
+ * validateSemver("1.0") // returns "Version must follow semantic versioning format (e.g., 1.0.0)"
169
+ * validateSemver("v1.0.0") // returns "Version must follow semantic versioning format (e.g., 1.0.0)"
170
+ * ```
85
171
  */
86
172
  export function validateSemver(version: string): true | string {
87
173
  const result = SemverSchema.safeParse(version);
@@ -91,7 +177,19 @@ export function validateSemver(version: string): true | string {
91
177
  }
92
178
 
93
179
  /**
94
- * Process validation errors and display them to the user
180
+ * Processes and displays validation errors to the user
181
+ * Formats errors into a readable list with bullet points
182
+ *
183
+ * @param {Array<{message?: string} | string>} errors - Array of error objects or strings
184
+ * @param {CliConsole} cliConsole - Console instance for output
185
+ * @example
186
+ * ```typescript
187
+ * processValidationErrors(["Invalid name", {message: "Path not found"}], console);
188
+ * // Output:
189
+ * // Errors:
190
+ * // • Invalid name
191
+ * // • Path not found
192
+ * ```
95
193
  */
96
194
  export function processValidationErrors(
97
195
  errors: Array<{ message?: string } | string>,
@@ -105,7 +203,18 @@ export function processValidationErrors(
105
203
  }
106
204
 
107
205
  /**
108
- * Process validation warnings and display them to the user
206
+ * Processes and displays validation warnings to the user
207
+ * Formats warnings into a readable list with bullet points
208
+ *
209
+ * @param {Array<{message?: string} | string>} warnings - Array of warning objects or strings
210
+ * @param {CliConsole} cliConsole - Console instance for output
211
+ * @example
212
+ * ```typescript
213
+ * processValidationWarnings(["Deprecated feature used"], console);
214
+ * // Output:
215
+ * // Warnings:
216
+ * // • Deprecated feature used
217
+ * ```
109
218
  */
110
219
  export function processValidationWarnings(
111
220
  warnings: Array<{ message?: string } | string>,
@@ -120,7 +229,19 @@ export function processValidationWarnings(
120
229
  }
121
230
 
122
231
  /**
123
- * Handle validation result with spinner and console output
232
+ * Handles validation results by updating spinner state and displaying errors/warnings
233
+ * Central function for processing validation outcomes in CLI commands
234
+ *
235
+ * @param {ValidationResult | unknown} result - Validation result object or unknown type
236
+ * @param {SpinnerManager} spinner - Spinner instance to update visual feedback
237
+ * @param {CliConsole} cliConsole - Console instance for output
238
+ * @param {string} entityType - Type of entity being validated (e.g., "Component", "Function")
239
+ * @example
240
+ * ```typescript
241
+ * const result = await validateComponent(path);
242
+ * handleValidationResult(result, spinner, console, "Component");
243
+ * // Updates spinner to success/fail and displays any errors or warnings
244
+ * ```
124
245
  */
125
246
  export function handleValidationResult(
126
247
  result: ValidationResult | unknown,
@@ -140,7 +261,14 @@ export function handleValidationResult(
140
261
  }
141
262
 
142
263
  /**
143
- * Handle valid/invalid validation status
264
+ * Updates spinner state based on validation success/failure
265
+ * Internal helper for handleValidationResult
266
+ *
267
+ * @param {ValidationResult} result - Validation result with valid status
268
+ * @param {SpinnerManager} spinner - Spinner to update
269
+ * @param {CliConsole} cliConsole - Console for error output
270
+ * @param {string} entityType - Type of entity for messaging
271
+ * @private
144
272
  */
145
273
  function handleValidResult(
146
274
  result: ValidationResult,
@@ -159,7 +287,12 @@ function handleValidResult(
159
287
  }
160
288
 
161
289
  /**
162
- * Handle validation warnings display
290
+ * Displays validation warnings if present
291
+ * Internal helper for handleValidationResult
292
+ *
293
+ * @param {ValidationResult} result - Validation result potentially containing warnings
294
+ * @param {CliConsole} cliConsole - Console for warning output
295
+ * @private
163
296
  */
164
297
  function handleValidationWarnings(
165
298
  result: ValidationResult,
package/tsup.config.ts ADDED
@@ -0,0 +1,15 @@
1
+ import { defineConfig } from "tsup";
2
+
3
+ export default defineConfig({
4
+ entry: ["src/index.ts"],
5
+ bundle: true,
6
+ minify: false,
7
+ sourcemap: false,
8
+ format: ["cjs"],
9
+ clean: true,
10
+ dts: true,
11
+ treeshake: true,
12
+ platform: "node",
13
+ target: "node18",
14
+ noExternal: ["@ollie-shop/core"],
15
+ });
@@ -1,89 +0,0 @@
1
- import { Command } from "@commander-js/extra-typings";
2
- import { vi } from "vitest";
3
- /**
4
- * CLI Testing Helper for Commander.js applications
5
- * Based on best practices for testing CLI applications with Vitest
6
- */
7
- export interface CLITestResult {
8
- exitCode: number;
9
- stdout: string[];
10
- stderr: string[];
11
- error?: Error;
12
- }
13
- export interface ProcessMocks {
14
- exit: ReturnType<typeof vi.fn>;
15
- stdout: {
16
- write: ReturnType<typeof vi.fn>;
17
- };
18
- stderr: {
19
- write: ReturnType<typeof vi.fn>;
20
- };
21
- }
22
- export interface ConsoleMocks {
23
- log: ReturnType<typeof vi.fn>;
24
- error: ReturnType<typeof vi.fn>;
25
- warn: ReturnType<typeof vi.fn>;
26
- info: ReturnType<typeof vi.fn>;
27
- }
28
- /**
29
- * Create a test-friendly Commander.js program that captures output
30
- * and prevents process.exit from terminating the test
31
- */
32
- export declare function createTestProgram(): {
33
- program: Command;
34
- mocks: {
35
- process: ProcessMocks;
36
- console: ConsoleMocks;
37
- };
38
- getResult: () => CLITestResult;
39
- };
40
- /**
41
- * Execute a CLI command with arguments and capture the result
42
- */
43
- export declare function executeCLI(program: Command, args: string[], options?: {
44
- from: "node" | "electron" | "user";
45
- }): Promise<CLITestResult>;
46
- /**
47
- * Reset all CLI test mocks between tests
48
- */
49
- export declare function resetCLIMocks(): void;
50
- /**
51
- * Create mock for inquirer prompts
52
- */
53
- export declare function createInquirerMock(responses: Record<string, unknown>): {
54
- prompt: import("vitest").Mock<(...args: any[]) => any>;
55
- };
56
- /**
57
- * Create mock for ora spinner
58
- */
59
- export declare function createSpinnerMock(): {
60
- mock: {
61
- start: import("vitest").Mock<(...args: any[]) => any>;
62
- stop: import("vitest").Mock<(...args: any[]) => any>;
63
- succeed: import("vitest").Mock<(...args: any[]) => any>;
64
- fail: import("vitest").Mock<(...args: any[]) => any>;
65
- warn: import("vitest").Mock<(...args: any[]) => any>;
66
- info: import("vitest").Mock<(...args: any[]) => any>;
67
- text: string;
68
- isSpinning: boolean;
69
- };
70
- create: import("vitest").Mock<() => {
71
- start: import("vitest").Mock<(...args: any[]) => any>;
72
- stop: import("vitest").Mock<(...args: any[]) => any>;
73
- succeed: import("vitest").Mock<(...args: any[]) => any>;
74
- fail: import("vitest").Mock<(...args: any[]) => any>;
75
- warn: import("vitest").Mock<(...args: any[]) => any>;
76
- info: import("vitest").Mock<(...args: any[]) => any>;
77
- text: string;
78
- isSpinning: boolean;
79
- }>;
80
- };
81
- /**
82
- * Assert CLI output contains expected text
83
- */
84
- export declare function expectCLIOutput(result: CLITestResult, expected: {
85
- stdout?: string | RegExp;
86
- stderr?: string | RegExp;
87
- exitCode?: number;
88
- }): void;
89
- //# sourceMappingURL=cli-test-helper.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli-test-helper.d.ts","sourceRoot":"","sources":["../../../src/__tests__/helpers/cli-test-helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AACtD,OAAO,EAAU,EAAE,EAAE,MAAM,QAAQ,CAAC;AAEpC;;;GAGG;AAEH,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAC/B,MAAM,EAAE;QACN,KAAK,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;KACjC,CAAC;IACF,MAAM,EAAE;QACN,KAAK,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;KACjC,CAAC;CACH;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,KAAK,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAChC,IAAI,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAC/B,IAAI,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;CAChC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE;QACL,OAAO,EAAE,YAAY,CAAC;QACtB,OAAO,EAAE,YAAY,CAAC;KACvB,CAAC;IACF,SAAS,EAAE,MAAM,aAAa,CAAC;CAChC,CAgGA;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,GAAE;IAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAAA;CAAqB,GACjE,OAAO,CAAC,aAAa,CAAC,CAgDxB;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAGpC;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;EAgBpE;AAED;;GAEG;AACH,wBAAgB,iBAAiB;;;;;;;;;;;;;;;;;;;;;EAgBhC;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE;IACR,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,QAuBF"}
@@ -1,220 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createTestProgram = createTestProgram;
4
- exports.executeCLI = executeCLI;
5
- exports.resetCLIMocks = resetCLIMocks;
6
- exports.createInquirerMock = createInquirerMock;
7
- exports.createSpinnerMock = createSpinnerMock;
8
- exports.expectCLIOutput = expectCLIOutput;
9
- const extra_typings_1 = require("@commander-js/extra-typings");
10
- const vitest_1 = require("vitest");
11
- /**
12
- * Create a test-friendly Commander.js program that captures output
13
- * and prevents process.exit from terminating the test
14
- */
15
- function createTestProgram() {
16
- const stdout = [];
17
- const stderr = [];
18
- let exitCode = 0;
19
- let capturedError;
20
- // Mock process methods
21
- const processMocks = {
22
- exit: vitest_1.vi.fn((code = 0) => {
23
- exitCode = code;
24
- // Throw error instead of exiting to prevent test termination
25
- throw new Error(`process.exit(${code})`);
26
- }),
27
- stdout: {
28
- write: vitest_1.vi.fn((data) => {
29
- stdout.push(data);
30
- return true;
31
- }),
32
- },
33
- stderr: {
34
- write: vitest_1.vi.fn((data) => {
35
- stderr.push(data);
36
- return true;
37
- }),
38
- },
39
- };
40
- // Mock console methods
41
- const consoleMocks = {
42
- log: vitest_1.vi.fn((...args) => {
43
- stdout.push(`${args.join(" ")}\n`);
44
- }),
45
- error: vitest_1.vi.fn((...args) => {
46
- stderr.push(`${args.join(" ")}\n`);
47
- }),
48
- warn: vitest_1.vi.fn((...args) => {
49
- stderr.push(`${args.join(" ")}\n`);
50
- }),
51
- info: vitest_1.vi.fn((...args) => {
52
- stdout.push(`${args.join(" ")}\n`);
53
- }),
54
- };
55
- // Apply mocks
56
- vitest_1.vi.spyOn(process, "exit").mockImplementation(((code) => {
57
- throw new Error(`Process exit with code ${code}`);
58
- }));
59
- vitest_1.vi.spyOn(process.stdout, "write").mockImplementation(processMocks.stdout.write);
60
- vitest_1.vi.spyOn(process.stderr, "write").mockImplementation(processMocks.stderr.write);
61
- vitest_1.vi.spyOn(console, "log").mockImplementation(consoleMocks.log);
62
- vitest_1.vi.spyOn(console, "error").mockImplementation(consoleMocks.error);
63
- vitest_1.vi.spyOn(console, "warn").mockImplementation(consoleMocks.warn);
64
- vitest_1.vi.spyOn(console, "info").mockImplementation(consoleMocks.info);
65
- // Also mock global.console which is used by the CLI console utility
66
- vitest_1.vi.spyOn(global.console, "log").mockImplementation(consoleMocks.log);
67
- vitest_1.vi.spyOn(global.console, "error").mockImplementation(consoleMocks.error);
68
- vitest_1.vi.spyOn(global.console, "warn").mockImplementation(consoleMocks.warn);
69
- vitest_1.vi.spyOn(global.console, "info").mockImplementation(consoleMocks.info);
70
- // Create program with exitOverride to handle errors gracefully
71
- const program = new extra_typings_1.Command();
72
- program
73
- .exitOverride((err) => {
74
- capturedError = err;
75
- exitCode = err.exitCode || 1;
76
- throw err;
77
- })
78
- .configureOutput({
79
- writeOut: (str) => {
80
- stdout.push(str);
81
- },
82
- writeErr: (str) => {
83
- stderr.push(str);
84
- },
85
- });
86
- const getResult = () => ({
87
- exitCode,
88
- stdout: [...stdout],
89
- stderr: [...stderr],
90
- error: capturedError,
91
- });
92
- return {
93
- program,
94
- mocks: {
95
- process: processMocks,
96
- console: consoleMocks,
97
- },
98
- getResult,
99
- };
100
- }
101
- /**
102
- * Execute a CLI command with arguments and capture the result
103
- */
104
- async function executeCLI(program, args, options = { from: "user" }) {
105
- const stdout = [];
106
- const stderr = [];
107
- let exitCode = 0;
108
- let capturedError;
109
- // Capture output
110
- const originalWriteOut = program.configureOutput().writeOut;
111
- const originalWriteErr = program.configureOutput().writeErr;
112
- program.configureOutput({
113
- writeOut: (str) => {
114
- stdout.push(str);
115
- if (originalWriteOut)
116
- originalWriteOut(str);
117
- },
118
- writeErr: (str) => {
119
- stderr.push(str);
120
- if (originalWriteErr)
121
- originalWriteErr(str);
122
- },
123
- });
124
- try {
125
- await program.parseAsync(args, options);
126
- }
127
- catch (error) {
128
- capturedError = error;
129
- // Handle Commander.js specific errors
130
- if (error && typeof error === "object" && "code" in error) {
131
- const commanderError = error;
132
- exitCode = commanderError.exitCode || 1;
133
- }
134
- else if (error instanceof Error &&
135
- error.message.includes("process.exit")) {
136
- // Handle our mocked process.exit
137
- const match = error.message.match(/process\.exit\((\d+)\)/);
138
- exitCode = match?.[1] ? Number.parseInt(match[1], 10) : 1;
139
- }
140
- else {
141
- exitCode = 1;
142
- }
143
- }
144
- return {
145
- exitCode,
146
- stdout,
147
- stderr,
148
- error: capturedError,
149
- };
150
- }
151
- /**
152
- * Reset all CLI test mocks between tests
153
- */
154
- function resetCLIMocks() {
155
- vitest_1.vi.clearAllMocks();
156
- vitest_1.vi.restoreAllMocks();
157
- }
158
- /**
159
- * Create mock for inquirer prompts
160
- */
161
- function createInquirerMock(responses) {
162
- return {
163
- prompt: vitest_1.vi
164
- .fn()
165
- .mockImplementation((questions) => {
166
- const answers = {};
167
- for (const question of questions) {
168
- if (question.name && responses[question.name] !== undefined) {
169
- answers[question.name] = responses[question.name];
170
- }
171
- }
172
- return Promise.resolve(answers);
173
- }),
174
- };
175
- }
176
- /**
177
- * Create mock for ora spinner
178
- */
179
- function createSpinnerMock() {
180
- const mock = {
181
- start: vitest_1.vi.fn().mockReturnThis(),
182
- stop: vitest_1.vi.fn().mockReturnThis(),
183
- succeed: vitest_1.vi.fn().mockReturnThis(),
184
- fail: vitest_1.vi.fn().mockReturnThis(),
185
- warn: vitest_1.vi.fn().mockReturnThis(),
186
- info: vitest_1.vi.fn().mockReturnThis(),
187
- text: "",
188
- isSpinning: false,
189
- };
190
- return {
191
- mock,
192
- create: vitest_1.vi.fn(() => mock),
193
- };
194
- }
195
- /**
196
- * Assert CLI output contains expected text
197
- */
198
- function expectCLIOutput(result, expected) {
199
- if (expected.exitCode !== undefined) {
200
- (0, vitest_1.expect)(result.exitCode).toBe(expected.exitCode);
201
- }
202
- if (expected.stdout !== undefined) {
203
- const stdoutText = result.stdout.join("");
204
- if (typeof expected.stdout === "string") {
205
- (0, vitest_1.expect)(stdoutText).toContain(expected.stdout);
206
- }
207
- else {
208
- (0, vitest_1.expect)(stdoutText).toMatch(expected.stdout);
209
- }
210
- }
211
- if (expected.stderr !== undefined) {
212
- const stderrText = result.stderr.join("");
213
- if (typeof expected.stderr === "string") {
214
- (0, vitest_1.expect)(stderrText).toContain(expected.stderr);
215
- }
216
- else {
217
- (0, vitest_1.expect)(stderrText).toMatch(expected.stderr);
218
- }
219
- }
220
- }