slicejs-cli 2.6.0 → 2.7.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.
- package/client.js +23 -7
- package/commands/Validations.js +36 -18
- package/commands/buildProduction/buildProduction.js +12 -11
- package/commands/createComponent/createComponent.js +4 -5
- package/commands/deleteComponent/deleteComponent.js +5 -5
- package/commands/doctor/doctor.js +9 -9
- package/commands/getComponent/getComponent.js +40 -51
- package/commands/init/init.js +103 -7
- package/commands/listComponents/listComponents.js +5 -3
- package/commands/startServer/startServer.js +7 -6
- package/commands/utils/PathHelper.js +58 -0
- package/commands/utils/VersionChecker.js +9 -7
- package/commands/utils/updateManager.js +110 -10
- package/package.json +1 -1
- package/post.js +17 -138
package/client.js
CHANGED
|
@@ -8,11 +8,12 @@ import deleteComponent from "./commands/deleteComponent/deleteComponent.js";
|
|
|
8
8
|
import getComponent, { listComponents as listRemoteComponents, syncComponents } from "./commands/getComponent/getComponent.js";
|
|
9
9
|
import startServer from "./commands/startServer/startServer.js";
|
|
10
10
|
import runDiagnostics from "./commands/doctor/doctor.js";
|
|
11
|
-
import versionChecker from "./commands/utils/
|
|
11
|
+
import versionChecker from "./commands/utils/VersionChecker.js";
|
|
12
12
|
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
17
|
import validations from "./commands/Validations.js";
|
|
17
18
|
import Print from "./commands/Print.js";
|
|
18
19
|
|
|
@@ -20,7 +21,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
20
21
|
|
|
21
22
|
const loadConfig = () => {
|
|
22
23
|
try {
|
|
23
|
-
const configPath =
|
|
24
|
+
const configPath = getConfigPath(import.meta.url);
|
|
24
25
|
const rawData = fs.readFileSync(configPath, "utf-8");
|
|
25
26
|
return JSON.parse(rawData);
|
|
26
27
|
} catch (error) {
|
|
@@ -37,10 +38,13 @@ const getCategories = () => {
|
|
|
37
38
|
// Function to run version check for all commands
|
|
38
39
|
async function runWithVersionCheck(commandFunction, ...args) {
|
|
39
40
|
try {
|
|
40
|
-
|
|
41
|
+
const updateInfo = await updateManager.checkForUpdates();
|
|
42
|
+
if (updateInfo && updateInfo.hasUpdates) {
|
|
43
|
+
await updateManager.checkAndPromptUpdates({});
|
|
44
|
+
}
|
|
45
|
+
|
|
41
46
|
const result = await commandFunction(...args);
|
|
42
47
|
|
|
43
|
-
// Then check for updates (non-blocking)
|
|
44
48
|
setTimeout(() => {
|
|
45
49
|
versionChecker.checkForUpdates(false);
|
|
46
50
|
}, 100);
|
|
@@ -54,7 +58,7 @@ async function runWithVersionCheck(commandFunction, ...args) {
|
|
|
54
58
|
|
|
55
59
|
const sliceClient = program;
|
|
56
60
|
|
|
57
|
-
sliceClient.version("2.
|
|
61
|
+
sliceClient.version("2.6.1").description("CLI for managing Slice.js framework components");
|
|
58
62
|
|
|
59
63
|
// INIT COMMAND
|
|
60
64
|
sliceClient
|
|
@@ -337,6 +341,17 @@ sliceClient
|
|
|
337
341
|
});
|
|
338
342
|
});
|
|
339
343
|
|
|
344
|
+
// LIST COMMAND - Quick shortcut for listing local components
|
|
345
|
+
sliceClient
|
|
346
|
+
.command("list")
|
|
347
|
+
.description("Quick list all local components (alias for component list)")
|
|
348
|
+
.action(async () => {
|
|
349
|
+
await runWithVersionCheck(() => {
|
|
350
|
+
listComponents();
|
|
351
|
+
return Promise.resolve();
|
|
352
|
+
});
|
|
353
|
+
});
|
|
354
|
+
|
|
340
355
|
// UPDATE COMMAND
|
|
341
356
|
sliceClient
|
|
342
357
|
.command("update")
|
|
@@ -379,11 +394,12 @@ Common Usage Examples:
|
|
|
379
394
|
slice browse - Browse all available components
|
|
380
395
|
slice sync - Update local components to latest versions
|
|
381
396
|
slice component create - Create new local component
|
|
397
|
+
slice list - List all local components
|
|
382
398
|
slice doctor - Run project diagnostics
|
|
383
399
|
|
|
384
400
|
Command Categories:
|
|
385
401
|
• init, dev, start - Project lifecycle (development only)
|
|
386
|
-
• get, browse, sync
|
|
402
|
+
• get, browse, sync, list - Quick shortcuts
|
|
387
403
|
• component <cmd> - Local component management
|
|
388
404
|
• registry <cmd> - Official repository operations
|
|
389
405
|
• version, update, doctor - Maintenance commands
|
|
@@ -419,4 +435,4 @@ const helpCommand = sliceClient.command("help").description("Display help inform
|
|
|
419
435
|
sliceClient.outputHelp();
|
|
420
436
|
});
|
|
421
437
|
|
|
422
|
-
program.parse();
|
|
438
|
+
program.parse();
|
package/commands/Validations.js
CHANGED
|
@@ -1,14 +1,28 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
|
+
import { getConfigPath, getComponentsJsPath } from './utils/PathHelper.js';
|
|
4
5
|
|
|
5
6
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
6
7
|
|
|
7
8
|
class Validations {
|
|
8
9
|
constructor() {
|
|
9
|
-
this.
|
|
10
|
-
this.
|
|
10
|
+
this._config = null;
|
|
11
|
+
this._categories = null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
_ensureConfig() {
|
|
15
|
+
if (!this._config) {
|
|
16
|
+
this._config = this.loadConfig();
|
|
17
|
+
if (this._config) {
|
|
18
|
+
this._categories = this._config.paths?.components;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
11
22
|
|
|
23
|
+
get config() {
|
|
24
|
+
this._ensureConfig();
|
|
25
|
+
return this._config;
|
|
12
26
|
}
|
|
13
27
|
|
|
14
28
|
isValidComponentName(componentName) {
|
|
@@ -19,36 +33,40 @@ class Validations {
|
|
|
19
33
|
|
|
20
34
|
loadConfig() {
|
|
21
35
|
try {
|
|
22
|
-
const configPath =
|
|
36
|
+
const configPath = getConfigPath(import.meta.url);
|
|
23
37
|
if (!fs.existsSync(configPath)) {
|
|
24
|
-
|
|
25
|
-
console.log('\x1b[36m', 'ℹ️ Info: Run "slice init" to initialize your project', '\x1b[0m');
|
|
38
|
+
// Return null silently - let commands handle missing config if needed
|
|
26
39
|
return null;
|
|
27
|
-
|
|
40
|
+
}
|
|
28
41
|
const rawData = fs.readFileSync(configPath, 'utf-8');
|
|
29
|
-
|
|
42
|
+
|
|
30
43
|
return JSON.parse(rawData);
|
|
31
44
|
} catch (error) {
|
|
32
45
|
console.error('\x1b[31m', `❌ Error loading configuration: ${error.message}`, '\x1b[0m');
|
|
33
|
-
console.log('\x1b[36m', 'ℹ️ Info: Check that sliceConfig.json is valid JSON', '\x1b[0m');
|
|
34
46
|
return null;
|
|
35
47
|
}
|
|
36
48
|
}
|
|
37
49
|
|
|
38
50
|
getCategories() {
|
|
39
|
-
|
|
51
|
+
this._ensureConfig();
|
|
52
|
+
return this._categories;
|
|
40
53
|
}
|
|
41
54
|
|
|
42
55
|
getCategoryPath(category) {
|
|
43
|
-
|
|
56
|
+
this._ensureConfig();
|
|
57
|
+
return this._categories && this._categories[category] ? this._categories[category].path : null;
|
|
44
58
|
}
|
|
45
59
|
|
|
46
|
-
getCategoryType(category){
|
|
47
|
-
|
|
60
|
+
getCategoryType(category) {
|
|
61
|
+
this._ensureConfig();
|
|
62
|
+
return this._categories && this._categories[category] ? this._categories[category].type : null;
|
|
48
63
|
}
|
|
49
64
|
|
|
50
65
|
isValidCategory(category) {
|
|
51
|
-
|
|
66
|
+
this._ensureConfig();
|
|
67
|
+
if (!this._categories) return { isValid: false, category: null };
|
|
68
|
+
|
|
69
|
+
const availableCategories = Object.keys(this._categories).map(cat => cat.toLowerCase());
|
|
52
70
|
|
|
53
71
|
if (availableCategories.includes(category.toLowerCase())) {
|
|
54
72
|
return { isValid: true, category };
|
|
@@ -59,17 +77,17 @@ class Validations {
|
|
|
59
77
|
|
|
60
78
|
componentExists(componentName) {
|
|
61
79
|
try {
|
|
62
|
-
const componentFilePath =
|
|
63
|
-
|
|
80
|
+
const componentFilePath = getComponentsJsPath(import.meta.url);
|
|
81
|
+
|
|
64
82
|
if (!fs.existsSync(componentFilePath)) {
|
|
65
83
|
console.error('\x1b[31m', '❌ Error: components.js not found in expected path', '\x1b[0m');
|
|
66
84
|
console.log('\x1b[36m', 'ℹ️ Info: Run "slice component list" to generate components.js', '\x1b[0m');
|
|
67
85
|
return false;
|
|
68
86
|
}
|
|
69
|
-
|
|
87
|
+
|
|
70
88
|
const fileContent = fs.readFileSync(componentFilePath, 'utf-8');
|
|
71
89
|
const components = eval(fileContent.replace('export default', '')); // Evalúa el contenido como objeto
|
|
72
|
-
|
|
90
|
+
|
|
73
91
|
return components.hasOwnProperty(componentName);
|
|
74
92
|
|
|
75
93
|
} catch (error) {
|
|
@@ -82,4 +100,4 @@ class Validations {
|
|
|
82
100
|
|
|
83
101
|
const validations = new Validations();
|
|
84
102
|
|
|
85
|
-
export default validations;
|
|
103
|
+
export default validations;
|
|
@@ -7,6 +7,7 @@ import { minify as terserMinify } from 'terser';
|
|
|
7
7
|
import { minify } from 'html-minifier-terser';
|
|
8
8
|
import CleanCSS from 'clean-css';
|
|
9
9
|
import Print from '../Print.js';
|
|
10
|
+
import { getSrcPath, getDistPath, getConfigPath } from '../utils/PathHelper.js';
|
|
10
11
|
|
|
11
12
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
12
13
|
|
|
@@ -15,7 +16,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
15
16
|
*/
|
|
16
17
|
const loadConfig = () => {
|
|
17
18
|
try {
|
|
18
|
-
const configPath =
|
|
19
|
+
const configPath = getConfigPath(import.meta.url);
|
|
19
20
|
const rawData = fs.readFileSync(configPath, 'utf-8');
|
|
20
21
|
return JSON.parse(rawData);
|
|
21
22
|
} catch (error) {
|
|
@@ -28,7 +29,7 @@ const loadConfig = () => {
|
|
|
28
29
|
* Verifica dependencias necesarias para el build
|
|
29
30
|
*/
|
|
30
31
|
async function checkBuildDependencies() {
|
|
31
|
-
const srcDir =
|
|
32
|
+
const srcDir = getSrcPath(import.meta.url);
|
|
32
33
|
|
|
33
34
|
if (!await fs.pathExists(srcDir)) {
|
|
34
35
|
Print.error('Source directory (/src) not found');
|
|
@@ -103,8 +104,8 @@ async function verifyBuildIntegrity(distDir) {
|
|
|
103
104
|
* Copia sliceConfig.json al directorio dist
|
|
104
105
|
*/
|
|
105
106
|
async function copySliceConfig() {
|
|
106
|
-
const srcConfig =
|
|
107
|
-
const distConfig =
|
|
107
|
+
const srcConfig = getConfigPath(import.meta.url);
|
|
108
|
+
const distConfig = getDistPath(import.meta.url, 'sliceConfig.json');
|
|
108
109
|
|
|
109
110
|
if (await fs.pathExists(srcConfig)) {
|
|
110
111
|
await fs.copy(srcConfig, distConfig);
|
|
@@ -336,7 +337,7 @@ async function minifyHTML(srcPath, distPath) {
|
|
|
336
337
|
async function createOptimizedBundle() {
|
|
337
338
|
Print.buildProgress('Creating optimized bundle...');
|
|
338
339
|
|
|
339
|
-
const mainJSPath =
|
|
340
|
+
const mainJSPath = getDistPath(import.meta.url, 'App', 'index.js');
|
|
340
341
|
|
|
341
342
|
if (await fs.pathExists(mainJSPath)) {
|
|
342
343
|
Print.success('Main bundle optimized');
|
|
@@ -389,7 +390,7 @@ async function generateBuildStats(srcDir, distDir) {
|
|
|
389
390
|
* Analiza el build sin construir
|
|
390
391
|
*/
|
|
391
392
|
async function analyzeBuild() {
|
|
392
|
-
const distDir =
|
|
393
|
+
const distDir = getDistPath(import.meta.url);
|
|
393
394
|
|
|
394
395
|
if (!await fs.pathExists(distDir)) {
|
|
395
396
|
Print.error('No build found to analyze. Run "slice build" first.');
|
|
@@ -398,7 +399,7 @@ async function analyzeBuild() {
|
|
|
398
399
|
|
|
399
400
|
Print.info('Analyzing production build...');
|
|
400
401
|
await generateBuildStats(
|
|
401
|
-
|
|
402
|
+
getSrcPath(import.meta.url),
|
|
402
403
|
distDir
|
|
403
404
|
);
|
|
404
405
|
}
|
|
@@ -413,8 +414,8 @@ export default async function buildProduction(options = {}) {
|
|
|
413
414
|
Print.title('🔨 Building Slice.js project for production...');
|
|
414
415
|
Print.newLine();
|
|
415
416
|
|
|
416
|
-
const srcDir =
|
|
417
|
-
const distDir =
|
|
417
|
+
const srcDir = getSrcPath(import.meta.url);
|
|
418
|
+
const distDir = getDistPath(import.meta.url);
|
|
418
419
|
|
|
419
420
|
if (!await fs.pathExists(srcDir)) {
|
|
420
421
|
throw new Error('Source directory not found. Run "slice init" first.');
|
|
@@ -470,7 +471,7 @@ export async function serveProductionBuild(port) {
|
|
|
470
471
|
const defaultPort = config?.server?.port || 3001;
|
|
471
472
|
const finalPort = port || defaultPort;
|
|
472
473
|
|
|
473
|
-
const distDir =
|
|
474
|
+
const distDir = getDistPath(import.meta.url);
|
|
474
475
|
|
|
475
476
|
if (!await fs.pathExists(distDir)) {
|
|
476
477
|
throw new Error('No production build found. Run "slice build" first.');
|
|
@@ -540,4 +541,4 @@ export async function buildCommand(options = {}) {
|
|
|
540
541
|
}
|
|
541
542
|
|
|
542
543
|
return success;
|
|
543
|
-
}
|
|
544
|
+
}
|
|
@@ -5,7 +5,8 @@ import path from 'path';
|
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
6
|
import Validations from '../Validations.js';
|
|
7
7
|
import Print from '../Print.js';
|
|
8
|
-
|
|
8
|
+
import { getSrcPath } from '../utils/PathHelper.js';
|
|
9
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
10
|
|
|
10
11
|
function createComponent(componentName, category) {
|
|
11
12
|
// Validación: Nombre de componente requerido
|
|
@@ -62,10 +63,8 @@ function createComponent(componentName, category) {
|
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
const categoryPath = Validations.getCategoryPath(category);
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
let componentDir = path.join(__dirname, '../../../../src/', categoryPath, className);
|
|
68
|
-
componentDir = componentDir.slice(1);
|
|
66
|
+
const categoryPathClean = categoryPath ? categoryPath.replace(/^[/\\]+/, '') : '';
|
|
67
|
+
const componentDir = getSrcPath(import.meta.url, categoryPathClean, className);
|
|
69
68
|
|
|
70
69
|
try {
|
|
71
70
|
// Crear directorio del componente
|
|
@@ -2,7 +2,9 @@ import fs from 'fs-extra';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import Validations from '../Validations.js';
|
|
4
4
|
import Print from '../Print.js';
|
|
5
|
-
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import { getSrcPath } from '../utils/PathHelper.js';
|
|
7
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
6
8
|
|
|
7
9
|
function deleteComponent(componentName, category) {
|
|
8
10
|
// Validación: Nombre de componente requerido
|
|
@@ -31,10 +33,8 @@ function deleteComponent(componentName, category) {
|
|
|
31
33
|
category = flagCategory.category;
|
|
32
34
|
|
|
33
35
|
const categoryPath = Validations.getCategoryPath(category);
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
let componentDir = path.join(__dirname, '../../../../src/', categoryPath, componentName);
|
|
37
|
-
componentDir = componentDir.slice(1);
|
|
36
|
+
const categoryPathClean = categoryPath ? categoryPath.replace(/^[/\\]+/, '') : '';
|
|
37
|
+
const componentDir = getSrcPath(import.meta.url, categoryPathClean, componentName);
|
|
38
38
|
|
|
39
39
|
// Verificar si el directorio del componente existe
|
|
40
40
|
if (!fs.existsSync(componentDir)) {
|
|
@@ -5,6 +5,7 @@ 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 { getProjectRoot, getSrcPath, getApiPath, getConfigPath, getPath } from '../utils/PathHelper.js';
|
|
8
9
|
|
|
9
10
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
10
11
|
|
|
@@ -34,9 +35,8 @@ async function checkNodeVersion() {
|
|
|
34
35
|
* Verifica la estructura de directorios
|
|
35
36
|
*/
|
|
36
37
|
async function checkDirectoryStructure() {
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
const apiPath = path.join(projectRoot, 'api');
|
|
38
|
+
const srcPath = getSrcPath(import.meta.url);
|
|
39
|
+
const apiPath = getApiPath(import.meta.url);
|
|
40
40
|
|
|
41
41
|
const srcExists = await fs.pathExists(srcPath);
|
|
42
42
|
const apiExists = await fs.pathExists(apiPath);
|
|
@@ -63,7 +63,7 @@ async function checkDirectoryStructure() {
|
|
|
63
63
|
* Verifica sliceConfig.json
|
|
64
64
|
*/
|
|
65
65
|
async function checkConfig() {
|
|
66
|
-
const configPath =
|
|
66
|
+
const configPath = getConfigPath(import.meta.url);
|
|
67
67
|
|
|
68
68
|
if (!await fs.pathExists(configPath)) {
|
|
69
69
|
return {
|
|
@@ -101,7 +101,7 @@ async function checkConfig() {
|
|
|
101
101
|
* Verifica disponibilidad del puerto
|
|
102
102
|
*/
|
|
103
103
|
async function checkPort() {
|
|
104
|
-
const configPath =
|
|
104
|
+
const configPath = getConfigPath(import.meta.url);
|
|
105
105
|
let port = 3000;
|
|
106
106
|
|
|
107
107
|
try {
|
|
@@ -145,7 +145,7 @@ async function checkPort() {
|
|
|
145
145
|
* Verifica dependencias en package.json
|
|
146
146
|
*/
|
|
147
147
|
async function checkDependencies() {
|
|
148
|
-
const packagePath =
|
|
148
|
+
const packagePath = getPath(import.meta.url, '', 'package.json');
|
|
149
149
|
|
|
150
150
|
if (!await fs.pathExists(packagePath)) {
|
|
151
151
|
return {
|
|
@@ -189,8 +189,8 @@ async function checkDependencies() {
|
|
|
189
189
|
* Verifica integridad de componentes
|
|
190
190
|
*/
|
|
191
191
|
async function checkComponents() {
|
|
192
|
-
const configPath =
|
|
193
|
-
|
|
192
|
+
const configPath = getConfigPath(import.meta.url);
|
|
193
|
+
const projectRoot = getProjectRoot(import.meta.url);
|
|
194
194
|
|
|
195
195
|
if (!await fs.pathExists(configPath)) {
|
|
196
196
|
return {
|
|
@@ -208,7 +208,7 @@ async function checkComponents() {
|
|
|
208
208
|
let componentIssues = 0;
|
|
209
209
|
|
|
210
210
|
for (const [category, { path: compPath }] of Object.entries(componentPaths)) {
|
|
211
|
-
const fullPath =
|
|
211
|
+
const fullPath = getSrcPath(import.meta.url, compPath);
|
|
212
212
|
|
|
213
213
|
if (await fs.pathExists(fullPath)) {
|
|
214
214
|
const items = await fs.readdir(fullPath);
|
|
@@ -6,6 +6,7 @@ import { fileURLToPath } from "url";
|
|
|
6
6
|
import inquirer from "inquirer";
|
|
7
7
|
import validations from "../Validations.js";
|
|
8
8
|
import Print from "../Print.js";
|
|
9
|
+
import { getConfigPath, getComponentsJsPath, getPath } from "../utils/PathHelper.js";
|
|
9
10
|
|
|
10
11
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
11
12
|
|
|
@@ -19,8 +20,7 @@ const COMPONENTS_REGISTRY_URL = 'https://raw.githubusercontent.com/VKneider/slic
|
|
|
19
20
|
*/
|
|
20
21
|
const loadConfig = () => {
|
|
21
22
|
try {
|
|
22
|
-
|
|
23
|
-
const configPath = path.join(__dirname, '../../../../src/sliceConfig.json');
|
|
23
|
+
const configPath = getConfigPath(import.meta.url);
|
|
24
24
|
if (!fs.existsSync(configPath)) {
|
|
25
25
|
throw new Error('sliceConfig.json not found in src folder');
|
|
26
26
|
}
|
|
@@ -98,8 +98,7 @@ filterOfficialComponents(allComponents) {
|
|
|
98
98
|
|
|
99
99
|
async getLocalComponents() {
|
|
100
100
|
try {
|
|
101
|
-
|
|
102
|
-
const componentsPath = path.join(__dirname, '../../../../src/Components/components.js');
|
|
101
|
+
const componentsPath = getComponentsJsPath(import.meta.url);
|
|
103
102
|
|
|
104
103
|
if (!await fs.pathExists(componentsPath)) {
|
|
105
104
|
return {};
|
|
@@ -132,8 +131,7 @@ filterOfficialComponents(allComponents) {
|
|
|
132
131
|
// ✅ CORREGIDO: Usar 4 niveles para compatibilidad con node_modules
|
|
133
132
|
const isProduction = this.config?.production?.enabled === true;
|
|
134
133
|
const folderSuffix = isProduction ? 'dist' : 'src';
|
|
135
|
-
|
|
136
|
-
const componentPath = path.join(__dirname, `../../../../${folderSuffix}`, categoryPath, name);
|
|
134
|
+
const componentPath = getPath(import.meta.url, folderSuffix, categoryPath, name);
|
|
137
135
|
|
|
138
136
|
if (fs.pathExistsSync(componentPath)) {
|
|
139
137
|
updatableComponents.push({
|
|
@@ -180,43 +178,6 @@ filterOfficialComponents(allComponents) {
|
|
|
180
178
|
return components;
|
|
181
179
|
}
|
|
182
180
|
|
|
183
|
-
displayAvailableComponents() {
|
|
184
|
-
if (!this.componentsRegistry) {
|
|
185
|
-
Print.error('❌ No se pudo cargar el registro de componentes');
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
console.log('\n📚 Componentes disponibles en el repositorio oficial de Slice.js:\n');
|
|
190
|
-
|
|
191
|
-
const visualComponents = this.getAvailableComponents('Visual');
|
|
192
|
-
const serviceComponents = this.getAvailableComponents('Service');
|
|
193
|
-
|
|
194
|
-
// ✅ SIMPLIFICADO: Solo mostrar nombres sin descripciones
|
|
195
|
-
Print.info('🎨 Visual Components (UI):');
|
|
196
|
-
Object.keys(visualComponents).forEach(name => {
|
|
197
|
-
const files = visualComponents[name].files;
|
|
198
|
-
const fileIcons = files.map(file => {
|
|
199
|
-
if (file.endsWith('.js')) return '📜';
|
|
200
|
-
if (file.endsWith('.html')) return '🌐';
|
|
201
|
-
if (file.endsWith('.css')) return '🎨';
|
|
202
|
-
return '📄';
|
|
203
|
-
}).join(' ');
|
|
204
|
-
console.log(` • ${name} ${fileIcons}`);
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
Print.info('\n⚙️ Service Components (Logic):');
|
|
208
|
-
Object.keys(serviceComponents).forEach(name => {
|
|
209
|
-
console.log(` • ${name} 📜`);
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
Print.newLine();
|
|
213
|
-
Print.info(`Total: ${Object.keys(visualComponents).length} Visual + ${Object.keys(serviceComponents).length} Service components`);
|
|
214
|
-
|
|
215
|
-
console.log(`\n💡 Ejemplos de uso:`);
|
|
216
|
-
console.log(`slice get Button Card Input # Obtener componentes Visual`);
|
|
217
|
-
console.log(`slice get FetchManager --service # Obtener componente Service`);
|
|
218
|
-
console.log(`slice sync # Sincronizar componentes Visual`);
|
|
219
|
-
}
|
|
220
181
|
|
|
221
182
|
async downloadComponentFiles(componentName, category, targetPath) {
|
|
222
183
|
const component = this.getAvailableComponents(category)[componentName];
|
|
@@ -270,6 +231,36 @@ filterOfficialComponents(allComponents) {
|
|
|
270
231
|
return downloadedFiles;
|
|
271
232
|
}
|
|
272
233
|
|
|
234
|
+
async updateLocalRegistrySafe(componentName, category) {
|
|
235
|
+
const componentsPath = path.join(__dirname, '../../../../src/Components/components.js');
|
|
236
|
+
try {
|
|
237
|
+
if (!await fs.pathExists(componentsPath)) {
|
|
238
|
+
const dir = path.dirname(componentsPath);
|
|
239
|
+
await fs.ensureDir(dir);
|
|
240
|
+
const initial = `const components = {};\n\nexport default components;\n`;
|
|
241
|
+
await fs.writeFile(componentsPath, initial, 'utf8');
|
|
242
|
+
}
|
|
243
|
+
const content = await fs.readFile(componentsPath, 'utf8');
|
|
244
|
+
const match = content.match(/const components = ({[\s\S]*?});/);
|
|
245
|
+
if (!match) throw new Error('Invalid components.js format in local project');
|
|
246
|
+
const componentsObj = eval('(' + match[1] + ')');
|
|
247
|
+
if (!componentsObj[componentName]) {
|
|
248
|
+
componentsObj[componentName] = category;
|
|
249
|
+
const sorted = Object.keys(componentsObj)
|
|
250
|
+
.sort()
|
|
251
|
+
.reduce((obj, key) => { obj[key] = componentsObj[key]; return obj; }, {});
|
|
252
|
+
const newContent = `const components = ${JSON.stringify(sorted, null, 2)};\n\nexport default components;\n`;
|
|
253
|
+
await fs.writeFile(componentsPath, newContent, 'utf8');
|
|
254
|
+
Print.registryUpdate(`Registered ${componentName} in local components.js`);
|
|
255
|
+
} else {
|
|
256
|
+
Print.info(`${componentName} already exists in local registry`);
|
|
257
|
+
}
|
|
258
|
+
} catch (error) {
|
|
259
|
+
Print.error(`Updating local components.js: ${error.message}`);
|
|
260
|
+
throw error;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
273
264
|
async updateLocalRegistry(componentName, category) {
|
|
274
265
|
// ✅ CORREGIDO: Usar 4 niveles para compatibilidad con node_modules
|
|
275
266
|
const componentsPath = path.join(__dirname, '../../../../src/Components/components.js');
|
|
@@ -331,14 +322,12 @@ filterOfficialComponents(allComponents) {
|
|
|
331
322
|
validations.config.paths.components[category];
|
|
332
323
|
|
|
333
324
|
if (hasValidConfig) {
|
|
334
|
-
// Usar validations cuando la config está disponible
|
|
335
325
|
categoryPath = validations.getCategoryPath(category);
|
|
336
326
|
} else {
|
|
337
|
-
// Usar rutas por defecto cuando no hay config (durante init o error)
|
|
338
327
|
if (category === 'Visual') {
|
|
339
|
-
categoryPath = '
|
|
328
|
+
categoryPath = 'Components/Visual';
|
|
340
329
|
} else if (category === 'Service') {
|
|
341
|
-
categoryPath = '
|
|
330
|
+
categoryPath = 'Components/Service';
|
|
342
331
|
} else {
|
|
343
332
|
throw new Error(`Unknown category: ${category}`);
|
|
344
333
|
}
|
|
@@ -347,7 +336,8 @@ filterOfficialComponents(allComponents) {
|
|
|
347
336
|
const isProduction = this.config?.production?.enabled === true;
|
|
348
337
|
const folderSuffix = isProduction ? 'dist' : 'src';
|
|
349
338
|
|
|
350
|
-
const
|
|
339
|
+
const cleanCategoryPath = categoryPath ? categoryPath.replace(/^[/\\]+/, '') : '';
|
|
340
|
+
const targetPath = getPath(import.meta.url, folderSuffix, cleanCategoryPath, componentName);
|
|
351
341
|
|
|
352
342
|
|
|
353
343
|
|
|
@@ -375,8 +365,7 @@ filterOfficialComponents(allComponents) {
|
|
|
375
365
|
// Download component files
|
|
376
366
|
const downloadedFiles = await this.downloadComponentFiles(componentName, category, targetPath);
|
|
377
367
|
|
|
378
|
-
|
|
379
|
-
await this.updateLocalRegistry(componentName, category);
|
|
368
|
+
await this.updateLocalRegistrySafe(componentName, category);
|
|
380
369
|
|
|
381
370
|
Print.success(`${componentName} installed successfully from official repository!`);
|
|
382
371
|
console.log(`📁 Location: ${folderSuffix}/${categoryPath}/${componentName}/`);
|
|
@@ -717,4 +706,4 @@ async function syncComponents(options = {}) {
|
|
|
717
706
|
}
|
|
718
707
|
|
|
719
708
|
export default getComponents;
|
|
720
|
-
export { listComponents, syncComponents, ComponentRegistry };
|
|
709
|
+
export { listComponents, syncComponents, ComponentRegistry };
|
package/commands/init/init.js
CHANGED
|
@@ -3,6 +3,8 @@ import path from 'path';
|
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import ora from 'ora';
|
|
5
5
|
import Print from '../Print.js';
|
|
6
|
+
import { getProjectRoot, getApiPath, getSrcPath } from '../utils/PathHelper.js';
|
|
7
|
+
import { execSync } from 'child_process';
|
|
6
8
|
|
|
7
9
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
8
10
|
|
|
@@ -11,12 +13,39 @@ import { ComponentRegistry } from '../getComponent/getComponent.js';
|
|
|
11
13
|
|
|
12
14
|
export default async function initializeProject(projectType) {
|
|
13
15
|
try {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
let
|
|
16
|
+
const projectRoot = getProjectRoot(import.meta.url);
|
|
17
|
+
const destinationApi = getApiPath(import.meta.url);
|
|
18
|
+
const destinationSrc = getSrcPath(import.meta.url);
|
|
19
|
+
|
|
20
|
+
const fwSpinner = ora('Ensuring latest Slice framework...').start();
|
|
21
|
+
let sliceBaseDir;
|
|
22
|
+
try {
|
|
23
|
+
const latest = execSync('npm view slicejs-web-framework version', { cwd: projectRoot }).toString().trim();
|
|
24
|
+
const installedPkgPath = path.join(projectRoot, 'node_modules', 'slicejs-web-framework', 'package.json');
|
|
25
|
+
let installed = null;
|
|
26
|
+
if (await fs.pathExists(installedPkgPath)) {
|
|
27
|
+
const pkg = await fs.readJson(installedPkgPath);
|
|
28
|
+
installed = pkg.version;
|
|
29
|
+
}
|
|
30
|
+
if (installed !== latest) {
|
|
31
|
+
execSync(`npm install slicejs-web-framework@${latest} --save`, { cwd: projectRoot, stdio: 'inherit' });
|
|
32
|
+
}
|
|
33
|
+
sliceBaseDir = path.join(projectRoot, 'node_modules', 'slicejs-web-framework');
|
|
34
|
+
fwSpinner.succeed(`slicejs-web-framework@${latest} ready`);
|
|
35
|
+
} catch (err) {
|
|
36
|
+
const fallback = path.join(path.dirname(fileURLToPath(import.meta.url)), '../../../slicejs-web-framework');
|
|
37
|
+
if (await fs.pathExists(fallback)) {
|
|
38
|
+
sliceBaseDir = fallback;
|
|
39
|
+
fwSpinner.warn('Using local slicejs-web-framework fallback');
|
|
40
|
+
} else {
|
|
41
|
+
fwSpinner.fail('Failed to ensure latest slicejs-web-framework');
|
|
42
|
+
Print.error(err.message);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const apiDir = path.join(sliceBaseDir, 'api');
|
|
48
|
+
const srcDir = path.join(sliceBaseDir, 'src');
|
|
20
49
|
|
|
21
50
|
try {
|
|
22
51
|
// Verificar si los directorios de destino ya existen
|
|
@@ -131,6 +160,73 @@ export default async function initializeProject(projectType) {
|
|
|
131
160
|
Print.info('You can add them later using "slice get <component-name>"');
|
|
132
161
|
}
|
|
133
162
|
|
|
163
|
+
// 4. CONFIGURAR SCRIPTS EN package.json DEL PROYECTO
|
|
164
|
+
const pkgSpinner = ora('Configuring npm scripts...').start();
|
|
165
|
+
try {
|
|
166
|
+
const projectRoot = getProjectRoot(import.meta.url);
|
|
167
|
+
const pkgPath = path.join(projectRoot, 'package.json');
|
|
168
|
+
|
|
169
|
+
let pkg;
|
|
170
|
+
if (await fs.pathExists(pkgPath)) {
|
|
171
|
+
pkg = await fs.readJson(pkgPath);
|
|
172
|
+
} else {
|
|
173
|
+
pkg = {
|
|
174
|
+
name: path.basename(projectRoot),
|
|
175
|
+
version: '1.0.0',
|
|
176
|
+
description: 'Slice.js project',
|
|
177
|
+
main: 'api/index.js',
|
|
178
|
+
scripts: {}
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
pkg.scripts = pkg.scripts || {};
|
|
183
|
+
|
|
184
|
+
// Comandos principales
|
|
185
|
+
pkg.scripts['dev'] = 'slice dev';
|
|
186
|
+
pkg.scripts['start'] = 'slice start';
|
|
187
|
+
|
|
188
|
+
// Gestión de componentes
|
|
189
|
+
pkg.scripts['component:create'] = 'slice component create';
|
|
190
|
+
pkg.scripts['component:list'] = 'slice component list';
|
|
191
|
+
pkg.scripts['component:delete'] = 'slice component delete';
|
|
192
|
+
|
|
193
|
+
// Atajos de repositorio
|
|
194
|
+
pkg.scripts['get'] = 'slice get';
|
|
195
|
+
pkg.scripts['browse'] = 'slice browse';
|
|
196
|
+
pkg.scripts['sync'] = 'slice sync';
|
|
197
|
+
|
|
198
|
+
// Utilidades
|
|
199
|
+
pkg.scripts['slice:version'] = 'slice version';
|
|
200
|
+
pkg.scripts['slice:update'] = 'slice update';
|
|
201
|
+
|
|
202
|
+
// Legacy (compatibilidad)
|
|
203
|
+
pkg.scripts['slice:init'] = 'slice init';
|
|
204
|
+
pkg.scripts['slice:start'] = 'slice start';
|
|
205
|
+
pkg.scripts['slice:dev'] = 'slice dev';
|
|
206
|
+
pkg.scripts['slice:create'] = 'slice component create';
|
|
207
|
+
pkg.scripts['slice:list'] = 'slice component list';
|
|
208
|
+
pkg.scripts['slice:delete'] = 'slice component delete';
|
|
209
|
+
pkg.scripts['slice:get'] = 'slice get';
|
|
210
|
+
pkg.scripts['slice:browse'] = 'slice browse';
|
|
211
|
+
pkg.scripts['slice:sync'] = 'slice sync';
|
|
212
|
+
pkg.scripts['run'] = 'slice dev';
|
|
213
|
+
|
|
214
|
+
// Configuración de módulo
|
|
215
|
+
pkg.type = pkg.type || 'module';
|
|
216
|
+
pkg.engines = pkg.engines || { node: '>=20.0.0' };
|
|
217
|
+
|
|
218
|
+
await fs.writeFile(pkgPath, JSON.stringify(pkg, null, 2), 'utf8');
|
|
219
|
+
pkgSpinner.succeed('npm scripts configured successfully');
|
|
220
|
+
|
|
221
|
+
console.log('\n🎯 New recommended commands:');
|
|
222
|
+
console.log(' npm run dev - Start development server');
|
|
223
|
+
console.log(' npm run get - Install components');
|
|
224
|
+
console.log(' npm run browse - Browse components');
|
|
225
|
+
} catch (error) {
|
|
226
|
+
pkgSpinner.fail('Failed to configure npm scripts');
|
|
227
|
+
Print.error(error.message);
|
|
228
|
+
}
|
|
229
|
+
|
|
134
230
|
Print.success('Proyecto inicializado correctamente.');
|
|
135
231
|
Print.newLine();
|
|
136
232
|
Print.info('Next steps:');
|
|
@@ -155,4 +251,4 @@ async function getAllVisualComponents(registry) {
|
|
|
155
251
|
Print.info(`Found ${allVisualComponents.length} Visual components in official repository`);
|
|
156
252
|
|
|
157
253
|
return allVisualComponents;
|
|
158
|
-
}
|
|
254
|
+
}
|
|
@@ -4,6 +4,7 @@ import { fileURLToPath } from 'url';
|
|
|
4
4
|
import Table from 'cli-table3';
|
|
5
5
|
import chalk from 'chalk';
|
|
6
6
|
import Print from '../Print.js';
|
|
7
|
+
import { getSrcPath, getComponentsJsPath, getConfigPath } from '../utils/PathHelper.js';
|
|
7
8
|
|
|
8
9
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
10
|
|
|
@@ -13,7 +14,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
13
14
|
*/
|
|
14
15
|
const loadConfig = () => {
|
|
15
16
|
try {
|
|
16
|
-
const configPath =
|
|
17
|
+
const configPath = getConfigPath(import.meta.url);
|
|
17
18
|
if (!fs.existsSync(configPath)) {
|
|
18
19
|
Print.error('sliceConfig.json not found');
|
|
19
20
|
Print.info('Run "slice init" to initialize your project');
|
|
@@ -72,7 +73,8 @@ const getComponents = () => {
|
|
|
72
73
|
let allComponents = new Map();
|
|
73
74
|
|
|
74
75
|
Object.entries(componentPaths).forEach(([category, { path: folderPath }]) => {
|
|
75
|
-
const
|
|
76
|
+
const cleanFolderPath = folderPath ? folderPath.replace(/^[/\\]+/, '') : '';
|
|
77
|
+
const fullPath = getSrcPath(import.meta.url, cleanFolderPath);
|
|
76
78
|
const files = listComponents(fullPath);
|
|
77
79
|
|
|
78
80
|
files.forEach(file => {
|
|
@@ -150,7 +152,7 @@ function listComponentsReal() {
|
|
|
150
152
|
Print.info(`Total: ${Object.keys(components).length} component${Object.keys(components).length !== 1 ? 's' : ''} found`);
|
|
151
153
|
|
|
152
154
|
// Ruta donde se generará components.js
|
|
153
|
-
const outputPath =
|
|
155
|
+
const outputPath = getComponentsJsPath(import.meta.url);
|
|
154
156
|
|
|
155
157
|
// Asegurar que el directorio existe
|
|
156
158
|
const outputDir = path.dirname(outputPath);
|
|
@@ -7,6 +7,7 @@ import { spawn } from 'child_process';
|
|
|
7
7
|
import { createServer } from 'net';
|
|
8
8
|
import setupWatcher, { stopWatcher } from './watchServer.js';
|
|
9
9
|
import Print from '../Print.js';
|
|
10
|
+
import { getConfigPath, getApiPath, getSrcPath, getDistPath } from '../utils/PathHelper.js';
|
|
10
11
|
|
|
11
12
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
12
13
|
|
|
@@ -15,7 +16,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
15
16
|
*/
|
|
16
17
|
const loadConfig = () => {
|
|
17
18
|
try {
|
|
18
|
-
const configPath =
|
|
19
|
+
const configPath = getConfigPath(import.meta.url);
|
|
19
20
|
const rawData = fs.readFileSync(configPath, 'utf-8');
|
|
20
21
|
return JSON.parse(rawData);
|
|
21
22
|
} catch (error) {
|
|
@@ -52,7 +53,7 @@ async function isPortAvailable(port) {
|
|
|
52
53
|
* Verifica si existe un build de producción
|
|
53
54
|
*/
|
|
54
55
|
async function checkProductionBuild() {
|
|
55
|
-
const distDir =
|
|
56
|
+
const distDir = getDistPath(import.meta.url);
|
|
56
57
|
return await fs.pathExists(distDir);
|
|
57
58
|
}
|
|
58
59
|
|
|
@@ -60,8 +61,8 @@ async function checkProductionBuild() {
|
|
|
60
61
|
* Verifica si existe la estructura de desarrollo
|
|
61
62
|
*/
|
|
62
63
|
async function checkDevelopmentStructure() {
|
|
63
|
-
const srcDir =
|
|
64
|
-
const apiDir =
|
|
64
|
+
const srcDir = getSrcPath(import.meta.url);
|
|
65
|
+
const apiDir = getApiPath(import.meta.url);
|
|
65
66
|
|
|
66
67
|
return (await fs.pathExists(srcDir)) && (await fs.pathExists(apiDir));
|
|
67
68
|
}
|
|
@@ -71,7 +72,7 @@ async function checkDevelopmentStructure() {
|
|
|
71
72
|
*/
|
|
72
73
|
function startNodeServer(port, mode) {
|
|
73
74
|
return new Promise((resolve, reject) => {
|
|
74
|
-
const apiIndexPath =
|
|
75
|
+
const apiIndexPath = getApiPath(import.meta.url, 'index.js');
|
|
75
76
|
|
|
76
77
|
// Verificar que el archivo existe
|
|
77
78
|
if (!fs.existsSync(apiIndexPath)) {
|
|
@@ -235,4 +236,4 @@ export default async function startServer(options = {}) {
|
|
|
235
236
|
/**
|
|
236
237
|
* Funciones de utilidad exportadas
|
|
237
238
|
*/
|
|
238
|
-
export { checkProductionBuild, checkDevelopmentStructure, isPortAvailable };
|
|
239
|
+
export { checkProductionBuild, checkDevelopmentStructure, isPortAvailable };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import fs from 'fs-extra'
|
|
3
|
+
import { fileURLToPath } from 'url'
|
|
4
|
+
|
|
5
|
+
const sanitize = (s) => (s || '').replace(/^[/\\]+/, '')
|
|
6
|
+
const dirOf = (url) => path.dirname(fileURLToPath(url))
|
|
7
|
+
|
|
8
|
+
function candidates(moduleUrl) {
|
|
9
|
+
const dir = dirOf(moduleUrl)
|
|
10
|
+
return [
|
|
11
|
+
path.join(dir, '../../'),
|
|
12
|
+
path.join(dir, '../../../../')
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function resolveProjectRoot(moduleUrl) {
|
|
17
|
+
const dirs = candidates(moduleUrl)
|
|
18
|
+
for (const root of dirs) {
|
|
19
|
+
const hasSrc = fs.pathExistsSync(path.join(root, 'src'))
|
|
20
|
+
const hasApi = fs.pathExistsSync(path.join(root, 'api'))
|
|
21
|
+
if (hasSrc || hasApi) return root
|
|
22
|
+
}
|
|
23
|
+
return dirs[1]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function joinProject(moduleUrl, ...segments) {
|
|
27
|
+
const root = resolveProjectRoot(moduleUrl)
|
|
28
|
+
const clean = segments.map(sanitize)
|
|
29
|
+
return path.join(root, ...clean)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function getProjectRoot(moduleUrl) {
|
|
33
|
+
return resolveProjectRoot(moduleUrl)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function getPath(moduleUrl, folder, ...segments) {
|
|
37
|
+
return joinProject(moduleUrl, folder, ...segments)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function getSrcPath(moduleUrl, ...segments) {
|
|
41
|
+
return joinProject(moduleUrl, 'src', ...segments)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function getApiPath(moduleUrl, ...segments) {
|
|
45
|
+
return joinProject(moduleUrl, 'api', ...segments)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function getDistPath(moduleUrl, ...segments) {
|
|
49
|
+
return joinProject(moduleUrl, 'dist', ...segments)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function getConfigPath(moduleUrl) {
|
|
53
|
+
return joinProject(moduleUrl, 'src', 'sliceConfig.json')
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function getComponentsJsPath(moduleUrl) {
|
|
57
|
+
return joinProject(moduleUrl, 'src', 'Components', 'components.js')
|
|
58
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
// commands/utils/VersionChecker.js
|
|
2
2
|
|
|
3
|
-
import fs from "fs-extra";
|
|
4
|
-
import path from "path";
|
|
5
|
-
import { fileURLToPath } from "url";
|
|
6
|
-
import Print from "../Print.js";
|
|
3
|
+
import fs from "fs-extra";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
|
+
import Print from "../Print.js";
|
|
7
|
+
import { getProjectRoot } from "../utils/PathHelper.js";
|
|
7
8
|
|
|
8
9
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
10
|
|
|
@@ -22,8 +23,9 @@ class VersionChecker {
|
|
|
22
23
|
const cliPackage = await fs.readJson(cliPackagePath);
|
|
23
24
|
this.currentCliVersion = cliPackage.version;
|
|
24
25
|
|
|
25
|
-
// Get Framework version from node_modules
|
|
26
|
-
const
|
|
26
|
+
// Get Framework version from project node_modules
|
|
27
|
+
const projectRoot = getProjectRoot(import.meta.url);
|
|
28
|
+
const frameworkPackagePath = path.join(projectRoot, 'node_modules', 'slicejs-web-framework', 'package.json');
|
|
27
29
|
if (await fs.pathExists(frameworkPackagePath)) {
|
|
28
30
|
const frameworkPackage = await fs.readJson(frameworkPackagePath);
|
|
29
31
|
this.currentFrameworkVersion = frameworkPackage.version;
|
|
@@ -162,4 +164,4 @@ class VersionChecker {
|
|
|
162
164
|
// Singleton instance
|
|
163
165
|
const versionChecker = new VersionChecker();
|
|
164
166
|
|
|
165
|
-
export default versionChecker;
|
|
167
|
+
export default versionChecker;
|
|
@@ -5,7 +5,10 @@ import { promisify } from "util";
|
|
|
5
5
|
import inquirer from "inquirer";
|
|
6
6
|
import ora from "ora";
|
|
7
7
|
import Print from "../Print.js";
|
|
8
|
-
import versionChecker from "./
|
|
8
|
+
import versionChecker from "./VersionChecker.js";
|
|
9
|
+
import { getProjectRoot } from "../utils/PathHelper.js";
|
|
10
|
+
import path from "path";
|
|
11
|
+
import { fileURLToPath } from "url";
|
|
9
12
|
|
|
10
13
|
const execAsync = promisify(exec);
|
|
11
14
|
|
|
@@ -14,6 +17,31 @@ class UpdateManager {
|
|
|
14
17
|
this.packagesToUpdate = [];
|
|
15
18
|
}
|
|
16
19
|
|
|
20
|
+
async detectCliInstall() {
|
|
21
|
+
try {
|
|
22
|
+
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
23
|
+
const cliRoot = path.join(moduleDir, '../../');
|
|
24
|
+
const projectRoot = getProjectRoot(import.meta.url);
|
|
25
|
+
let globalPrefix = '';
|
|
26
|
+
try {
|
|
27
|
+
const { stdout } = await execAsync('npm config get prefix');
|
|
28
|
+
globalPrefix = stdout.toString().trim();
|
|
29
|
+
} catch {}
|
|
30
|
+
const localNodeModules = path.join(projectRoot, 'node_modules');
|
|
31
|
+
const globalNodeModules = globalPrefix ? path.join(globalPrefix, 'node_modules') : '';
|
|
32
|
+
|
|
33
|
+
if (cliRoot.startsWith(localNodeModules)) {
|
|
34
|
+
return { type: 'local', cliRoot, projectRoot, globalPrefix };
|
|
35
|
+
}
|
|
36
|
+
if (globalNodeModules && cliRoot.startsWith(globalNodeModules)) {
|
|
37
|
+
return { type: 'global', cliRoot, projectRoot, globalPrefix };
|
|
38
|
+
}
|
|
39
|
+
return { type: 'unknown', cliRoot, projectRoot, globalPrefix };
|
|
40
|
+
} catch (error) {
|
|
41
|
+
return { type: 'unknown' };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
17
45
|
/**
|
|
18
46
|
* Check for available updates and return structured info
|
|
19
47
|
*/
|
|
@@ -132,13 +160,45 @@ class UpdateManager {
|
|
|
132
160
|
return answers.packages;
|
|
133
161
|
}
|
|
134
162
|
|
|
163
|
+
async buildUpdatePlan(packages) {
|
|
164
|
+
const plan = [];
|
|
165
|
+
const info = await this.detectCliInstall();
|
|
166
|
+
for (const pkg of packages) {
|
|
167
|
+
if (pkg === 'slicejs-cli') {
|
|
168
|
+
if (info.type === 'global') {
|
|
169
|
+
plan.push({ package: pkg, target: 'global', command: 'npm install -g slicejs-cli@latest' });
|
|
170
|
+
} else {
|
|
171
|
+
plan.push({ package: pkg, target: 'project', command: 'npm install slicejs-cli@latest' });
|
|
172
|
+
}
|
|
173
|
+
} else if (pkg === 'slicejs-web-framework') {
|
|
174
|
+
plan.push({ package: pkg, target: 'project', command: 'npm install slicejs-web-framework@latest' });
|
|
175
|
+
} else {
|
|
176
|
+
plan.push({ package: pkg, target: 'project', command: `npm install ${pkg}@latest` });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return plan;
|
|
180
|
+
}
|
|
181
|
+
|
|
135
182
|
/**
|
|
136
183
|
* Execute npm update command for a specific package
|
|
137
184
|
*/
|
|
138
185
|
async updatePackage(packageName) {
|
|
139
186
|
try {
|
|
140
|
-
|
|
141
|
-
|
|
187
|
+
let command = `npm install ${packageName}@latest`;
|
|
188
|
+
let options = {};
|
|
189
|
+
|
|
190
|
+
if (packageName === 'slicejs-cli') {
|
|
191
|
+
const info = await this.detectCliInstall();
|
|
192
|
+
if (info.type === 'global') {
|
|
193
|
+
command = `npm install -g slicejs-cli@latest`;
|
|
194
|
+
} else {
|
|
195
|
+
options.cwd = info.projectRoot || getProjectRoot(import.meta.url);
|
|
196
|
+
}
|
|
197
|
+
} else {
|
|
198
|
+
options.cwd = getProjectRoot(import.meta.url);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const { stdout, stderr } = await execAsync(command, options);
|
|
142
202
|
|
|
143
203
|
return {
|
|
144
204
|
success: true,
|
|
@@ -213,24 +273,64 @@ class UpdateManager {
|
|
|
213
273
|
// Display available updates
|
|
214
274
|
this.displayUpdates(updateInfo);
|
|
215
275
|
|
|
216
|
-
|
|
217
|
-
|
|
276
|
+
// Get packages to update
|
|
277
|
+
const packagesToUpdate = await this.promptForUpdates(updateInfo, options);
|
|
218
278
|
|
|
219
279
|
if (!packagesToUpdate || packagesToUpdate.length === 0) {
|
|
220
280
|
Print.info('No se seleccionaron paquetes para actualizar.');
|
|
221
281
|
return false;
|
|
222
282
|
}
|
|
223
283
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
284
|
+
// Show plan and confirm installation if not auto-confirmed
|
|
285
|
+
let plan = await this.buildUpdatePlan(packagesToUpdate);
|
|
286
|
+
console.log('');
|
|
287
|
+
Print.info('🧭 Plan de actualización:');
|
|
288
|
+
plan.forEach(item => {
|
|
289
|
+
const where = item.target === 'global' ? 'GLOBAL' : 'PROYECTO';
|
|
290
|
+
console.log(` • ${item.package} → ${where}`);
|
|
291
|
+
console.log(` ${item.command}`);
|
|
292
|
+
});
|
|
293
|
+
console.log('');
|
|
294
|
+
|
|
295
|
+
const cliInfo = await this.detectCliInstall();
|
|
296
|
+
if (cliInfo.type === 'global' && !packagesToUpdate.includes('slicejs-cli')) {
|
|
297
|
+
if (!options.yes && !options.cli) {
|
|
298
|
+
const { addCli } = await inquirer.prompt([
|
|
227
299
|
{
|
|
228
300
|
type: 'confirm',
|
|
229
|
-
name: '
|
|
230
|
-
message: '
|
|
301
|
+
name: 'addCli',
|
|
302
|
+
message: 'Se detectó CLI global. ¿Agregar la actualización global del CLI al plan?',
|
|
231
303
|
default: true
|
|
232
304
|
}
|
|
233
305
|
]);
|
|
306
|
+
if (addCli) {
|
|
307
|
+
packagesToUpdate.push('slicejs-cli');
|
|
308
|
+
plan = await this.buildUpdatePlan(packagesToUpdate);
|
|
309
|
+
console.log('');
|
|
310
|
+
Print.info('🧭 Plan actualizado:');
|
|
311
|
+
plan.forEach(item => {
|
|
312
|
+
const where = item.target === 'global' ? 'GLOBAL' : 'PROYECTO';
|
|
313
|
+
console.log(` • ${item.package} → ${where}`);
|
|
314
|
+
console.log(` ${item.command}`);
|
|
315
|
+
});
|
|
316
|
+
console.log('');
|
|
317
|
+
}
|
|
318
|
+
} else {
|
|
319
|
+
Print.warning('CLI global detectado. Se recomienda actualizar slicejs-cli global para mantener alineado con el framework.');
|
|
320
|
+
console.log(' Sugerencia: npm install -g slicejs-cli@latest');
|
|
321
|
+
console.log('');
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (!options.yes && !options.cli && !options.framework) {
|
|
326
|
+
const { confirm } = await inquirer.prompt([
|
|
327
|
+
{
|
|
328
|
+
type: 'confirm',
|
|
329
|
+
name: 'confirm',
|
|
330
|
+
message: '¿Deseas continuar con la actualización según el plan mostrado?',
|
|
331
|
+
default: true
|
|
332
|
+
}
|
|
333
|
+
]);
|
|
234
334
|
|
|
235
335
|
if (!confirm) {
|
|
236
336
|
Print.info('Actualización cancelada.');
|
package/package.json
CHANGED
package/post.js
CHANGED
|
@@ -5,142 +5,21 @@ import Print from './commands/Print.js';
|
|
|
5
5
|
|
|
6
6
|
const __filename = fileURLToPath(import.meta.url);
|
|
7
7
|
const __dirname = path.dirname(__filename);
|
|
8
|
-
const projectName = path.basename(__dirname);
|
|
9
8
|
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
projectPackageJson.scripts['start'] = 'slice start';
|
|
28
|
-
|
|
29
|
-
// Component management
|
|
30
|
-
projectPackageJson.scripts['component:create'] = 'slice component create';
|
|
31
|
-
projectPackageJson.scripts['component:list'] = 'slice component list';
|
|
32
|
-
projectPackageJson.scripts['component:delete'] = 'slice component delete';
|
|
33
|
-
|
|
34
|
-
// Main repository commands (most used shortcuts)
|
|
35
|
-
projectPackageJson.scripts['get'] = 'slice get';
|
|
36
|
-
projectPackageJson.scripts['browse'] = 'slice browse';
|
|
37
|
-
projectPackageJson.scripts['sync'] = 'slice sync';
|
|
38
|
-
|
|
39
|
-
// Utility commands
|
|
40
|
-
projectPackageJson.scripts['slice:version'] = 'slice version';
|
|
41
|
-
projectPackageJson.scripts['slice:update'] = 'slice update';
|
|
42
|
-
|
|
43
|
-
// Legacy commands - mantener por compatibilidad temporal
|
|
44
|
-
projectPackageJson.scripts['slice:init'] = 'slice init';
|
|
45
|
-
projectPackageJson.scripts['slice:start'] = 'slice start';
|
|
46
|
-
projectPackageJson.scripts['slice:dev'] = 'slice dev';
|
|
47
|
-
projectPackageJson.scripts['slice:create'] = 'slice component create';
|
|
48
|
-
projectPackageJson.scripts['slice:list'] = 'slice component list';
|
|
49
|
-
projectPackageJson.scripts['slice:delete'] = 'slice component delete';
|
|
50
|
-
projectPackageJson.scripts['slice:get'] = 'slice get';
|
|
51
|
-
projectPackageJson.scripts['slice:browse'] = 'slice browse';
|
|
52
|
-
projectPackageJson.scripts['slice:sync'] = 'slice sync';
|
|
53
|
-
projectPackageJson.scripts['run'] = 'slice dev';
|
|
54
|
-
|
|
55
|
-
// Module configuration
|
|
56
|
-
projectPackageJson.type = 'module';
|
|
57
|
-
projectPackageJson.engines = {
|
|
58
|
-
"node": ">=20.0.0"
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
// Write the new content to package.json
|
|
62
|
-
return fs.promises.writeFile(projectPackageJsonPath, JSON.stringify(projectPackageJson, null, 2), 'utf8');
|
|
63
|
-
})
|
|
64
|
-
.then(() => {
|
|
65
|
-
console.log('✅ SliceJS CLI configured successfully');
|
|
66
|
-
console.log('\n🎯 New recommended commands:');
|
|
67
|
-
console.log(' slice dev - Start development server');
|
|
68
|
-
console.log(' slice get Button - Get components from repository');
|
|
69
|
-
console.log(' slice browse - View available components');
|
|
70
|
-
console.log(' slice component create - Create local component');
|
|
71
|
-
console.log('\n📦 Available npm scripts:');
|
|
72
|
-
console.log(' npm run dev - Start development server');
|
|
73
|
-
console.log(' npm run get - Install components');
|
|
74
|
-
console.log(' npm run browse - Browse components');
|
|
75
|
-
console.log('\n⚠️ Legacy commands (deprecated but still work):');
|
|
76
|
-
console.log(' npm run slice:dev - Use "slice dev" instead');
|
|
77
|
-
console.log(' npm run slice:get - Use "slice get" instead');
|
|
78
|
-
console.log('\n💡 You can also use npx:');
|
|
79
|
-
console.log(' npx slicejs-cli dev');
|
|
80
|
-
console.log('\n📘 Documentation: https://slice-js-docs.vercel.app/');
|
|
81
|
-
})
|
|
82
|
-
.catch(err => {
|
|
83
|
-
if (err.code === 'ENOENT') {
|
|
84
|
-
// The package.json file doesn't exist, so we create a new one with the commands
|
|
85
|
-
const defaultPackageJson = {
|
|
86
|
-
name: projectName,
|
|
87
|
-
version: '1.0.0',
|
|
88
|
-
description: 'Slice.js project',
|
|
89
|
-
main: 'api/index.js',
|
|
90
|
-
scripts: {
|
|
91
|
-
// Main workflow commands
|
|
92
|
-
'dev': 'slice dev',
|
|
93
|
-
'start': 'slice start',
|
|
94
|
-
|
|
95
|
-
// Component management
|
|
96
|
-
'component:create': 'slice component create',
|
|
97
|
-
'component:list': 'slice component list',
|
|
98
|
-
'component:delete': 'slice component delete',
|
|
99
|
-
|
|
100
|
-
// Repository commands
|
|
101
|
-
'get': 'slice get',
|
|
102
|
-
'browse': 'slice browse',
|
|
103
|
-
'sync': 'slice sync',
|
|
104
|
-
|
|
105
|
-
// Utility
|
|
106
|
-
'slice:version': 'slice version',
|
|
107
|
-
'slice:update': 'slice update',
|
|
108
|
-
|
|
109
|
-
// Legacy commands (for compatibility)
|
|
110
|
-
'slice:init': 'slice init',
|
|
111
|
-
'slice:start': 'slice start',
|
|
112
|
-
'slice:dev': 'slice dev',
|
|
113
|
-
'slice:create': 'slice component create',
|
|
114
|
-
'slice:list': 'slice component list',
|
|
115
|
-
'slice:delete': 'slice component delete',
|
|
116
|
-
'slice:get': 'slice get',
|
|
117
|
-
'slice:browse': 'slice browse',
|
|
118
|
-
'slice:sync': 'slice sync',
|
|
119
|
-
'run': 'slice dev'
|
|
120
|
-
},
|
|
121
|
-
type: 'module',
|
|
122
|
-
engines: {
|
|
123
|
-
"node": ">=20.0.0"
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
return fs.promises.writeFile(projectPackageJsonPath, JSON.stringify(defaultPackageJson, null, 2), 'utf8');
|
|
128
|
-
} else {
|
|
129
|
-
throw err;
|
|
130
|
-
}
|
|
131
|
-
})
|
|
132
|
-
.then(() => {
|
|
133
|
-
console.log('✅ SliceJS CLI commands configured successfully');
|
|
134
|
-
console.log('\n🎯 Simplified development workflow:');
|
|
135
|
-
console.log(' slice dev → Start development server');
|
|
136
|
-
console.log(' slice get Button → Install components');
|
|
137
|
-
console.log(' slice browse → View available components');
|
|
138
|
-
console.log('\n🔧 Benefits:');
|
|
139
|
-
console.log(' • Simple and direct commands');
|
|
140
|
-
console.log(' • Can be used globally or with npx');
|
|
141
|
-
console.log(' • Legacy npm scripts still work for compatibility');
|
|
142
|
-
})
|
|
143
|
-
.catch(err => {
|
|
144
|
-
console.error('❌ Error setting up package.json:', err.message);
|
|
145
|
-
process.exit(1);
|
|
146
|
-
});
|
|
9
|
+
const isGlobal = process.env.npm_config_global === 'true';
|
|
10
|
+
const initCwd = process.env.INIT_CWD ? path.resolve(process.env.INIT_CWD) : null;
|
|
11
|
+
const targetRoot = initCwd || path.resolve(__dirname, '../../');
|
|
12
|
+
const projectPackageJsonPath = path.join(targetRoot, 'package.json');
|
|
13
|
+
|
|
14
|
+
if (isGlobal) {
|
|
15
|
+
console.log('ℹ️ Instalación global detectada de slicejs-cli.');
|
|
16
|
+
console.log(' Omite configuración de scripts. Usa el binario directamente:');
|
|
17
|
+
console.log(' slice dev');
|
|
18
|
+
console.log(' slice get Button');
|
|
19
|
+
process.exit(0);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
console.log('ℹ️ Instalación local detectada de slicejs-cli.');
|
|
23
|
+
console.log(' Se omite configuración automática de scripts en postinstall.');
|
|
24
|
+
console.log(' Usa "slice init" para configurar los scripts del proyecto.');
|
|
25
|
+
process.exit(0);
|