slicejs-cli 2.7.4 → 2.7.5
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.
|
@@ -9,6 +9,7 @@ import inquirer from 'inquirer';
|
|
|
9
9
|
import { exec } from 'child_process';
|
|
10
10
|
import { promisify } from 'util';
|
|
11
11
|
import { getProjectRoot, getSrcPath, getApiPath, getConfigPath, getPath } from '../utils/PathHelper.js';
|
|
12
|
+
import updateManager from '../utils/updateManager.js';
|
|
12
13
|
|
|
13
14
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
14
15
|
|
|
@@ -148,7 +149,8 @@ async function checkPort() {
|
|
|
148
149
|
* Verifica dependencias en package.json
|
|
149
150
|
*/
|
|
150
151
|
async function checkDependencies() {
|
|
151
|
-
const
|
|
152
|
+
const projectRoot = getProjectRoot(import.meta.url);
|
|
153
|
+
const packagePath = path.join(projectRoot, 'package.json');
|
|
152
154
|
|
|
153
155
|
if (!await fs.pathExists(packagePath)) {
|
|
154
156
|
return {
|
|
@@ -160,18 +162,18 @@ async function checkDependencies() {
|
|
|
160
162
|
|
|
161
163
|
try {
|
|
162
164
|
const pkg = await fs.readJson(packagePath);
|
|
163
|
-
const
|
|
164
|
-
const
|
|
165
|
+
const hasFrameworkDep = pkg.dependencies?.['slicejs-web-framework'] || pkg.devDependencies?.['slicejs-web-framework'];
|
|
166
|
+
const frameworkNodePath = path.join(projectRoot, 'node_modules', 'slicejs-web-framework', 'package.json');
|
|
167
|
+
const hasFrameworkNode = await fs.pathExists(frameworkNodePath);
|
|
168
|
+
const hasFramework = !!(hasFrameworkDep || hasFrameworkNode);
|
|
165
169
|
|
|
166
|
-
if (
|
|
170
|
+
if (hasFramework) {
|
|
167
171
|
return {
|
|
168
172
|
pass: true,
|
|
169
|
-
message: '
|
|
173
|
+
message: 'Required framework dependency is installed'
|
|
170
174
|
};
|
|
171
175
|
} else {
|
|
172
|
-
const missing = [];
|
|
173
|
-
if (!hasCli) missing.push('slicejs-cli');
|
|
174
|
-
if (!hasFramework) missing.push('slicejs-web-framework');
|
|
176
|
+
const missing = ['slicejs-web-framework'];
|
|
175
177
|
|
|
176
178
|
return {
|
|
177
179
|
warn: true,
|
|
@@ -334,9 +336,7 @@ export default async function runDiagnostics() {
|
|
|
334
336
|
if (confirmInstall) {
|
|
335
337
|
for (const pkg of depsResult.missing) {
|
|
336
338
|
try {
|
|
337
|
-
const cmd =
|
|
338
|
-
? 'npm install -D slicejs-cli@latest'
|
|
339
|
-
: 'npm install slicejs-web-framework@latest';
|
|
339
|
+
const cmd = 'npm install slicejs-web-framework@latest';
|
|
340
340
|
Print.info(`Installing ${pkg}...`);
|
|
341
341
|
await execAsync(cmd, { cwd: projectRoot });
|
|
342
342
|
Print.success(`${pkg} installed`);
|
|
@@ -7,6 +7,7 @@ import inquirer from "inquirer";
|
|
|
7
7
|
import validations from "../Validations.js";
|
|
8
8
|
import Print from "../Print.js";
|
|
9
9
|
import { getConfigPath, getComponentsJsPath, getPath } from "../utils/PathHelper.js";
|
|
10
|
+
import ora from "ora";
|
|
10
11
|
|
|
11
12
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
12
13
|
|
|
@@ -188,32 +189,51 @@ filterOfficialComponents(allComponents) {
|
|
|
188
189
|
|
|
189
190
|
const downloadedFiles = [];
|
|
190
191
|
const failedFiles = [];
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
192
|
+
const total = component.files.length;
|
|
193
|
+
let done = 0;
|
|
194
|
+
const spinner = ora(`Downloading ${componentName} 0/${total}`).start();
|
|
195
|
+
const fetchWithRetry = async (url, retries = 3, baseDelay = 500) => {
|
|
196
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
197
|
+
try {
|
|
198
|
+
const response = await fetch(url);
|
|
199
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
200
|
+
return await response.text();
|
|
201
|
+
} catch (e) {
|
|
202
|
+
if (attempt === retries) throw e;
|
|
203
|
+
const delay = baseDelay * Math.pow(2, attempt);
|
|
204
|
+
await new Promise(r => setTimeout(r, delay));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
const worker = async (fileName) => {
|
|
209
|
+
const url = `${DOCS_REPO_BASE_URL}/${category}/${componentName}/${fileName}`;
|
|
195
210
|
const localPath = path.join(targetPath, fileName);
|
|
196
|
-
|
|
197
211
|
try {
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
if (!response.ok) {
|
|
201
|
-
Print.downloadError(fileName, `HTTP ${response.status}: ${response.statusText}`);
|
|
202
|
-
failedFiles.push(fileName);
|
|
203
|
-
continue; // ✅ CONTINUAR en lugar de lanzar error
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
const content = await response.text();
|
|
212
|
+
const content = await fetchWithRetry(url);
|
|
207
213
|
await fs.writeFile(localPath, content, 'utf8');
|
|
208
214
|
downloadedFiles.push(fileName);
|
|
209
|
-
|
|
210
215
|
Print.downloadSuccess(fileName);
|
|
211
216
|
} catch (error) {
|
|
212
217
|
Print.downloadError(fileName, error.message);
|
|
213
218
|
failedFiles.push(fileName);
|
|
214
|
-
|
|
219
|
+
} finally {
|
|
220
|
+
done += 1;
|
|
221
|
+
spinner.text = `Downloading ${componentName} ${done}/${total}`;
|
|
215
222
|
}
|
|
216
|
-
}
|
|
223
|
+
};
|
|
224
|
+
const runConcurrent = async (items, concurrency = 3) => {
|
|
225
|
+
let index = 0;
|
|
226
|
+
const runners = Array(Math.min(concurrency, items.length)).fill(0).map(async () => {
|
|
227
|
+
while (true) {
|
|
228
|
+
const i = index++;
|
|
229
|
+
if (i >= items.length) break;
|
|
230
|
+
await worker(items[i]);
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
await Promise.all(runners);
|
|
234
|
+
};
|
|
235
|
+
await runConcurrent(component.files, 3);
|
|
236
|
+
spinner.stop();
|
|
217
237
|
|
|
218
238
|
// ✅ NUEVO: Solo lanzar error si NO se descargó el archivo principal (.js)
|
|
219
239
|
const mainFileDownloaded = downloadedFiles.some(file => file.endsWith('.js'));
|
|
@@ -311,7 +331,7 @@ filterOfficialComponents(allComponents) {
|
|
|
311
331
|
const availableComponents = this.getAvailableComponents(category);
|
|
312
332
|
|
|
313
333
|
if (!availableComponents[componentName]) {
|
|
314
|
-
throw new Error(`
|
|
334
|
+
throw new Error(`Component '${componentName}' not found in category '${category}' in the official repository`);
|
|
315
335
|
}
|
|
316
336
|
|
|
317
337
|
// ✅ MEJORADO: Detectar si validations tiene acceso a la configuración
|
|
@@ -347,7 +367,7 @@ filterOfficialComponents(allComponents) {
|
|
|
347
367
|
{
|
|
348
368
|
type: 'confirm',
|
|
349
369
|
name: 'overwrite',
|
|
350
|
-
message: `
|
|
370
|
+
message: `The component '${componentName}' already exists locally. Overwrite with the repository version?`,
|
|
351
371
|
default: false
|
|
352
372
|
}
|
|
353
373
|
]);
|
|
@@ -395,16 +415,34 @@ filterOfficialComponents(allComponents) {
|
|
|
395
415
|
async installMultipleComponents(componentNames, category = 'Visual', force = false) {
|
|
396
416
|
const results = [];
|
|
397
417
|
Print.info(`Getting ${componentNames.length} ${category} components from official repository...`);
|
|
398
|
-
|
|
399
|
-
|
|
418
|
+
const total = componentNames.length;
|
|
419
|
+
let done = 0;
|
|
420
|
+
const spinner = ora(`Installing 0/${total}`).start();
|
|
421
|
+
const worker = async (componentName) => {
|
|
400
422
|
try {
|
|
401
423
|
const result = await this.installComponent(componentName, category, force);
|
|
402
424
|
results.push({ name: componentName, success: result });
|
|
403
425
|
} catch (error) {
|
|
404
426
|
Print.componentError(componentName, 'getting', error.message);
|
|
405
427
|
results.push({ name: componentName, success: false, error: error.message });
|
|
428
|
+
} finally {
|
|
429
|
+
done += 1;
|
|
430
|
+
spinner.text = `Installing ${done}/${total}`;
|
|
406
431
|
}
|
|
407
|
-
}
|
|
432
|
+
};
|
|
433
|
+
const runConcurrent = async (items, concurrency = 3) => {
|
|
434
|
+
let index = 0;
|
|
435
|
+
const runners = Array(Math.min(concurrency, items.length)).fill(0).map(async () => {
|
|
436
|
+
while (true) {
|
|
437
|
+
const i = index++;
|
|
438
|
+
if (i >= items.length) break;
|
|
439
|
+
await worker(items[i]);
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
await Promise.all(runners);
|
|
443
|
+
};
|
|
444
|
+
await runConcurrent(componentNames, 3);
|
|
445
|
+
spinner.stop();
|
|
408
446
|
|
|
409
447
|
// Summary
|
|
410
448
|
const successful = results.filter(r => r.success).length;
|
|
@@ -492,11 +530,11 @@ filterOfficialComponents(allComponents) {
|
|
|
492
530
|
|
|
493
531
|
displayAvailableComponents() {
|
|
494
532
|
if (!this.componentsRegistry) {
|
|
495
|
-
Print.error('❌
|
|
533
|
+
Print.error('❌ Could not load component registry');
|
|
496
534
|
return;
|
|
497
535
|
}
|
|
498
536
|
|
|
499
|
-
console.log('\n📚
|
|
537
|
+
console.log('\n📚 Available components in the official Slice.js repository:\n');
|
|
500
538
|
|
|
501
539
|
const visualComponents = this.getAvailableComponents('Visual');
|
|
502
540
|
const serviceComponents = this.getAvailableComponents('Service');
|
|
@@ -522,10 +560,10 @@ filterOfficialComponents(allComponents) {
|
|
|
522
560
|
Print.newLine();
|
|
523
561
|
Print.info(`Total: ${Object.keys(visualComponents).length} Visual + ${Object.keys(serviceComponents).length} Service components`);
|
|
524
562
|
|
|
525
|
-
console.log(`\n💡
|
|
526
|
-
console.log(`slice get Button Card Input #
|
|
527
|
-
console.log(`slice get FetchManager --service #
|
|
528
|
-
console.log(`slice sync #
|
|
563
|
+
console.log(`\n💡 Usage examples:`);
|
|
564
|
+
console.log(`slice get Button Card Input # Install Visual components`);
|
|
565
|
+
console.log(`slice get FetchManager --service # Install Service component`);
|
|
566
|
+
console.log(`slice sync # Sync Visual components`);
|
|
529
567
|
}
|
|
530
568
|
|
|
531
569
|
async interactiveInstall() {
|
|
@@ -533,7 +571,7 @@ filterOfficialComponents(allComponents) {
|
|
|
533
571
|
{
|
|
534
572
|
type: 'list',
|
|
535
573
|
name: 'componentType',
|
|
536
|
-
message: '
|
|
574
|
+
message: 'Select the type of component to install from the repository:',
|
|
537
575
|
choices: [
|
|
538
576
|
{ name: '🎨 Visual Components (UI)', value: 'Visual' },
|
|
539
577
|
{ name: '⚙️ Service Components (Logic)', value: 'Service' }
|
|
@@ -552,10 +590,10 @@ filterOfficialComponents(allComponents) {
|
|
|
552
590
|
{
|
|
553
591
|
type: 'list',
|
|
554
592
|
name: 'installMode',
|
|
555
|
-
message: '
|
|
593
|
+
message: 'How do you want to install Visual components?',
|
|
556
594
|
choices: [
|
|
557
|
-
{ name: '
|
|
558
|
-
{ name: '
|
|
595
|
+
{ name: 'Get one', value: 'single' },
|
|
596
|
+
{ name: 'Get multiple', value: 'multiple' }
|
|
559
597
|
]
|
|
560
598
|
}
|
|
561
599
|
]);
|
|
@@ -565,11 +603,11 @@ filterOfficialComponents(allComponents) {
|
|
|
565
603
|
{
|
|
566
604
|
type: 'checkbox',
|
|
567
605
|
name: 'selectedComponents',
|
|
568
|
-
message: '
|
|
606
|
+
message: 'Select Visual components to install from the repository:',
|
|
569
607
|
choices: componentChoices,
|
|
570
608
|
validate: (input) => {
|
|
571
609
|
if (input.length === 0) {
|
|
572
|
-
return '
|
|
610
|
+
return 'You must select at least one component';
|
|
573
611
|
}
|
|
574
612
|
return true;
|
|
575
613
|
}
|
|
@@ -582,7 +620,7 @@ filterOfficialComponents(allComponents) {
|
|
|
582
620
|
{
|
|
583
621
|
type: 'list',
|
|
584
622
|
name: 'selectedComponent',
|
|
585
|
-
message: '
|
|
623
|
+
message: 'Select a Visual component:',
|
|
586
624
|
choices: componentChoices
|
|
587
625
|
}
|
|
588
626
|
]);
|
|
@@ -594,7 +632,7 @@ filterOfficialComponents(allComponents) {
|
|
|
594
632
|
{
|
|
595
633
|
type: 'list',
|
|
596
634
|
name: 'selectedComponent',
|
|
597
|
-
message: '
|
|
635
|
+
message: 'Select a Service component:',
|
|
598
636
|
choices: componentChoices
|
|
599
637
|
}
|
|
600
638
|
]);
|
package/commands/init/init.js
CHANGED
|
@@ -48,30 +48,29 @@ export default async function initializeProject(projectType) {
|
|
|
48
48
|
const srcDir = path.join(sliceBaseDir, 'src');
|
|
49
49
|
|
|
50
50
|
try {
|
|
51
|
-
|
|
52
|
-
if (fs.existsSync(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
51
|
+
if (fs.existsSync(destinationApi)) throw new Error(`The "api" directory already exists: ${destinationApi}`);
|
|
52
|
+
if (fs.existsSync(destinationSrc)) throw new Error(`The "src" directory already exists: ${destinationSrc}`);
|
|
53
|
+
} catch (error) {
|
|
54
|
+
Print.error('Validating destination directories:', error.message);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
58
57
|
|
|
59
58
|
// 1. COPIAR LA CARPETA API (mantener lógica original)
|
|
60
|
-
const apiSpinner = ora('Copying API structure...').start();
|
|
61
|
-
try {
|
|
62
|
-
if (!fs.existsSync(apiDir)) throw new Error(`
|
|
63
|
-
await fs.copy(apiDir, destinationApi, { recursive: true });
|
|
64
|
-
apiSpinner.succeed('API structure created successfully');
|
|
65
|
-
} catch (error) {
|
|
66
|
-
apiSpinner.fail('Error copying API structure');
|
|
67
|
-
Print.error(error.message);
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
59
|
+
const apiSpinner = ora('Copying API structure...').start();
|
|
60
|
+
try {
|
|
61
|
+
if (!fs.existsSync(apiDir)) throw new Error(`API folder not found: ${apiDir}`);
|
|
62
|
+
await fs.copy(apiDir, destinationApi, { recursive: true });
|
|
63
|
+
apiSpinner.succeed('API structure created successfully');
|
|
64
|
+
} catch (error) {
|
|
65
|
+
apiSpinner.fail('Error copying API structure');
|
|
66
|
+
Print.error(error.message);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
70
69
|
|
|
71
70
|
// 2. CREAR ESTRUCTURA SRC BÁSICA (sin copiar componentes Visual)
|
|
72
|
-
const srcSpinner = ora('Creating src structure...').start();
|
|
73
|
-
try {
|
|
74
|
-
if (!fs.existsSync(srcDir)) throw new Error(`
|
|
71
|
+
const srcSpinner = ora('Creating src structure...').start();
|
|
72
|
+
try {
|
|
73
|
+
if (!fs.existsSync(srcDir)) throw new Error(`src folder not found: ${srcDir}`);
|
|
75
74
|
|
|
76
75
|
// Copiar solo los archivos base de src, excluyendo Components/Visual
|
|
77
76
|
await fs.ensureDir(destinationSrc);
|
|
@@ -95,22 +94,22 @@ export default async function initializeProject(projectType) {
|
|
|
95
94
|
const destComponentItemPath = path.join(destItemPath, componentItem);
|
|
96
95
|
|
|
97
96
|
if (componentItem !== 'Visual') {
|
|
98
|
-
//
|
|
99
|
-
await fs.copy(componentItemPath, destComponentItemPath, { recursive: true });
|
|
100
|
-
} else {
|
|
101
|
-
//
|
|
102
|
-
await fs.ensureDir(destComponentItemPath);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
} else {
|
|
106
|
-
//
|
|
107
|
-
await fs.copy(srcItemPath, destItemPath, { recursive: true });
|
|
108
|
-
}
|
|
109
|
-
} else {
|
|
110
|
-
//
|
|
111
|
-
await fs.copy(srcItemPath, destItemPath);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
97
|
+
// Copy Service and other component types
|
|
98
|
+
await fs.copy(componentItemPath, destComponentItemPath, { recursive: true });
|
|
99
|
+
} else {
|
|
100
|
+
// Only create empty Visual directory
|
|
101
|
+
await fs.ensureDir(destComponentItemPath);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
} else {
|
|
105
|
+
// Copy other folders normally
|
|
106
|
+
await fs.copy(srcItemPath, destItemPath, { recursive: true });
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
// Copy files normally
|
|
110
|
+
await fs.copy(srcItemPath, destItemPath);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
114
113
|
|
|
115
114
|
srcSpinner.succeed('Source structure created successfully');
|
|
116
115
|
} catch (error) {
|
|
@@ -143,15 +142,15 @@ export default async function initializeProject(projectType) {
|
|
|
143
142
|
if (successful > 0 && failed === 0) {
|
|
144
143
|
componentsSpinner.succeed(`All ${successful} Visual components installed successfully`);
|
|
145
144
|
} else if (successful > 0) {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
145
|
+
componentsSpinner.warn(`${successful} components installed, ${failed} failed`);
|
|
146
|
+
Print.info('You can install failed components later using "slice get <component-name>"');
|
|
147
|
+
} else {
|
|
148
|
+
componentsSpinner.fail('Failed to install Visual components');
|
|
149
|
+
}
|
|
150
|
+
} else {
|
|
151
|
+
componentsSpinner.warn('No Visual components found in registry');
|
|
152
|
+
Print.info('You can add components later using "slice get <component-name>"');
|
|
153
|
+
}
|
|
155
154
|
|
|
156
155
|
} catch (error) {
|
|
157
156
|
componentsSpinner.fail('Could not download Visual components from official repository');
|
|
@@ -223,21 +222,21 @@ export default async function initializeProject(projectType) {
|
|
|
223
222
|
console.log(' npm run get - Install components');
|
|
224
223
|
console.log(' npm run browse - Browse components');
|
|
225
224
|
} catch (error) {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
}
|
|
225
|
+
pkgSpinner.fail('Failed to configure npm scripts');
|
|
226
|
+
Print.error(error.message);
|
|
227
|
+
}
|
|
229
228
|
|
|
230
|
-
Print.success('
|
|
231
|
-
Print.newLine();
|
|
232
|
-
Print.info('Next steps:');
|
|
233
|
-
console.log(' slice browse - View available components');
|
|
234
|
-
console.log(' slice get Button - Install specific components');
|
|
235
|
-
console.log(' slice sync - Update all components to latest versions');
|
|
229
|
+
Print.success('Project initialized successfully.');
|
|
230
|
+
Print.newLine();
|
|
231
|
+
Print.info('Next steps:');
|
|
232
|
+
console.log(' slice browse - View available components');
|
|
233
|
+
console.log(' slice get Button - Install specific components');
|
|
234
|
+
console.log(' slice sync - Update all components to latest versions');
|
|
236
235
|
|
|
237
236
|
} catch (error) {
|
|
238
|
-
Print.error('
|
|
239
|
-
}
|
|
240
|
-
}
|
|
237
|
+
Print.error('Unexpected error initializing project:', error.message);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
241
240
|
|
|
242
241
|
/**
|
|
243
242
|
* Obtiene TODOS los componentes Visual disponibles en el registry
|
|
@@ -14,6 +14,16 @@ function candidates(moduleUrl) {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
function resolveProjectRoot(moduleUrl) {
|
|
17
|
+
const initCwd = process.env.INIT_CWD
|
|
18
|
+
if (initCwd && fs.pathExistsSync(initCwd)) {
|
|
19
|
+
return initCwd
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const cwd = process.cwd()
|
|
23
|
+
if (cwd && fs.pathExistsSync(cwd)) {
|
|
24
|
+
return cwd
|
|
25
|
+
}
|
|
26
|
+
|
|
17
27
|
const dirs = candidates(moduleUrl)
|
|
18
28
|
for (const root of dirs) {
|
|
19
29
|
const hasSrc = fs.pathExistsSync(path.join(root, 'src'))
|
|
@@ -111,7 +111,7 @@ class VersionChecker {
|
|
|
111
111
|
|
|
112
112
|
if (!silent && (cliStatus === 'outdated' || frameworkStatus === 'outdated')) {
|
|
113
113
|
console.log(''); // Line break
|
|
114
|
-
Print.warning('📦
|
|
114
|
+
Print.warning('📦 Available Updates:');
|
|
115
115
|
|
|
116
116
|
if (cliStatus === 'outdated') {
|
|
117
117
|
console.log(` 🔧 CLI: ${current.cli} → ${latest.cli}`);
|
|
@@ -142,7 +142,7 @@ class VersionChecker {
|
|
|
142
142
|
const current = await this.getCurrentVersions();
|
|
143
143
|
const latest = await this.getLatestVersions();
|
|
144
144
|
|
|
145
|
-
console.log('\n📋
|
|
145
|
+
console.log('\n📋 Version Information:');
|
|
146
146
|
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
147
147
|
|
|
148
148
|
if (current?.cli) {
|
|
@@ -95,7 +95,7 @@ class UpdateManager {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
console.log('');
|
|
98
|
-
Print.warning('📦
|
|
98
|
+
Print.warning('📦 Available Updates:');
|
|
99
99
|
console.log('');
|
|
100
100
|
|
|
101
101
|
updateInfo.updates.forEach(pkg => {
|
|
@@ -145,17 +145,17 @@ class UpdateManager {
|
|
|
145
145
|
const answers = await inquirer.prompt([
|
|
146
146
|
{
|
|
147
147
|
type: 'checkbox',
|
|
148
|
-
name: 'packages',
|
|
149
|
-
message: '
|
|
150
|
-
choices,
|
|
151
|
-
validate: (answer) => {
|
|
152
|
-
if (answer.length === 0) {
|
|
153
|
-
return '
|
|
154
|
-
}
|
|
155
|
-
return true;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
]);
|
|
148
|
+
name: 'packages',
|
|
149
|
+
message: 'Which packages do you want to update?',
|
|
150
|
+
choices,
|
|
151
|
+
validate: (answer) => {
|
|
152
|
+
if (answer.length === 0) {
|
|
153
|
+
return 'You must select at least one package';
|
|
154
|
+
}
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
]);
|
|
159
159
|
|
|
160
160
|
return answers.packages;
|
|
161
161
|
}
|
|
@@ -229,25 +229,25 @@ class UpdateManager {
|
|
|
229
229
|
const results = [];
|
|
230
230
|
|
|
231
231
|
for (const packageName of packages) {
|
|
232
|
-
const spinner = ora(`
|
|
232
|
+
const spinner = ora(`Updating ${packageName}...`).start();
|
|
233
233
|
|
|
234
234
|
try {
|
|
235
235
|
const result = await this.updatePackage(packageName);
|
|
236
236
|
|
|
237
|
-
if (result.success) {
|
|
238
|
-
spinner.succeed(`${packageName}
|
|
239
|
-
results.push({ packageName, success: true });
|
|
240
|
-
} else {
|
|
241
|
-
spinner.fail(`Error
|
|
242
|
-
Print.error(`
|
|
243
|
-
results.push({ packageName, success: false, error: result.error });
|
|
244
|
-
}
|
|
245
|
-
} catch (error) {
|
|
246
|
-
spinner.fail(`Error
|
|
247
|
-
Print.error(`
|
|
248
|
-
results.push({ packageName, success: false, error: error.message });
|
|
249
|
-
}
|
|
250
|
-
}
|
|
237
|
+
if (result.success) {
|
|
238
|
+
spinner.succeed(`${packageName} updated successfully`);
|
|
239
|
+
results.push({ packageName, success: true });
|
|
240
|
+
} else {
|
|
241
|
+
spinner.fail(`Error updating ${packageName}`);
|
|
242
|
+
Print.error(`Details: ${result.error}`);
|
|
243
|
+
results.push({ packageName, success: false, error: result.error });
|
|
244
|
+
}
|
|
245
|
+
} catch (error) {
|
|
246
|
+
spinner.fail(`Error updating ${packageName}`);
|
|
247
|
+
Print.error(`Details: ${error.message}`);
|
|
248
|
+
results.push({ packageName, success: false, error: error.message });
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
251
|
|
|
252
252
|
return results;
|
|
253
253
|
}
|
|
@@ -256,26 +256,26 @@ class UpdateManager {
|
|
|
256
256
|
* Main method to check and prompt for updates
|
|
257
257
|
*/
|
|
258
258
|
async checkAndPromptUpdates(options = {}) {
|
|
259
|
-
const spinner = ora('
|
|
259
|
+
const spinner = ora('Checking for updates...').start();
|
|
260
260
|
|
|
261
261
|
try {
|
|
262
262
|
const updateInfo = await this.checkForUpdates();
|
|
263
263
|
spinner.stop();
|
|
264
264
|
|
|
265
|
-
if (!updateInfo) {
|
|
266
|
-
Print.error('
|
|
267
|
-
return false;
|
|
268
|
-
}
|
|
265
|
+
if (!updateInfo) {
|
|
266
|
+
Print.error('Could not check for updates. Verify your internet connection.');
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
269
|
|
|
270
|
-
if (updateInfo.allCurrent) {
|
|
271
|
-
Print.success('✅
|
|
272
|
-
return true;
|
|
273
|
-
}
|
|
270
|
+
if (updateInfo.allCurrent) {
|
|
271
|
+
Print.success('✅ All components are up to date!');
|
|
272
|
+
return true;
|
|
273
|
+
}
|
|
274
274
|
|
|
275
|
-
if (!updateInfo.hasUpdates) {
|
|
276
|
-
Print.success('✅
|
|
277
|
-
return true;
|
|
278
|
-
}
|
|
275
|
+
if (!updateInfo.hasUpdates) {
|
|
276
|
+
Print.success('✅ All components are up to date!');
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
279
279
|
|
|
280
280
|
// Display available updates
|
|
281
281
|
this.displayUpdates(updateInfo);
|
|
@@ -283,20 +283,20 @@ class UpdateManager {
|
|
|
283
283
|
// Get packages to update
|
|
284
284
|
const packagesToUpdate = await this.promptForUpdates(updateInfo, options);
|
|
285
285
|
|
|
286
|
-
if (!packagesToUpdate || packagesToUpdate.length === 0) {
|
|
287
|
-
Print.info('No
|
|
288
|
-
return false;
|
|
289
|
-
}
|
|
286
|
+
if (!packagesToUpdate || packagesToUpdate.length === 0) {
|
|
287
|
+
Print.info('No packages selected for update.');
|
|
288
|
+
return false;
|
|
289
|
+
}
|
|
290
290
|
|
|
291
291
|
// Show plan and confirm installation if not auto-confirmed
|
|
292
292
|
let plan = await this.buildUpdatePlan(packagesToUpdate);
|
|
293
293
|
console.log('');
|
|
294
|
-
Print.info('🧭
|
|
295
|
-
plan.forEach(item => {
|
|
296
|
-
const where = item.target === 'global' ? 'GLOBAL' : '
|
|
297
|
-
console.log(` • ${item.package} → ${where}`);
|
|
298
|
-
console.log(` ${item.command}`);
|
|
299
|
-
});
|
|
294
|
+
Print.info('🧭 Update plan:');
|
|
295
|
+
plan.forEach(item => {
|
|
296
|
+
const where = item.target === 'global' ? 'GLOBAL' : 'PROJECT';
|
|
297
|
+
console.log(` • ${item.package} → ${where}`);
|
|
298
|
+
console.log(` ${item.command}`);
|
|
299
|
+
});
|
|
300
300
|
console.log('');
|
|
301
301
|
|
|
302
302
|
const cliInfo = await this.detectCliInstall();
|
|
@@ -306,47 +306,47 @@ class UpdateManager {
|
|
|
306
306
|
{
|
|
307
307
|
type: 'confirm',
|
|
308
308
|
name: 'addCli',
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
309
|
+
message: 'Global CLI detected. Add the global CLI update to the plan?',
|
|
310
|
+
default: true
|
|
311
|
+
}
|
|
312
|
+
]);
|
|
313
313
|
if (addCli) {
|
|
314
314
|
packagesToUpdate.push('slicejs-cli');
|
|
315
315
|
plan = await this.buildUpdatePlan(packagesToUpdate);
|
|
316
316
|
console.log('');
|
|
317
|
-
Print.info('🧭
|
|
318
|
-
plan.forEach(item => {
|
|
319
|
-
const where = item.target === 'global' ? 'GLOBAL' : '
|
|
320
|
-
console.log(` • ${item.package} → ${where}`);
|
|
321
|
-
console.log(` ${item.command}`);
|
|
322
|
-
});
|
|
317
|
+
Print.info('🧭 Updated plan:');
|
|
318
|
+
plan.forEach(item => {
|
|
319
|
+
const where = item.target === 'global' ? 'GLOBAL' : 'PROJECT';
|
|
320
|
+
console.log(` • ${item.package} → ${where}`);
|
|
321
|
+
console.log(` ${item.command}`);
|
|
322
|
+
});
|
|
323
323
|
console.log('');
|
|
324
324
|
}
|
|
325
325
|
} else {
|
|
326
|
-
Print.warning('CLI
|
|
327
|
-
console.log('
|
|
328
|
-
console.log('');
|
|
329
|
-
}
|
|
330
|
-
}
|
|
326
|
+
Print.warning('Global CLI detected. It is recommended to update slicejs-cli globally to keep aligned with the framework.');
|
|
327
|
+
console.log(' Suggestion: npm install -g slicejs-cli@latest');
|
|
328
|
+
console.log('');
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
331
|
|
|
332
332
|
if (!options.yes && !options.cli && !options.framework) {
|
|
333
333
|
const { confirm } = await inquirer.prompt([
|
|
334
|
-
{
|
|
335
|
-
type: 'confirm',
|
|
336
|
-
name: 'confirm',
|
|
337
|
-
message: '
|
|
338
|
-
default: true
|
|
339
|
-
}
|
|
340
|
-
]);
|
|
334
|
+
{
|
|
335
|
+
type: 'confirm',
|
|
336
|
+
name: 'confirm',
|
|
337
|
+
message: 'Do you want to proceed with the update according to the plan shown?',
|
|
338
|
+
default: true
|
|
339
|
+
}
|
|
340
|
+
]);
|
|
341
341
|
|
|
342
342
|
if (!confirm) {
|
|
343
|
-
Print.info('
|
|
344
|
-
return false;
|
|
345
|
-
}
|
|
346
|
-
}
|
|
343
|
+
Print.info('Update cancelled.');
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
347
|
|
|
348
348
|
console.log(''); // Line break
|
|
349
|
-
Print.info('📥
|
|
349
|
+
Print.info('📥 Installing updates...');
|
|
350
350
|
console.log('');
|
|
351
351
|
|
|
352
352
|
// Install updates
|
|
@@ -357,24 +357,24 @@ class UpdateManager {
|
|
|
357
357
|
const successCount = results.filter(r => r.success).length;
|
|
358
358
|
const failCount = results.filter(r => !r.success).length;
|
|
359
359
|
|
|
360
|
-
if (failCount === 0) {
|
|
361
|
-
Print.success(`✅ ${successCount}
|
|
362
|
-
} else {
|
|
363
|
-
Print.warning(`⚠️ ${successCount}
|
|
364
|
-
}
|
|
360
|
+
if (failCount === 0) {
|
|
361
|
+
Print.success(`✅ ${successCount} package(s) updated successfully!`);
|
|
362
|
+
} else {
|
|
363
|
+
Print.warning(`⚠️ ${successCount} successful, ${failCount} failed`);
|
|
364
|
+
}
|
|
365
365
|
|
|
366
366
|
if (successCount > 0) {
|
|
367
367
|
console.log('');
|
|
368
|
-
Print.info('💡
|
|
369
|
-
}
|
|
368
|
+
Print.info('💡 It is recommended to restart the development server if it is running.');
|
|
369
|
+
}
|
|
370
370
|
|
|
371
371
|
return failCount === 0;
|
|
372
372
|
|
|
373
373
|
} catch (error) {
|
|
374
374
|
spinner.stop();
|
|
375
|
-
Print.error(`Error
|
|
376
|
-
return false;
|
|
377
|
-
}
|
|
375
|
+
Print.error(`Error during update: ${error.message}`);
|
|
376
|
+
return false;
|
|
377
|
+
}
|
|
378
378
|
}
|
|
379
379
|
}
|
|
380
380
|
|