slicejs-cli 2.7.3 → 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.
- package/client.js +46 -1
- package/commands/doctor/doctor.js +43 -9
- package/commands/getComponent/getComponent.js +74 -36
- package/commands/init/init.js +56 -57
- package/commands/utils/PathHelper.js +10 -0
- package/commands/utils/VersionChecker.js +2 -2
- package/commands/utils/updateManager.js +87 -87
- package/package.json +5 -1
- package/post.js +5 -5
package/client.js
CHANGED
|
@@ -13,7 +13,9 @@ import updateManager from "./commands/utils/updateManager.js";
|
|
|
13
13
|
import fs from "fs";
|
|
14
14
|
import path from "path";
|
|
15
15
|
import { fileURLToPath } from "url";
|
|
16
|
-
import { getConfigPath } from "./commands/utils/PathHelper.js";
|
|
16
|
+
import { getConfigPath, getProjectRoot } from "./commands/utils/PathHelper.js";
|
|
17
|
+
import { exec } from "child_process";
|
|
18
|
+
import { promisify } from "util";
|
|
17
19
|
import validations from "./commands/Validations.js";
|
|
18
20
|
import Print from "./commands/Print.js";
|
|
19
21
|
|
|
@@ -37,6 +39,49 @@ const getCategories = () => {
|
|
|
37
39
|
// Function to run version check for all commands
|
|
38
40
|
async function runWithVersionCheck(commandFunction, ...args) {
|
|
39
41
|
try {
|
|
42
|
+
const execAsync = promisify(exec);
|
|
43
|
+
await (async () => {
|
|
44
|
+
try {
|
|
45
|
+
const info = await updateManager.detectCliInstall();
|
|
46
|
+
if (info && info.type === 'global') {
|
|
47
|
+
const projectRoot = getProjectRoot(import.meta.url);
|
|
48
|
+
const pkgPath = path.join(projectRoot, 'package.json');
|
|
49
|
+
let hasPkg = fs.existsSync(pkgPath);
|
|
50
|
+
if (!hasPkg) {
|
|
51
|
+
const { confirmInit } = await inquirer.prompt([
|
|
52
|
+
{
|
|
53
|
+
type: 'confirm',
|
|
54
|
+
name: 'confirmInit',
|
|
55
|
+
message: 'No package.json found. Initialize npm in this project now?',
|
|
56
|
+
default: true
|
|
57
|
+
}
|
|
58
|
+
]);
|
|
59
|
+
if (confirmInit) {
|
|
60
|
+
await execAsync('npm init -y', { cwd: projectRoot });
|
|
61
|
+
hasPkg = true;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (hasPkg) {
|
|
65
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
66
|
+
const hasFramework = pkg.dependencies?.['slicejs-web-framework'];
|
|
67
|
+
if (!hasFramework) {
|
|
68
|
+
const { confirm } = await inquirer.prompt([
|
|
69
|
+
{
|
|
70
|
+
type: 'confirm',
|
|
71
|
+
name: 'confirm',
|
|
72
|
+
message: 'slicejs-web-framework is not installed in this project. Install it now?',
|
|
73
|
+
default: true
|
|
74
|
+
}
|
|
75
|
+
]);
|
|
76
|
+
if (confirm) {
|
|
77
|
+
await updateManager.updatePackage('slicejs-web-framework');
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
} catch {}
|
|
83
|
+
})();
|
|
84
|
+
|
|
40
85
|
const updateInfo = await updateManager.checkForUpdates();
|
|
41
86
|
if (updateInfo && updateInfo.hasUpdates) {
|
|
42
87
|
await updateManager.checkAndPromptUpdates({});
|
|
@@ -5,7 +5,11 @@ import { createServer } from 'net';
|
|
|
5
5
|
import chalk from 'chalk';
|
|
6
6
|
import Table from 'cli-table3';
|
|
7
7
|
import Print from '../Print.js';
|
|
8
|
+
import inquirer from 'inquirer';
|
|
9
|
+
import { exec } from 'child_process';
|
|
10
|
+
import { promisify } from 'util';
|
|
8
11
|
import { getProjectRoot, getSrcPath, getApiPath, getConfigPath, getPath } from '../utils/PathHelper.js';
|
|
12
|
+
import updateManager from '../utils/updateManager.js';
|
|
9
13
|
|
|
10
14
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
11
15
|
|
|
@@ -145,7 +149,8 @@ async function checkPort() {
|
|
|
145
149
|
* Verifica dependencias en package.json
|
|
146
150
|
*/
|
|
147
151
|
async function checkDependencies() {
|
|
148
|
-
const
|
|
152
|
+
const projectRoot = getProjectRoot(import.meta.url);
|
|
153
|
+
const packagePath = path.join(projectRoot, 'package.json');
|
|
149
154
|
|
|
150
155
|
if (!await fs.pathExists(packagePath)) {
|
|
151
156
|
return {
|
|
@@ -157,23 +162,26 @@ async function checkDependencies() {
|
|
|
157
162
|
|
|
158
163
|
try {
|
|
159
164
|
const pkg = await fs.readJson(packagePath);
|
|
160
|
-
const
|
|
161
|
-
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);
|
|
162
169
|
|
|
163
|
-
if (
|
|
170
|
+
if (hasFramework) {
|
|
164
171
|
return {
|
|
165
172
|
pass: true,
|
|
166
|
-
message: '
|
|
173
|
+
message: 'Required framework dependency is installed'
|
|
167
174
|
};
|
|
168
175
|
} else {
|
|
169
|
-
const missing = [];
|
|
170
|
-
if (!hasCli) missing.push('slicejs-cli');
|
|
171
|
-
if (!hasFramework) missing.push('slicejs-web-framework');
|
|
176
|
+
const missing = ['slicejs-web-framework'];
|
|
172
177
|
|
|
173
178
|
return {
|
|
174
179
|
warn: true,
|
|
175
180
|
message: `Missing dependencies: ${missing.join(', ')}`,
|
|
176
|
-
suggestion: '
|
|
181
|
+
suggestion: missing.includes('slicejs-web-framework')
|
|
182
|
+
? 'Run "npm install slicejs-web-framework@latest" in your project'
|
|
183
|
+
: 'Run "npm install -D slicejs-cli@latest" in your project',
|
|
184
|
+
missing
|
|
177
185
|
};
|
|
178
186
|
}
|
|
179
187
|
} catch (error) {
|
|
@@ -313,6 +321,32 @@ export default async function runDiagnostics() {
|
|
|
313
321
|
Print.newLine();
|
|
314
322
|
Print.separator();
|
|
315
323
|
|
|
324
|
+
const depsResult = results.find(r => r.name === 'Dependencies');
|
|
325
|
+
if (depsResult && depsResult.warn && Array.isArray(depsResult.missing) && depsResult.missing.length > 0) {
|
|
326
|
+
const projectRoot = getProjectRoot(import.meta.url);
|
|
327
|
+
const execAsync = promisify(exec);
|
|
328
|
+
const { confirmInstall } = await inquirer.prompt([
|
|
329
|
+
{
|
|
330
|
+
type: 'confirm',
|
|
331
|
+
name: 'confirmInstall',
|
|
332
|
+
message: `Install missing dependencies in this project now? (${depsResult.missing.join(', ')})`,
|
|
333
|
+
default: true
|
|
334
|
+
}
|
|
335
|
+
]);
|
|
336
|
+
if (confirmInstall) {
|
|
337
|
+
for (const pkg of depsResult.missing) {
|
|
338
|
+
try {
|
|
339
|
+
const cmd = 'npm install slicejs-web-framework@latest';
|
|
340
|
+
Print.info(`Installing ${pkg}...`);
|
|
341
|
+
await execAsync(cmd, { cwd: projectRoot });
|
|
342
|
+
Print.success(`${pkg} installed`);
|
|
343
|
+
} catch (e) {
|
|
344
|
+
Print.error(`Installing ${pkg}: ${e.message}`);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
316
350
|
if (issues === 0 && warnings === 0) {
|
|
317
351
|
Print.success('All checks passed! 🎉');
|
|
318
352
|
Print.info('Your Slice.js project is correctly configured');
|
|
@@ -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
|
|
package/package.json
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "slicejs-cli",
|
|
3
|
-
"version": "2.7.
|
|
3
|
+
"version": "2.7.5",
|
|
4
4
|
"description": "Command client for developing web applications with Slice.js framework",
|
|
5
5
|
"main": "client.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"slice": "./client.js"
|
|
8
8
|
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/vkneider/slicejs-cli.git"
|
|
12
|
+
},
|
|
9
13
|
"scripts": {
|
|
10
14
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
11
15
|
"postinstall": "node post.js"
|
package/post.js
CHANGED
|
@@ -12,14 +12,14 @@ const targetRoot = initCwd || path.resolve(__dirname, '../../');
|
|
|
12
12
|
const projectPackageJsonPath = path.join(targetRoot, 'package.json');
|
|
13
13
|
|
|
14
14
|
if (isGlobal) {
|
|
15
|
-
console.log('ℹ️
|
|
16
|
-
console.log('
|
|
15
|
+
console.log('ℹ️ Global installation of slicejs-cli detected.');
|
|
16
|
+
console.log(' Skipping scripts setup. Use the binary directly:');
|
|
17
17
|
console.log(' slice dev');
|
|
18
18
|
console.log(' slice get Button');
|
|
19
19
|
process.exit(0);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
console.log('ℹ️
|
|
23
|
-
console.log('
|
|
24
|
-
console.log('
|
|
22
|
+
console.log('ℹ️ Local installation of slicejs-cli detected.');
|
|
23
|
+
console.log(' Skipping automatic scripts setup in postinstall.');
|
|
24
|
+
console.log(' Use "slice init" to configure project scripts.');
|
|
25
25
|
process.exit(0);
|