pnpm-catalog-updates 0.7.19 → 1.0.0

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.
@@ -5,42 +5,46 @@
5
5
  * Provides consistent option parsing and validation.
6
6
  */
7
7
 
8
- import { Option } from 'commander';
8
+ import { Option } from 'commander'
9
9
 
10
10
  export interface GlobalCliOptions {
11
- workspace?: string;
12
- verbose?: boolean;
13
- color?: boolean;
14
- registry?: string;
15
- timeout?: number;
16
- config?: string;
11
+ workspace?: string
12
+ verbose?: boolean
13
+ color?: boolean
14
+ registry?: string
15
+ timeout?: number
16
+ config?: string
17
17
  }
18
18
 
19
19
  export interface CheckCliOptions extends GlobalCliOptions {
20
- catalog?: string;
21
- format?: 'table' | 'json' | 'yaml' | 'minimal';
22
- target?: 'latest' | 'greatest' | 'minor' | 'patch' | 'newest';
23
- prerelease?: boolean;
24
- include?: string[];
25
- exclude?: string[];
20
+ catalog?: string
21
+ format?: 'table' | 'json' | 'yaml' | 'minimal'
22
+ target?: 'latest' | 'greatest' | 'minor' | 'patch' | 'newest'
23
+ prerelease?: boolean
24
+ include?: string[]
25
+ exclude?: string[]
26
26
  }
27
27
 
28
28
  export interface UpdateCliOptions extends CheckCliOptions {
29
- interactive?: boolean;
30
- dryRun?: boolean;
31
- force?: boolean;
32
- createBackup?: boolean;
29
+ interactive?: boolean
30
+ dryRun?: boolean
31
+ force?: boolean
32
+ createBackup?: boolean
33
33
  }
34
34
 
35
35
  export interface AnalyzeCliOptions extends GlobalCliOptions {
36
- format?: 'table' | 'json' | 'yaml' | 'minimal';
36
+ format?: 'table' | 'json' | 'yaml' | 'minimal'
37
+ ai?: boolean
38
+ provider?: 'auto' | 'claude' | 'gemini' | 'codex'
39
+ analysisType?: 'impact' | 'security' | 'compatibility' | 'recommend'
40
+ skipCache?: boolean
37
41
  }
38
42
 
39
43
  export interface WorkspaceCliOptions extends GlobalCliOptions {
40
- validate?: boolean;
41
- stats?: boolean;
42
- info?: boolean;
43
- format?: 'table' | 'json' | 'yaml' | 'minimal';
44
+ validate?: boolean
45
+ stats?: boolean
46
+ info?: boolean
47
+ format?: 'table' | 'json' | 'yaml' | 'minimal'
44
48
  }
45
49
 
46
50
  /**
@@ -60,7 +64,7 @@ export const globalOptions = [
60
64
  .env('PCU_TIMEOUT'),
61
65
 
62
66
  new Option('--config <path>', 'path to configuration file').env('PCU_CONFIG'),
63
- ];
67
+ ]
64
68
 
65
69
  /**
66
70
  * Check command specific options
@@ -85,7 +89,7 @@ export const checkOptions = [
85
89
  new Option('--include <pattern...>', 'include packages matching pattern').env('PCU_INCLUDE'),
86
90
 
87
91
  new Option('--exclude <pattern...>', 'exclude packages matching pattern').env('PCU_EXCLUDE'),
88
- ];
92
+ ]
89
93
 
90
94
  /**
91
95
  * Update command specific options
@@ -100,7 +104,7 @@ export const updateOptions = [
100
104
  new Option('--force', 'force updates even if risky').env('PCU_FORCE'),
101
105
 
102
106
  new Option('--create-backup', 'create backup files before updating').env('PCU_CREATE_BACKUP'),
103
- ];
107
+ ]
104
108
 
105
109
  /**
106
110
  * Analyze command specific options
@@ -112,7 +116,21 @@ export const analyzeOptions = [
112
116
  .choices(['table', 'json', 'yaml', 'minimal'])
113
117
  .default('table')
114
118
  .env('PCU_OUTPUT_FORMAT'),
115
- ];
119
+
120
+ new Option('--ai', 'enable AI-powered analysis').env('PCU_AI_ENABLED'),
121
+
122
+ new Option('--provider <name>', 'AI provider to use')
123
+ .choices(['auto', 'claude', 'gemini', 'codex'])
124
+ .default('auto')
125
+ .env('PCU_AI_PROVIDER'),
126
+
127
+ new Option('--analysis-type <type>', 'type of AI analysis')
128
+ .choices(['impact', 'security', 'compatibility', 'recommend'])
129
+ .default('impact')
130
+ .env('PCU_AI_ANALYSIS_TYPE'),
131
+
132
+ new Option('--skip-cache', 'skip AI analysis cache').env('PCU_AI_SKIP_CACHE'),
133
+ ]
116
134
 
117
135
  /**
118
136
  * Workspace command specific options
@@ -130,7 +148,7 @@ export const workspaceOptions = [
130
148
  .choices(['table', 'json', 'yaml', 'minimal'])
131
149
  .default('table')
132
150
  .env('PCU_OUTPUT_FORMAT'),
133
- ];
151
+ ]
134
152
 
135
153
  /**
136
154
  * Option groups for better help organization
@@ -178,203 +196,242 @@ export const optionGroups = {
178
196
  new Option('--timeout <ms>', 'request timeout').argParser(parseInt),
179
197
  ],
180
198
  },
181
- };
199
+ }
182
200
 
183
201
  /**
184
202
  * Utility functions for option handling
185
203
  */
186
204
  export class OptionUtils {
205
+ private static parseBoolean(value: unknown): boolean {
206
+ if (value === undefined || value === null) return false
207
+ if (typeof value === 'boolean') return value
208
+ if (typeof value === 'number') return value !== 0
209
+ if (typeof value === 'string') {
210
+ const normalized = value.trim().toLowerCase()
211
+ if (normalized === '') return false
212
+ if (['false', '0', 'no', 'off', 'n'].includes(normalized)) return false
213
+ if (['true', '1', 'yes', 'on', 'y'].includes(normalized)) return true
214
+ return true
215
+ }
216
+ return Boolean(value)
217
+ }
218
+
187
219
  /**
188
220
  * Parse and validate global options
189
221
  */
190
222
  static parseGlobalOptions(options: any): GlobalCliOptions {
191
- const parsed: GlobalCliOptions = {};
223
+ const parsed: GlobalCliOptions = {}
192
224
 
193
225
  if (options.workspace) {
194
- parsed.workspace = String(options.workspace).trim();
226
+ parsed.workspace = String(options.workspace).trim()
195
227
  }
196
228
 
197
229
  if (options.verbose !== undefined) {
198
- parsed.verbose = Boolean(options.verbose);
230
+ parsed.verbose = OptionUtils.parseBoolean(options.verbose)
199
231
  }
200
232
 
201
233
  if (options.color !== undefined) {
202
- parsed.color = Boolean(options.color);
234
+ parsed.color = OptionUtils.parseBoolean(options.color)
203
235
  }
204
236
 
205
237
  if (options.registry) {
206
- parsed.registry = String(options.registry).trim();
238
+ parsed.registry = String(options.registry).trim()
207
239
  }
208
240
 
209
241
  if (options.timeout) {
210
- const timeout = parseInt(String(options.timeout), 10);
211
- if (!isNaN(timeout) && timeout > 0) {
212
- parsed.timeout = timeout;
242
+ const timeout = parseInt(String(options.timeout), 10)
243
+ if (!Number.isNaN(timeout) && timeout > 0) {
244
+ parsed.timeout = timeout
213
245
  }
214
246
  }
215
247
 
216
248
  if (options.config) {
217
- parsed.config = String(options.config).trim();
249
+ parsed.config = String(options.config).trim()
218
250
  }
219
251
 
220
- return parsed;
252
+ return parsed
221
253
  }
222
254
 
223
255
  /**
224
256
  * Parse check command options
225
257
  */
226
258
  static parseCheckOptions(options: any): CheckCliOptions {
227
- const global = this.parseGlobalOptions(options);
228
- const check: CheckCliOptions = { ...global };
259
+ const global = OptionUtils.parseGlobalOptions(options)
260
+ const check: CheckCliOptions = { ...global }
229
261
 
230
262
  if (options.catalog) {
231
- check.catalog = String(options.catalog).trim();
263
+ check.catalog = String(options.catalog).trim()
232
264
  }
233
265
 
234
266
  if (options.format && typeof options.format === 'string') {
235
- check.format = options.format as Exclude<CheckCliOptions['format'], undefined>;
267
+ check.format = options.format as Exclude<CheckCliOptions['format'], undefined>
236
268
  }
237
269
 
238
270
  if (options.target && typeof options.target === 'string') {
239
- check.target = options.target as Exclude<CheckCliOptions['target'], undefined>;
271
+ check.target = options.target as Exclude<CheckCliOptions['target'], undefined>
240
272
  }
241
273
 
242
274
  if (options.prerelease !== undefined) {
243
- check.prerelease = Boolean(options.prerelease);
275
+ check.prerelease = OptionUtils.parseBoolean(options.prerelease)
244
276
  }
245
277
 
246
278
  if (options.include) {
247
279
  check.include = Array.isArray(options.include)
248
280
  ? options.include.map((p: any) => String(p).trim()).filter(Boolean)
249
- : [String(options.include).trim()].filter(Boolean);
281
+ : [String(options.include).trim()].filter(Boolean)
250
282
  }
251
283
 
252
284
  if (options.exclude) {
253
285
  check.exclude = Array.isArray(options.exclude)
254
286
  ? options.exclude.map((p: any) => String(p).trim()).filter(Boolean)
255
- : [String(options.exclude).trim()].filter(Boolean);
287
+ : [String(options.exclude).trim()].filter(Boolean)
256
288
  }
257
289
 
258
- return check;
290
+ return check
259
291
  }
260
292
 
261
293
  /**
262
294
  * Parse update command options
263
295
  */
264
296
  static parseUpdateOptions(options: any): UpdateCliOptions {
265
- const check = this.parseCheckOptions(options);
266
- const update: UpdateCliOptions = { ...check };
297
+ const check = OptionUtils.parseCheckOptions(options)
298
+ const update: UpdateCliOptions = { ...check }
267
299
 
268
300
  if (options.interactive !== undefined) {
269
- update.interactive = Boolean(options.interactive);
301
+ update.interactive = OptionUtils.parseBoolean(options.interactive)
270
302
  }
271
303
 
272
304
  if (options.dryRun !== undefined) {
273
- update.dryRun = Boolean(options.dryRun);
305
+ update.dryRun = OptionUtils.parseBoolean(options.dryRun)
274
306
  }
275
307
 
276
308
  if (options.force !== undefined) {
277
- update.force = Boolean(options.force);
309
+ update.force = OptionUtils.parseBoolean(options.force)
278
310
  }
279
311
 
280
312
  if (options.createBackup !== undefined) {
281
- update.createBackup = Boolean(options.createBackup);
313
+ update.createBackup = OptionUtils.parseBoolean(options.createBackup)
282
314
  }
283
315
 
284
- return update;
316
+ return update
285
317
  }
286
318
 
287
319
  /**
288
320
  * Parse analyze command options
289
321
  */
290
322
  static parseAnalyzeOptions(options: any): AnalyzeCliOptions {
291
- const global = this.parseGlobalOptions(options);
292
- const analyze: AnalyzeCliOptions = { ...global };
323
+ const global = OptionUtils.parseGlobalOptions(options)
324
+ const analyze: AnalyzeCliOptions = { ...global }
293
325
 
294
326
  if (options.format && typeof options.format === 'string') {
295
- analyze.format = options.format as Exclude<AnalyzeCliOptions['format'], undefined>;
327
+ analyze.format = options.format as Exclude<AnalyzeCliOptions['format'], undefined>
296
328
  }
297
329
 
298
- return analyze;
330
+ if (options.ai !== undefined) {
331
+ analyze.ai = OptionUtils.parseBoolean(options.ai)
332
+ }
333
+
334
+ if (options.provider && typeof options.provider === 'string') {
335
+ analyze.provider = options.provider as Exclude<AnalyzeCliOptions['provider'], undefined>
336
+ }
337
+
338
+ if (options.analysisType && typeof options.analysisType === 'string') {
339
+ analyze.analysisType = options.analysisType as Exclude<
340
+ AnalyzeCliOptions['analysisType'],
341
+ undefined
342
+ >
343
+ }
344
+
345
+ if (options.skipCache !== undefined) {
346
+ analyze.skipCache = OptionUtils.parseBoolean(options.skipCache)
347
+ }
348
+
349
+ return analyze
299
350
  }
300
351
 
301
352
  /**
302
353
  * Parse workspace command options
303
354
  */
304
355
  static parseWorkspaceOptions(options: any): WorkspaceCliOptions {
305
- const global = this.parseGlobalOptions(options);
306
- const workspace: WorkspaceCliOptions = { ...global };
356
+ const global = OptionUtils.parseGlobalOptions(options)
357
+ const workspace: WorkspaceCliOptions = { ...global }
307
358
 
308
359
  if (options.validate !== undefined) {
309
- workspace.validate = Boolean(options.validate);
360
+ workspace.validate = OptionUtils.parseBoolean(options.validate)
310
361
  }
311
362
 
312
363
  if (options.stats !== undefined) {
313
- workspace.stats = Boolean(options.stats);
364
+ workspace.stats = OptionUtils.parseBoolean(options.stats)
314
365
  }
315
366
 
316
367
  if (options.info !== undefined) {
317
- workspace.info = Boolean(options.info);
368
+ workspace.info = OptionUtils.parseBoolean(options.info)
318
369
  }
319
370
 
320
371
  if (options.format && typeof options.format === 'string') {
321
- workspace.format = options.format as Exclude<WorkspaceCliOptions['format'], undefined>;
372
+ workspace.format = options.format as Exclude<WorkspaceCliOptions['format'], undefined>
322
373
  }
323
374
 
324
- return workspace;
375
+ return workspace
325
376
  }
326
377
 
327
378
  /**
328
379
  * Generate help text for option group
329
380
  */
330
381
  static generateHelpText(groupName: keyof typeof optionGroups): string {
331
- const group = optionGroups[groupName];
332
- if (!group) return '';
382
+ const group = optionGroups[groupName]
383
+ if (!group) return ''
333
384
 
334
- const lines = [`${group.title}:`];
385
+ const lines = [`${group.title}:`]
335
386
 
336
387
  for (const option of group.options) {
337
- const flags = option.flags;
338
- const description = option.description || '';
339
- const choices = option.argChoices ? ` (choices: ${option.argChoices.join(', ')})` : '';
340
- const defaultValue = option.defaultValue ? ` (default: ${option.defaultValue})` : '';
388
+ const flags = option.flags
389
+ const description = option.description || ''
390
+ const choices = option.argChoices ? ` (choices: ${option.argChoices.join(', ')})` : ''
391
+ const defaultValue = option.defaultValue ? ` (default: ${option.defaultValue})` : ''
341
392
 
342
- lines.push(` ${flags.padEnd(30)} ${description}${choices}${defaultValue}`);
393
+ lines.push(` ${flags.padEnd(30)} ${description}${choices}${defaultValue}`)
343
394
  }
344
395
 
345
- return lines.join('\n');
396
+ return lines.join('\n')
346
397
  }
347
398
 
348
399
  /**
349
400
  * Validate option combinations
350
401
  */
351
402
  static validateOptionCombinations(command: string, options: any): string[] {
352
- const errors: string[] = [];
403
+ const errors: string[] = []
353
404
 
354
405
  switch (command) {
355
406
  case 'update':
356
- if (options.interactive && options.dryRun) {
357
- errors.push('Cannot use --interactive with --dry-run');
407
+ if (
408
+ OptionUtils.parseBoolean(options.interactive) &&
409
+ OptionUtils.parseBoolean(options.dryRun)
410
+ ) {
411
+ errors.push('Cannot use --interactive with --dry-run')
358
412
  }
359
- break;
413
+ break
360
414
 
361
- case 'workspace':
362
- const actionCount = [options.validate, options.stats, options.info].filter(Boolean).length;
415
+ case 'workspace': {
416
+ const actionCount = [options.validate, options.stats, options.info].filter((v) =>
417
+ OptionUtils.parseBoolean(v)
418
+ ).length
363
419
  if (actionCount > 1) {
364
- errors.push('Cannot use multiple workspace actions simultaneously');
420
+ errors.push('Cannot use multiple workspace actions simultaneously')
365
421
  }
366
422
  if (actionCount === 0) {
367
423
  // Default to info
368
- options.info = true;
424
+ options.info = true
369
425
  }
370
- break;
426
+ break
427
+ }
371
428
  }
372
429
 
373
430
  // Global validations
374
- if (options.verbose && options.silent) {
375
- errors.push('Cannot use both --verbose and --silent');
431
+ if (OptionUtils.parseBoolean(options.verbose) && OptionUtils.parseBoolean(options.silent)) {
432
+ errors.push('Cannot use both --verbose and --silent')
376
433
  }
377
434
 
378
- return errors;
435
+ return errors
379
436
  }
380
437
  }
@@ -2,4 +2,4 @@
2
2
  * CLI Options Entry Point
3
3
  */
4
4
 
5
- export * from './globalOptions.js';
5
+ export * from './globalOptions.js'