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.
@@ -4,22 +4,22 @@
4
4
  * Provides smart prompts and auto-completion for CLI commands
5
5
  */
6
6
 
7
- import { FileSystemService } from '@pcu/core';
8
- import chalk from 'chalk';
9
- import inquirer from 'inquirer';
10
- import { StyledText } from '../themes/colorTheme.js';
7
+ import { FileSystemService } from '@pcu/core'
8
+ import chalk from 'chalk'
9
+ import inquirer from 'inquirer'
10
+ import { StyledText } from '../themes/colorTheme.js'
11
11
 
12
12
  export interface AutoCompleteOption {
13
- name: string;
14
- value: string;
15
- description?: string;
13
+ name: string
14
+ value: string
15
+ description?: string
16
16
  }
17
17
 
18
18
  export class InteractivePrompts {
19
- private fsService: FileSystemService;
19
+ private fsService: FileSystemService
20
20
 
21
21
  constructor() {
22
- this.fsService = new FileSystemService();
22
+ this.fsService = new FileSystemService()
23
23
  }
24
24
 
25
25
  /**
@@ -29,14 +29,14 @@ export class InteractivePrompts {
29
29
  packages: Array<{ name: string; current: string; latest: string; type: string }>
30
30
  ): Promise<string[]> {
31
31
  if (packages.length === 0) {
32
- return [];
32
+ return []
33
33
  }
34
34
 
35
35
  const choices = packages.map((pkg) => ({
36
36
  name: this.formatPackageChoice(pkg),
37
37
  value: pkg.name,
38
38
  checked: false,
39
- }));
39
+ }))
40
40
 
41
41
  const answers = await inquirer.prompt({
42
42
  type: 'checkbox',
@@ -45,12 +45,12 @@ export class InteractivePrompts {
45
45
  choices,
46
46
  pageSize: 15,
47
47
  validate: (input: unknown) => {
48
- const selected = input as string[];
49
- return selected.length > 0 || 'Please select at least one package';
48
+ const selected = input as string[]
49
+ return selected.length > 0 || 'Please select at least one package'
50
50
  },
51
- });
51
+ })
52
52
 
53
- return answers.selectedPackages;
53
+ return answers.selectedPackages
54
54
  }
55
55
 
56
56
  /**
@@ -58,17 +58,17 @@ export class InteractivePrompts {
58
58
  */
59
59
  async selectCatalog(catalogs: string[]): Promise<string | null> {
60
60
  if (catalogs.length === 0) {
61
- return null;
61
+ return null
62
62
  }
63
63
 
64
64
  if (catalogs.length === 1) {
65
- return catalogs[0] ?? null;
65
+ return catalogs[0] ?? null
66
66
  }
67
67
 
68
68
  const choices = [
69
69
  { name: 'All catalogs', value: 'all' },
70
70
  ...catalogs.map((name) => ({ name, value: name })),
71
- ];
71
+ ]
72
72
 
73
73
  const answers = await inquirer.prompt([
74
74
  {
@@ -78,9 +78,9 @@ export class InteractivePrompts {
78
78
  choices,
79
79
  pageSize: 10,
80
80
  },
81
- ]);
81
+ ])
82
82
 
83
- return answers.catalog === 'all' ? null : answers.catalog;
83
+ return answers.catalog === 'all' ? null : answers.catalog
84
84
  }
85
85
 
86
86
  /**
@@ -93,7 +93,7 @@ export class InteractivePrompts {
93
93
  { name: 'Minor (non-breaking)', value: 'minor' },
94
94
  { name: 'Patch (bug fixes only)', value: 'patch' },
95
95
  { name: 'Newest (latest release)', value: 'newest' },
96
- ];
96
+ ]
97
97
 
98
98
  const answers = await inquirer.prompt([
99
99
  {
@@ -102,18 +102,18 @@ export class InteractivePrompts {
102
102
  message: StyledText.iconUpdate('Select update strategy:'),
103
103
  choices: strategies,
104
104
  },
105
- ]);
105
+ ])
106
106
 
107
- return answers.strategy;
107
+ return answers.strategy
108
108
  }
109
109
 
110
110
  /**
111
111
  * Confirm dangerous operations
112
112
  */
113
113
  async confirmDangerousOperation(operation: string, details?: string): Promise<boolean> {
114
- console.log('');
114
+ console.log('')
115
115
  if (details) {
116
- console.log(chalk.yellow('⚠️ Warning:'), details);
116
+ console.log(chalk.yellow('⚠️ Warning:'), details)
117
117
  }
118
118
 
119
119
  const answers = await inquirer.prompt([
@@ -123,9 +123,9 @@ export class InteractivePrompts {
123
123
  message: StyledText.warning(`Are you sure you want to ${operation}?`),
124
124
  default: false,
125
125
  },
126
- ]);
126
+ ])
127
127
 
128
- return answers.confirmed;
128
+ return answers.confirmed
129
129
  }
130
130
 
131
131
  /**
@@ -143,20 +143,20 @@ export class InteractivePrompts {
143
143
  choices: packages.map((pkg) => ({ name: pkg, value: pkg })),
144
144
  pageSize: 10,
145
145
  },
146
- ]);
146
+ ])
147
147
 
148
- return answers.package;
148
+ return answers.package
149
149
  }
150
150
 
151
151
  /**
152
152
  * Workspace path selection with auto-complete
153
153
  */
154
154
  async selectWorkspacePath(): Promise<string> {
155
- const currentDir = process.cwd();
155
+ const currentDir = process.cwd()
156
156
  const choices = [
157
157
  { name: `Current directory (${currentDir})`, value: currentDir },
158
158
  { name: 'Browse for directory...', value: 'browse' },
159
- ];
159
+ ]
160
160
 
161
161
  const answers = await inquirer.prompt([
162
162
  {
@@ -165,20 +165,20 @@ export class InteractivePrompts {
165
165
  message: StyledText.icon('📁', 'Select workspace directory:'),
166
166
  choices,
167
167
  },
168
- ]);
168
+ ])
169
169
 
170
170
  if (answers.path === 'browse') {
171
- return this.browseDirectory();
171
+ return this.browseDirectory()
172
172
  }
173
173
 
174
- return answers.path;
174
+ return answers.path
175
175
  }
176
176
 
177
177
  /**
178
178
  * Browse directory structure
179
179
  */
180
180
  private async browseDirectory(currentPath = process.cwd()): Promise<string> {
181
- const directoryNames = await this.fsService.listDirectories(currentPath);
181
+ const directoryNames = await this.fsService.listDirectories(currentPath)
182
182
  const choices = [
183
183
  { name: '.. (parent directory)', value: '..' },
184
184
  { name: `. (current: ${currentPath})`, value: '.' },
@@ -186,7 +186,7 @@ export class InteractivePrompts {
186
186
  name: `📁 ${name}`,
187
187
  value: `${currentPath}/${name}`,
188
188
  })),
189
- ];
189
+ ]
190
190
 
191
191
  const answers = await inquirer.prompt([
192
192
  {
@@ -196,24 +196,24 @@ export class InteractivePrompts {
196
196
  choices,
197
197
  pageSize: 15,
198
198
  },
199
- ]);
199
+ ])
200
200
 
201
201
  if (answers.selected === '.') {
202
- return currentPath;
202
+ return currentPath
203
203
  }
204
204
 
205
205
  if (answers.selected === '..') {
206
- const parent = currentPath.split('/').slice(0, -1).join('/') || '/';
207
- return this.browseDirectory(parent);
206
+ const parent = currentPath.split('/').slice(0, -1).join('/') || '/'
207
+ return this.browseDirectory(parent)
208
208
  }
209
209
 
210
210
  // Check if this directory contains a pnpm workspace
211
- const workspaceFiles = ['pnpm-workspace.yaml', 'pnpm-workspace.yml'];
212
- let hasWorkspace = false;
211
+ const workspaceFiles = ['pnpm-workspace.yaml', 'pnpm-workspace.yml']
212
+ let hasWorkspace = false
213
213
  for (const file of workspaceFiles) {
214
214
  if (await this.fsService.exists(`${answers.selected}/${file}`)) {
215
- hasWorkspace = true;
216
- break;
215
+ hasWorkspace = true
216
+ break
217
217
  }
218
218
  }
219
219
 
@@ -225,21 +225,21 @@ export class InteractivePrompts {
225
225
  message: `Use ${answers.selected} as workspace?`,
226
226
  default: true,
227
227
  },
228
- ]);
228
+ ])
229
229
 
230
230
  if (confirm.useThis) {
231
- return answers.selected;
231
+ return answers.selected
232
232
  }
233
233
  }
234
234
 
235
- return this.browseDirectory(answers.selected);
235
+ return this.browseDirectory(answers.selected)
236
236
  }
237
237
 
238
238
  /**
239
239
  * Multi-step configuration wizard
240
240
  */
241
241
  async configurationWizard(): Promise<any> {
242
- console.log(chalk.bold.blue('\n🧙‍♂️ Configuration Wizard\n'));
242
+ console.log(chalk.bold.blue('\n🧙‍♂️ Configuration Wizard\n'))
243
243
 
244
244
  const themeAnswer = await inquirer.prompt({
245
245
  type: 'list',
@@ -252,21 +252,21 @@ export class InteractivePrompts {
252
252
  { name: 'Neon - High contrast', value: 'neon' },
253
253
  ],
254
254
  default: 'default',
255
- });
255
+ })
256
256
 
257
257
  const interactiveAnswer = await inquirer.prompt({
258
258
  type: 'confirm',
259
259
  name: 'interactive',
260
260
  message: 'Enable interactive mode by default?',
261
261
  default: true,
262
- });
262
+ })
263
263
 
264
264
  const backupAnswer = await inquirer.prompt({
265
265
  type: 'confirm',
266
266
  name: 'backup',
267
267
  message: 'Create backups before updates?',
268
268
  default: true,
269
- });
269
+ })
270
270
 
271
271
  const strategyAnswer = await inquirer.prompt({
272
272
  type: 'list',
@@ -278,7 +278,7 @@ export class InteractivePrompts {
278
278
  { name: 'Patch updates (bug fixes)', value: 'patch' },
279
279
  ],
280
280
  default: 'latest',
281
- });
281
+ })
282
282
 
283
283
  const timeoutAnswer = await inquirer.prompt({
284
284
  type: 'number',
@@ -286,10 +286,10 @@ export class InteractivePrompts {
286
286
  message: 'Network timeout (seconds):',
287
287
  default: 30,
288
288
  validate: (input: number | undefined) => {
289
- if (input === undefined) return 'Timeout is required';
290
- return input > 0 || 'Timeout must be positive';
289
+ if (input === undefined) return 'Timeout is required'
290
+ return input > 0 || 'Timeout must be positive'
291
291
  },
292
- });
292
+ })
293
293
 
294
294
  const answers = {
295
295
  ...themeAnswer,
@@ -297,27 +297,27 @@ export class InteractivePrompts {
297
297
  ...backupAnswer,
298
298
  ...strategyAnswer,
299
299
  ...timeoutAnswer,
300
- };
300
+ }
301
301
 
302
- return answers;
302
+ return answers
303
303
  }
304
304
 
305
305
  /**
306
306
  * Impact preview before update
307
307
  */
308
308
  async previewImpact(impact: any): Promise<boolean> {
309
- console.log(chalk.bold.blue('\n📊 Impact Preview\n'));
309
+ console.log(chalk.bold.blue('\n📊 Impact Preview\n'))
310
310
 
311
311
  // Display impact summary
312
- console.log(`Packages to update: ${impact.totalUpdates}`);
313
- console.log(`Risk level: ${impact.riskLevel}`);
314
- console.log(`Affected packages: ${impact.affectedCount}`);
312
+ console.log(`Packages to update: ${impact.totalUpdates}`)
313
+ console.log(`Risk level: ${impact.riskLevel}`)
314
+ console.log(`Affected packages: ${impact.affectedCount}`)
315
315
 
316
316
  if (impact.securityUpdates > 0) {
317
- console.log(StyledText.iconSecurity(`${impact.securityUpdates} security updates`));
317
+ console.log(StyledText.iconSecurity(`${impact.securityUpdates} security updates`))
318
318
  }
319
319
 
320
- console.log('');
320
+ console.log('')
321
321
 
322
322
  const answers = await inquirer.prompt([
323
323
  {
@@ -326,9 +326,9 @@ export class InteractivePrompts {
326
326
  message: 'Proceed with update?',
327
327
  default: true,
328
328
  },
329
- ]);
329
+ ])
330
330
 
331
- return answers.proceed;
331
+ return answers.proceed
332
332
  }
333
333
 
334
334
  /**
@@ -340,7 +340,7 @@ export class InteractivePrompts {
340
340
  { name: 'Skip this package', value: 'skip' },
341
341
  { name: 'Continue with remaining', value: 'continue' },
342
342
  { name: 'Abort operation', value: 'abort' },
343
- ];
343
+ ]
344
344
 
345
345
  const answers = await inquirer.prompt([
346
346
  {
@@ -349,9 +349,9 @@ export class InteractivePrompts {
349
349
  message: StyledText.iconError(`Error: ${error}`),
350
350
  choices: options,
351
351
  },
352
- ]);
352
+ ])
353
353
 
354
- return answers.action;
354
+ return answers.action
355
355
  }
356
356
 
357
357
  /**
@@ -365,9 +365,9 @@ export class InteractivePrompts {
365
365
  message: StyledText.iconUpdate(message),
366
366
  default: true,
367
367
  },
368
- ]);
368
+ ])
369
369
 
370
- return answers.update;
370
+ return answers.update
371
371
  }
372
372
 
373
373
  /**
@@ -378,11 +378,11 @@ export class InteractivePrompts {
378
378
  major: chalk.red,
379
379
  minor: chalk.yellow,
380
380
  patch: chalk.green,
381
- };
381
+ }
382
382
 
383
- const typeColor = updateTypeColor[pkg.type] || chalk.gray;
383
+ const typeColor = updateTypeColor[pkg.type] || chalk.gray
384
384
 
385
- return `${pkg.name} ${chalk.dim(pkg.current)} → ${typeColor(pkg.latest)} ${chalk.dim(`(${pkg.type})`)}`;
385
+ return `${pkg.name} ${chalk.dim(pkg.current)} → ${typeColor(pkg.latest)} ${chalk.dim(`(${pkg.type})`)}`
386
386
  }
387
387
  }
388
388
 
@@ -391,7 +391,7 @@ export class InteractivePrompts {
391
391
  */
392
392
  export class AutoCompleteManager {
393
393
  static async suggestWorkspaces(current: string): Promise<string[]> {
394
- const suggestions: string[] = [];
394
+ const suggestions: string[] = []
395
395
 
396
396
  // Common workspace patterns
397
397
  const patterns = [
@@ -399,32 +399,32 @@ export class AutoCompleteManager {
399
399
  'pnpm-workspace.yml',
400
400
  '**/*/pnpm-workspace.yaml',
401
401
  '**/*/pnpm-workspace.yml',
402
- ];
402
+ ]
403
403
 
404
404
  for (const pattern of patterns) {
405
405
  try {
406
- const { glob } = await import('glob');
407
- const matches = await glob(pattern);
406
+ const { glob } = await import('glob')
407
+ const matches = await glob(pattern)
408
408
  matches.forEach((match: string) => {
409
- const dir = match.replace(/\/pnpm-workspace\.ya?ml$/, '');
409
+ const dir = match.replace(/\/pnpm-workspace\.ya?ml$/, '')
410
410
  if (!suggestions.includes(dir)) {
411
- suggestions.push(dir);
411
+ suggestions.push(dir)
412
412
  }
413
- });
413
+ })
414
414
  } catch {
415
415
  // Ignore errors
416
416
  }
417
417
  }
418
418
 
419
- return suggestions.filter((s) => s.toLowerCase().includes(current.toLowerCase()));
419
+ return suggestions.filter((s) => s.toLowerCase().includes(current.toLowerCase()))
420
420
  }
421
421
 
422
422
  static async suggestCatalogs(): Promise<string[]> {
423
- return [];
423
+ return []
424
424
  }
425
425
 
426
426
  static async suggestPackages(): Promise<string[]> {
427
- return [];
427
+ return []
428
428
  }
429
429
  }
430
430
 
@@ -433,8 +433,8 @@ export class AutoCompleteManager {
433
433
  */
434
434
  export class InteractiveCommandBuilder {
435
435
  static async buildCommand(): Promise<{
436
- command: string;
437
- options: Record<string, any>;
436
+ command: string
437
+ options: Record<string, any>
438
438
  }> {
439
439
  const baseCommand = await inquirer.prompt([
440
440
  {
@@ -448,9 +448,9 @@ export class InteractiveCommandBuilder {
448
448
  { name: 'Show workspace info', value: 'workspace' },
449
449
  ],
450
450
  },
451
- ]);
451
+ ])
452
452
 
453
- const options: Record<string, any> = {};
453
+ const options: Record<string, any> = {}
454
454
 
455
455
  // Common options
456
456
  const common = await inquirer.prompt([
@@ -466,13 +466,13 @@ export class InteractiveCommandBuilder {
466
466
  ],
467
467
  default: 'table',
468
468
  },
469
- ]);
469
+ ])
470
470
 
471
- options.format = common.format;
471
+ options.format = common.format
472
472
 
473
473
  // Command-specific options
474
474
  switch (baseCommand.command) {
475
- case 'update':
475
+ case 'update': {
476
476
  const updateOpts = await inquirer.prompt([
477
477
  {
478
478
  type: 'confirm',
@@ -492,11 +492,12 @@ export class InteractiveCommandBuilder {
492
492
  message: 'Create backup?',
493
493
  default: true,
494
494
  },
495
- ]);
496
- Object.assign(options, updateOpts);
497
- break;
495
+ ])
496
+ Object.assign(options, updateOpts)
497
+ break
498
+ }
498
499
 
499
- case 'check':
500
+ case 'check': {
500
501
  const checkOpts = await inquirer.prompt([
501
502
  {
502
503
  type: 'confirm',
@@ -504,14 +505,15 @@ export class InteractiveCommandBuilder {
504
505
  message: 'Include pre-release versions?',
505
506
  default: false,
506
507
  },
507
- ]);
508
- options.prerelease = checkOpts.includePrerelease;
509
- break;
508
+ ])
509
+ options.prerelease = checkOpts.includePrerelease
510
+ break
511
+ }
510
512
  }
511
513
 
512
514
  return {
513
515
  command: baseCommand.command,
514
516
  options,
515
- };
517
+ }
516
518
  }
517
519
  }