slicejs-cli 2.8.0 → 2.8.2
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/commands/init/init.js +56 -56
- package/commands/utils/PathHelper.js +68 -68
- package/commands/utils/VersionChecker.js +11 -11
- package/commands/utils/bundling/BundleGenerator.js +32 -129
- package/commands/utils/bundling/DependencyAnalyzer.js +270 -12
- package/commands/utils/updateManager.js +87 -87
- package/package.json +1 -1
package/commands/init/init.js
CHANGED
|
@@ -48,29 +48,29 @@ export default async function initializeProject(projectType) {
|
|
|
48
48
|
const srcDir = path.join(sliceBaseDir, 'src');
|
|
49
49
|
|
|
50
50
|
try {
|
|
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
|
-
}
|
|
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
|
+
}
|
|
57
57
|
|
|
58
58
|
// 1. COPIAR LA CARPETA API (mantener lógica original)
|
|
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
|
-
}
|
|
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
|
+
}
|
|
69
69
|
|
|
70
70
|
// 2. CREAR ESTRUCTURA SRC BÁSICA (sin copiar componentes Visual)
|
|
71
|
-
const srcSpinner = ora('Creating src structure...').start();
|
|
72
|
-
try {
|
|
73
|
-
if (!fs.existsSync(srcDir)) throw new Error(`src folder not found: ${srcDir}`);
|
|
71
|
+
const srcSpinner = ora('Creating src structure...').start();
|
|
72
|
+
try {
|
|
73
|
+
if (!fs.existsSync(srcDir)) throw new Error(`src folder not found: ${srcDir}`);
|
|
74
74
|
|
|
75
75
|
// Copiar solo los archivos base de src, excluyendo Components/Visual
|
|
76
76
|
await fs.ensureDir(destinationSrc);
|
|
@@ -94,22 +94,22 @@ export default async function initializeProject(projectType) {
|
|
|
94
94
|
const destComponentItemPath = path.join(destItemPath, componentItem);
|
|
95
95
|
|
|
96
96
|
if (componentItem !== 'Visual') {
|
|
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
|
-
}
|
|
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
|
+
}
|
|
113
113
|
|
|
114
114
|
srcSpinner.succeed('Source structure created successfully');
|
|
115
115
|
} catch (error) {
|
|
@@ -142,15 +142,15 @@ export default async function initializeProject(projectType) {
|
|
|
142
142
|
if (successful > 0 && failed === 0) {
|
|
143
143
|
componentsSpinner.succeed(`All ${successful} Visual components installed successfully`);
|
|
144
144
|
} else if (successful > 0) {
|
|
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
|
-
}
|
|
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
|
+
}
|
|
154
154
|
|
|
155
155
|
} catch (error) {
|
|
156
156
|
componentsSpinner.fail('Could not download Visual components from official repository');
|
|
@@ -222,21 +222,21 @@ export default async function initializeProject(projectType) {
|
|
|
222
222
|
console.log(' npm run get - Install components');
|
|
223
223
|
console.log(' npm run browse - Browse components');
|
|
224
224
|
} catch (error) {
|
|
225
|
-
pkgSpinner.fail('Failed to configure npm scripts');
|
|
226
|
-
Print.error(error.message);
|
|
227
|
-
}
|
|
225
|
+
pkgSpinner.fail('Failed to configure npm scripts');
|
|
226
|
+
Print.error(error.message);
|
|
227
|
+
}
|
|
228
228
|
|
|
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');
|
|
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');
|
|
235
235
|
|
|
236
236
|
} catch (error) {
|
|
237
|
-
Print.error('Unexpected error initializing project:', error.message);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
237
|
+
Print.error('Unexpected error initializing project:', error.message);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
240
|
|
|
241
241
|
/**
|
|
242
242
|
* Obtiene TODOS los componentes Visual disponibles en el registry
|
|
@@ -1,68 +1,68 @@
|
|
|
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 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
|
-
|
|
27
|
-
const dirs = candidates(moduleUrl)
|
|
28
|
-
for (const root of dirs) {
|
|
29
|
-
const hasSrc = fs.pathExistsSync(path.join(root, 'src'))
|
|
30
|
-
const hasApi = fs.pathExistsSync(path.join(root, 'api'))
|
|
31
|
-
if (hasSrc || hasApi) return root
|
|
32
|
-
}
|
|
33
|
-
return dirs[1]
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function joinProject(moduleUrl, ...segments) {
|
|
37
|
-
const root = resolveProjectRoot(moduleUrl)
|
|
38
|
-
const clean = segments.map(sanitize)
|
|
39
|
-
return path.join(root, ...clean)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function getProjectRoot(moduleUrl) {
|
|
43
|
-
return resolveProjectRoot(moduleUrl)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function getPath(moduleUrl, folder, ...segments) {
|
|
47
|
-
return joinProject(moduleUrl, folder, ...segments)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function getSrcPath(moduleUrl, ...segments) {
|
|
51
|
-
return joinProject(moduleUrl, 'src', ...segments)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function getApiPath(moduleUrl, ...segments) {
|
|
55
|
-
return joinProject(moduleUrl, 'api', ...segments)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export function getDistPath(moduleUrl, ...segments) {
|
|
59
|
-
return joinProject(moduleUrl, 'dist', ...segments)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export function getConfigPath(moduleUrl) {
|
|
63
|
-
return joinProject(moduleUrl, 'src', 'sliceConfig.json')
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export function getComponentsJsPath(moduleUrl) {
|
|
67
|
-
return joinProject(moduleUrl, 'src', 'Components', 'components.js')
|
|
68
|
-
}
|
|
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 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
|
+
|
|
27
|
+
const dirs = candidates(moduleUrl)
|
|
28
|
+
for (const root of dirs) {
|
|
29
|
+
const hasSrc = fs.pathExistsSync(path.join(root, 'src'))
|
|
30
|
+
const hasApi = fs.pathExistsSync(path.join(root, 'api'))
|
|
31
|
+
if (hasSrc || hasApi) return root
|
|
32
|
+
}
|
|
33
|
+
return dirs[1]
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function joinProject(moduleUrl, ...segments) {
|
|
37
|
+
const root = resolveProjectRoot(moduleUrl)
|
|
38
|
+
const clean = segments.map(sanitize)
|
|
39
|
+
return path.join(root, ...clean)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function getProjectRoot(moduleUrl) {
|
|
43
|
+
return resolveProjectRoot(moduleUrl)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function getPath(moduleUrl, folder, ...segments) {
|
|
47
|
+
return joinProject(moduleUrl, folder, ...segments)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function getSrcPath(moduleUrl, ...segments) {
|
|
51
|
+
return joinProject(moduleUrl, 'src', ...segments)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function getApiPath(moduleUrl, ...segments) {
|
|
55
|
+
return joinProject(moduleUrl, 'api', ...segments)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function getDistPath(moduleUrl, ...segments) {
|
|
59
|
+
return joinProject(moduleUrl, 'dist', ...segments)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function getConfigPath(moduleUrl) {
|
|
63
|
+
return joinProject(moduleUrl, 'src', 'sliceConfig.json')
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function getComponentsJsPath(moduleUrl) {
|
|
67
|
+
return joinProject(moduleUrl, 'src', 'Components', 'components.js')
|
|
68
|
+
}
|
|
@@ -1,10 +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";
|
|
7
|
-
import { getProjectRoot } from "../utils/PathHelper.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";
|
|
8
8
|
|
|
9
9
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
10
10
|
|
|
@@ -23,9 +23,9 @@ class VersionChecker {
|
|
|
23
23
|
const cliPackage = await fs.readJson(cliPackagePath);
|
|
24
24
|
this.currentCliVersion = cliPackage.version;
|
|
25
25
|
|
|
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');
|
|
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');
|
|
29
29
|
if (await fs.pathExists(frameworkPackagePath)) {
|
|
30
30
|
const frameworkPackage = await fs.readJson(frameworkPackagePath);
|
|
31
31
|
this.currentFrameworkVersion = frameworkPackage.version;
|
|
@@ -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('📦 Available Updates:');
|
|
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📋 Version Information:');
|
|
145
|
+
console.log('\n📋 Version Information:');
|
|
146
146
|
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
147
147
|
|
|
148
148
|
if (current?.cli) {
|
|
@@ -164,4 +164,4 @@ class VersionChecker {
|
|
|
164
164
|
// Singleton instance
|
|
165
165
|
const versionChecker = new VersionChecker();
|
|
166
166
|
|
|
167
|
-
export default versionChecker;
|
|
167
|
+
export default versionChecker;
|
|
@@ -256,7 +256,7 @@ export default class BundleGenerator {
|
|
|
256
256
|
paths: groupData.routes,
|
|
257
257
|
components: uniqueComponents,
|
|
258
258
|
size: totalSize,
|
|
259
|
-
file: `slice-bundle.${groupKey}.js`
|
|
259
|
+
file: `slice-bundle.${this.routeToFileName(groupKey)}.js`
|
|
260
260
|
};
|
|
261
261
|
|
|
262
262
|
console.log(`✓ Bundle ${groupKey}: ${uniqueComponents.length} components, ${(totalSize / 1024).toFixed(1)} KB (${groupData.routes.length} routes)`);
|
|
@@ -313,7 +313,7 @@ export default class BundleGenerator {
|
|
|
313
313
|
paths: routePaths,
|
|
314
314
|
components: uniqueComponents,
|
|
315
315
|
size: totalSize,
|
|
316
|
-
file: `slice-bundle.${category}.js`
|
|
316
|
+
file: `slice-bundle.${this.routeToFileName(category)}.js`
|
|
317
317
|
};
|
|
318
318
|
|
|
319
319
|
console.log(`✓ Bundle ${category}: ${uniqueComponents.length} components, ${(totalSize / 1024).toFixed(1)} KB (${routes.length} routes)`);
|
|
@@ -398,10 +398,14 @@ export default class BundleGenerator {
|
|
|
398
398
|
|
|
399
399
|
// 2. Route bundles
|
|
400
400
|
for (const [routeKey, bundle] of Object.entries(this.bundles.routes)) {
|
|
401
|
+
const routeIdentifier = Array.isArray(bundle.path || bundle.paths)
|
|
402
|
+
? routeKey
|
|
403
|
+
: (bundle.path || bundle.paths || routeKey);
|
|
404
|
+
|
|
401
405
|
const routeFile = await this.createBundleFile(
|
|
402
406
|
bundle.components,
|
|
403
407
|
'route',
|
|
404
|
-
|
|
408
|
+
routeIdentifier
|
|
405
409
|
);
|
|
406
410
|
files.push(routeFile);
|
|
407
411
|
}
|
|
@@ -524,7 +528,7 @@ export default class BundleGenerator {
|
|
|
524
528
|
name: comp.name,
|
|
525
529
|
category: comp.category,
|
|
526
530
|
categoryType: comp.categoryType,
|
|
527
|
-
js: this.cleanJavaScript(jsContent, comp.name
|
|
531
|
+
js: this.cleanJavaScript(jsContent, comp.name),
|
|
528
532
|
externalDependencies: dependencyContents, // Files imported with import statements
|
|
529
533
|
componentDependencies: Array.from(comp.dependencies), // Other components this one depends on
|
|
530
534
|
html: htmlContent,
|
|
@@ -547,134 +551,29 @@ export default class BundleGenerator {
|
|
|
547
551
|
}
|
|
548
552
|
|
|
549
553
|
/**
|
|
550
|
-
* Cleans JavaScript code by
|
|
554
|
+
* Cleans JavaScript code by removing imports/exports and ensuring class is available globally
|
|
551
555
|
*/
|
|
552
|
-
cleanJavaScript(code, componentName
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
//
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
let finalPath = absolutePath;
|
|
565
|
-
if (!fs.existsSync(finalPath)) {
|
|
566
|
-
if (fs.existsSync(finalPath + '.js')) finalPath += '.js';
|
|
567
|
-
else if (fs.existsSync(finalPath + '.json')) finalPath += '.json';
|
|
568
|
-
else {
|
|
569
|
-
console.warn(`BundleGenerator: Could not resolve ${importPath} in ${componentName}`);
|
|
570
|
-
return `/* Fail: File not found ${importPath} */`; // return comment so regular import stripper deletes it
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
let fileContent = fs.readFileSync(finalPath, 'utf-8');
|
|
575
|
-
|
|
576
|
-
// Parse Import Clause
|
|
577
|
-
let defaultImport = null;
|
|
578
|
-
let namedImports = [];
|
|
579
|
-
|
|
580
|
-
const cleanClause = importClause.trim();
|
|
581
|
-
|
|
582
|
-
if (cleanClause.includes('{')) {
|
|
583
|
-
// Has named imports
|
|
584
|
-
const parts = cleanClause.split('{');
|
|
585
|
-
const preBrace = parts[0].trim(); // "Default, " or ""
|
|
586
|
-
const braceContent = parts[1].replace('}', '').trim(); // "A, B as C"
|
|
587
|
-
|
|
588
|
-
if (preBrace) {
|
|
589
|
-
defaultImport = preBrace.replace(',', '').trim();
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
if (braceContent) {
|
|
593
|
-
namedImports = braceContent.split(',').map(i => {
|
|
594
|
-
const [name, alias] = i.split(/\s+as\s+/).map(s => s.trim());
|
|
595
|
-
return { name, alias: alias || name };
|
|
596
|
-
});
|
|
597
|
-
}
|
|
598
|
-
} else {
|
|
599
|
-
if (cleanClause.includes('*')) return match; // Skip namespace
|
|
600
|
-
defaultImport = cleanClause;
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
// Transform exported content to local variables
|
|
604
|
-
|
|
605
|
-
// STRATEGY:
|
|
606
|
-
// 1. Convert all 'const/let' to 'var' to allow redeclaration (resolves naming collisions)
|
|
607
|
-
// 2. Wrap exports
|
|
608
|
-
|
|
609
|
-
// Replace const/let with var globally to prevent "Identifier already declared" errors
|
|
610
|
-
// Use a sophisticated regex that handles:
|
|
611
|
-
// - Start of line or indentation
|
|
612
|
-
// - Previous statement termination (; or })
|
|
613
|
-
// - Optional export keyword
|
|
614
|
-
fileContent = fileContent.replace(/(^|[\s;}])(export\s+)?(const|let)(?=\s+)/gm, '$1$2var');
|
|
615
|
-
|
|
616
|
-
const defaultExportName = `__default_${path.basename(finalPath, path.extname(finalPath)).replace(/\W/g, '_')}_${Math.random().toString(36).substr(2, 5)}`;
|
|
617
|
-
|
|
618
|
-
// Handle export default
|
|
619
|
-
if (fileContent.includes('export default')) {
|
|
620
|
-
fileContent = fileContent.replace(/export\s+default\s+/g, `var ${defaultExportName} = `);
|
|
621
|
-
} else {
|
|
622
|
-
// If no export default, but we are importing default, try to find a variable with the same name
|
|
623
|
-
// This happens in legacy data files like: const data = ...; (no export default)
|
|
624
|
-
if (defaultImport) {
|
|
625
|
-
// Check if there is a variable matching the import name in the file content
|
|
626
|
-
const varRegex = new RegExp(`var\\s+${defaultImport}\\s*=`);
|
|
627
|
-
if (varRegex.test(fileContent)) {
|
|
628
|
-
// Found it, map it to our default export name for consistency
|
|
629
|
-
fileContent += `\nvar ${defaultExportName} = ${defaultImport};\n`;
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
// Handle named exports: remove 'export' keyword
|
|
635
|
-
fileContent = fileContent.replace(/^\s*export\s+/gm, '');
|
|
636
|
-
// Also clean up export { ... } statements
|
|
637
|
-
fileContent = fileContent.replace(/^\s*export\s*\{[^}]+\};?/gm, '');
|
|
638
|
-
|
|
639
|
-
let aliasCode = '';
|
|
640
|
-
|
|
641
|
-
// Map Default Import
|
|
642
|
-
if (defaultImport) {
|
|
643
|
-
// Use var for alias to be safe against existing variable
|
|
644
|
-
aliasCode += `if (typeof ${defaultImport} === 'undefined') { var ${defaultImport} = (typeof ${defaultExportName} !== 'undefined') ? ${defaultExportName} : undefined; }\n`;
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
// Map Named Imports with Aliases
|
|
648
|
-
namedImports.forEach(({ name, alias }) => {
|
|
649
|
-
if (name !== alias) {
|
|
650
|
-
aliasCode += `var ${alias} = ${name};\n`;
|
|
651
|
-
}
|
|
652
|
-
});
|
|
653
|
-
|
|
654
|
-
return `/* Inlined: ${importPath} */\n${fileContent}\n${aliasCode}`;
|
|
655
|
-
} catch (e) {
|
|
656
|
-
console.warn(`Failed to inline ${importPath} in ${componentName}: ${e.message}`);
|
|
657
|
-
return `/* Error inlining ${importPath}: ${e.message} */`;
|
|
658
|
-
}
|
|
659
|
-
});
|
|
660
|
-
|
|
661
|
-
// 2. Remove any remaining import statements (non-local or failed ones)
|
|
662
|
-
newCode = newCode.replace(/^.*import\s+.*from\s+['"`].*['"`];?.*$/gm, '');
|
|
663
|
-
|
|
664
|
-
// 3. Remove export default from the component itself
|
|
665
|
-
newCode = newCode.replace(/export\s+default\s+/g, '');
|
|
666
|
-
|
|
667
|
-
// 4. Make sure the class is available globally for bundle evaluation
|
|
668
|
-
if (newCode.includes('customElements.define')) {
|
|
669
|
-
newCode = newCode.replace(/customElements\.define\([^;]+\);?\s*$/, `window.${componentName} = ${componentName};\n$&`);
|
|
556
|
+
cleanJavaScript(code, componentName) {
|
|
557
|
+
// Remove export default
|
|
558
|
+
code = code.replace(/export\s+default\s+/g, '');
|
|
559
|
+
|
|
560
|
+
// Remove imports (components will already be available)
|
|
561
|
+
code = code.replace(/import\s+.*?from\s+['"].*?['"];?\s*/g, '');
|
|
562
|
+
|
|
563
|
+
// Make sure the class is available globally for bundle evaluation
|
|
564
|
+
// Preserve original customElements.define if it exists
|
|
565
|
+
if (code.includes('customElements.define')) {
|
|
566
|
+
// Add global assignment before customElements.define
|
|
567
|
+
code = code.replace(/customElements\.define\([^;]+\);?\s*$/, `window.${componentName} = ${componentName};\n$&`);
|
|
670
568
|
} else {
|
|
671
|
-
|
|
569
|
+
// If no customElements.define found, just assign to global
|
|
570
|
+
code += `\nwindow.${componentName} = ${componentName};`;
|
|
672
571
|
}
|
|
673
572
|
|
|
674
|
-
//
|
|
675
|
-
|
|
573
|
+
// Add return statement for bundle evaluation compatibility
|
|
574
|
+
code += `\nreturn ${componentName};`;
|
|
676
575
|
|
|
677
|
-
return
|
|
576
|
+
return code;
|
|
678
577
|
}
|
|
679
578
|
|
|
680
579
|
/**
|
|
@@ -732,9 +631,13 @@ if (window.slice && window.slice.controller) {
|
|
|
732
631
|
};
|
|
733
632
|
|
|
734
633
|
for (const [key, bundle] of Object.entries(this.bundles.routes)) {
|
|
634
|
+
const routeIdentifier = Array.isArray(bundle.path || bundle.paths)
|
|
635
|
+
? key
|
|
636
|
+
: (bundle.path || bundle.paths || key);
|
|
637
|
+
|
|
735
638
|
config.bundles.routes[key] = {
|
|
736
639
|
path: bundle.path || bundle.paths || key, // Support both single path and array of paths, fallback to key
|
|
737
|
-
file: bundle.
|
|
640
|
+
file: `slice-bundle.${this.routeToFileName(routeIdentifier)}.js`,
|
|
738
641
|
size: bundle.size,
|
|
739
642
|
components: bundle.components.map(c => c.name),
|
|
740
643
|
dependencies: ['critical']
|
|
@@ -832,4 +735,4 @@ if (typeof window !== 'undefined' && window.slice && window.slice.controller) {
|
|
|
832
735
|
}
|
|
833
736
|
`;
|
|
834
737
|
}
|
|
835
|
-
}
|
|
738
|
+
}
|
|
@@ -133,16 +133,280 @@ export default class DependencyAnalyzer {
|
|
|
133
133
|
component.size = await this.calculateComponentSize(component.path);
|
|
134
134
|
|
|
135
135
|
// Parse and extract dependencies
|
|
136
|
-
component.dependencies = await this.extractDependencies(content);
|
|
136
|
+
component.dependencies = await this.extractDependencies(content, jsFile);
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
/**
|
|
141
141
|
* Extracts dependencies from a component file
|
|
142
142
|
*/
|
|
143
|
-
async extractDependencies(code) {
|
|
143
|
+
async extractDependencies(code, componentFilePath = null) {
|
|
144
144
|
const dependencies = new Set();
|
|
145
145
|
|
|
146
|
+
const resolveRoutesArray = (node, scope) => {
|
|
147
|
+
if (!node) return null;
|
|
148
|
+
|
|
149
|
+
if (node.type === 'ArrayExpression') {
|
|
150
|
+
return node;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (node.type === 'ObjectExpression') {
|
|
154
|
+
const routesProp = node.properties.find(p => p.key?.name === 'routes');
|
|
155
|
+
if (routesProp?.value) {
|
|
156
|
+
return resolveRoutesArray(routesProp.value, scope);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (node.type === 'Identifier' && scope) {
|
|
161
|
+
const binding = scope.getBinding(node.name);
|
|
162
|
+
if (!binding) return null;
|
|
163
|
+
const bindingNode = binding.path?.node;
|
|
164
|
+
|
|
165
|
+
if (bindingNode?.type === 'VariableDeclarator') {
|
|
166
|
+
const init = bindingNode.init;
|
|
167
|
+
if (init?.type === 'ArrayExpression') {
|
|
168
|
+
return init;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (init?.type === 'Identifier') {
|
|
172
|
+
return resolveRoutesArray(init, binding.path.scope);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (init?.type === 'ObjectExpression') {
|
|
176
|
+
return resolveRoutesArray(init, binding.path.scope);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (init?.type === 'MemberExpression') {
|
|
180
|
+
return resolveRoutesArray(init, binding.path.scope);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (bindingNode?.type === 'ImportSpecifier' || bindingNode?.type === 'ImportDefaultSpecifier') {
|
|
185
|
+
const parent = binding.path.parentPath?.node;
|
|
186
|
+
if (parent?.type === 'ImportDeclaration') {
|
|
187
|
+
const importedName = bindingNode.type === 'ImportDefaultSpecifier'
|
|
188
|
+
? 'default'
|
|
189
|
+
: bindingNode.imported?.name;
|
|
190
|
+
const importedNode = resolveImportedValue(parent.source.value, importedName, componentFilePath);
|
|
191
|
+
return resolveRoutesArray(importedNode, null);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (node.type === 'MemberExpression' && scope) {
|
|
197
|
+
const objectNode = resolveObjectExpression(node.object, scope);
|
|
198
|
+
if (objectNode) {
|
|
199
|
+
const propName = node.property?.name || node.property?.value;
|
|
200
|
+
if (propName) {
|
|
201
|
+
const prop = objectNode.properties.find(p => p.key?.name === propName || p.key?.value === propName);
|
|
202
|
+
if (prop?.value) {
|
|
203
|
+
return resolveRoutesArray(prop.value, scope);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return null;
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
const resolveObjectExpression = (node, scope) => {
|
|
213
|
+
if (!node) return null;
|
|
214
|
+
if (node.type === 'ObjectExpression') return node;
|
|
215
|
+
|
|
216
|
+
if (node.type === 'Identifier' && scope) {
|
|
217
|
+
const binding = scope.getBinding(node.name);
|
|
218
|
+
const bindingNode = binding?.path?.node;
|
|
219
|
+
if (bindingNode?.type === 'VariableDeclarator') {
|
|
220
|
+
const init = bindingNode.init;
|
|
221
|
+
if (init?.type === 'ObjectExpression') {
|
|
222
|
+
return init;
|
|
223
|
+
}
|
|
224
|
+
if (init?.type === 'Identifier') {
|
|
225
|
+
return resolveObjectExpression(init, binding.path.scope);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (bindingNode?.type === 'ImportSpecifier' || bindingNode?.type === 'ImportDefaultSpecifier') {
|
|
230
|
+
const parent = binding.path.parentPath?.node;
|
|
231
|
+
if (parent?.type === 'ImportDeclaration') {
|
|
232
|
+
const importedName = bindingNode.type === 'ImportDefaultSpecifier'
|
|
233
|
+
? 'default'
|
|
234
|
+
: bindingNode.imported?.name;
|
|
235
|
+
const importedNode = resolveImportedValue(parent.source.value, importedName, componentFilePath);
|
|
236
|
+
return resolveObjectExpression(importedNode, null);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return null;
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
const resolveStringValue = (node, scope) => {
|
|
245
|
+
if (!node) return null;
|
|
246
|
+
if (node.type === 'StringLiteral') return node.value;
|
|
247
|
+
if (node.type === 'TemplateLiteral' && node.expressions.length === 0) {
|
|
248
|
+
return node.quasis.map(q => q.value.cooked).join('');
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (node.type === 'Identifier' && scope) {
|
|
252
|
+
const binding = scope.getBinding(node.name);
|
|
253
|
+
const bindingNode = binding?.path?.node;
|
|
254
|
+
if (bindingNode?.type === 'VariableDeclarator') {
|
|
255
|
+
return resolveStringValue(bindingNode.init, binding.path.scope);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (bindingNode?.type === 'ImportSpecifier' || bindingNode?.type === 'ImportDefaultSpecifier') {
|
|
259
|
+
const parent = binding.path.parentPath?.node;
|
|
260
|
+
if (parent?.type === 'ImportDeclaration') {
|
|
261
|
+
const importedName = bindingNode.type === 'ImportDefaultSpecifier'
|
|
262
|
+
? 'default'
|
|
263
|
+
: bindingNode.imported?.name;
|
|
264
|
+
const importedNode = resolveImportedValue(parent.source.value, importedName, componentFilePath);
|
|
265
|
+
return resolveStringValue(importedNode, null);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (node.type === 'MemberExpression' && scope) {
|
|
271
|
+
const objectNode = resolveObjectExpression(node.object, scope);
|
|
272
|
+
if (objectNode) {
|
|
273
|
+
const propName = node.property?.name || node.property?.value;
|
|
274
|
+
if (propName) {
|
|
275
|
+
const prop = objectNode.properties.find(p => p.key?.name === propName || p.key?.value === propName);
|
|
276
|
+
if (prop?.value) {
|
|
277
|
+
return resolveStringValue(prop.value, scope);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return null;
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
const resolveImportedValue = (importPath, importedName, fromFilePath) => {
|
|
287
|
+
if (!fromFilePath) return null;
|
|
288
|
+
|
|
289
|
+
const baseDir = path.dirname(fromFilePath);
|
|
290
|
+
const resolvedPath = resolveImportPath(importPath, baseDir);
|
|
291
|
+
if (!resolvedPath) {
|
|
292
|
+
console.warn(`⚠️ Cannot resolve import for MultiRoute routes: ${importPath}`);
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const cacheKey = `${resolvedPath}:${importedName || 'default'}`;
|
|
297
|
+
if (!resolveImportedValue.cache) {
|
|
298
|
+
resolveImportedValue.cache = new Map();
|
|
299
|
+
}
|
|
300
|
+
if (resolveImportedValue.cache.has(cacheKey)) {
|
|
301
|
+
return resolveImportedValue.cache.get(cacheKey);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
try {
|
|
305
|
+
const source = fs.readFileSync(resolvedPath, 'utf-8');
|
|
306
|
+
const importAst = parse(source, {
|
|
307
|
+
sourceType: 'module',
|
|
308
|
+
plugins: ['jsx']
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
const topLevelBindings = new Map();
|
|
312
|
+
for (const node of importAst.program.body) {
|
|
313
|
+
if (node.type === 'VariableDeclaration') {
|
|
314
|
+
node.declarations.forEach(decl => {
|
|
315
|
+
if (decl.id?.type === 'Identifier') {
|
|
316
|
+
topLevelBindings.set(decl.id.name, decl.init);
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
let exportNode = null;
|
|
323
|
+
for (const node of importAst.program.body) {
|
|
324
|
+
if (node.type === 'ExportDefaultDeclaration' && importedName === 'default') {
|
|
325
|
+
exportNode = node.declaration;
|
|
326
|
+
break;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (node.type === 'ExportNamedDeclaration') {
|
|
330
|
+
if (node.declaration?.type === 'VariableDeclaration') {
|
|
331
|
+
for (const decl of node.declaration.declarations) {
|
|
332
|
+
if (decl.id?.name === importedName) {
|
|
333
|
+
exportNode = decl.init;
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (!exportNode && node.specifiers?.length) {
|
|
340
|
+
const specifier = node.specifiers.find(s => s.exported?.name === importedName);
|
|
341
|
+
if (specifier && specifier.local?.name) {
|
|
342
|
+
exportNode = topLevelBindings.get(specifier.local.name) || null;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (exportNode) break;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (exportNode?.type === 'Identifier') {
|
|
351
|
+
exportNode = topLevelBindings.get(exportNode.name) || exportNode;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
resolveImportedValue.cache.set(cacheKey, exportNode || null);
|
|
355
|
+
return exportNode || null;
|
|
356
|
+
} catch (error) {
|
|
357
|
+
console.warn(`⚠️ Error resolving import ${importPath}: ${error.message}`);
|
|
358
|
+
resolveImportedValue.cache.set(cacheKey, null);
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
const resolveImportPath = (importPath, baseDir) => {
|
|
364
|
+
if (!importPath.startsWith('.')) return null;
|
|
365
|
+
|
|
366
|
+
const resolvedBase = path.resolve(baseDir, importPath);
|
|
367
|
+
const extensions = ['.js', '.mjs', '.cjs', '.json'];
|
|
368
|
+
|
|
369
|
+
if (fs.existsSync(resolvedBase) && fs.statSync(resolvedBase).isFile()) {
|
|
370
|
+
return resolvedBase;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (!path.extname(resolvedBase)) {
|
|
374
|
+
for (const ext of extensions) {
|
|
375
|
+
const candidate = resolvedBase + ext;
|
|
376
|
+
if (fs.existsSync(candidate)) {
|
|
377
|
+
return candidate;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
return null;
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
const addMultiRouteDependencies = (routesArrayNode, scope) => {
|
|
386
|
+
if (!routesArrayNode || routesArrayNode.type !== 'ArrayExpression') return;
|
|
387
|
+
|
|
388
|
+
routesArrayNode.elements.forEach(routeElement => {
|
|
389
|
+
if (!routeElement) return;
|
|
390
|
+
|
|
391
|
+
if (routeElement.type === 'SpreadElement') {
|
|
392
|
+
const spreadArray = resolveRoutesArray(routeElement.argument, scope);
|
|
393
|
+
addMultiRouteDependencies(spreadArray, scope);
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
const routeObject = resolveObjectExpression(routeElement, scope) || routeElement;
|
|
398
|
+
if (routeObject?.type === 'ObjectExpression') {
|
|
399
|
+
const componentProp = routeObject.properties.find(p => p.key?.name === 'component');
|
|
400
|
+
if (componentProp?.value) {
|
|
401
|
+
const componentName = resolveStringValue(componentProp.value, scope);
|
|
402
|
+
if (componentName) {
|
|
403
|
+
dependencies.add(componentName);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
};
|
|
409
|
+
|
|
146
410
|
try {
|
|
147
411
|
const ast = parse(code, {
|
|
148
412
|
sourceType: 'module',
|
|
@@ -168,15 +432,9 @@ export default class DependencyAnalyzer {
|
|
|
168
432
|
|
|
169
433
|
// Extract routes from MultiRoute props
|
|
170
434
|
const routesProp = args[1].properties.find(p => p.key?.name === 'routes');
|
|
171
|
-
if (routesProp
|
|
172
|
-
routesProp.value.
|
|
173
|
-
|
|
174
|
-
const componentProp = routeElement.properties.find(p => p.key?.name === 'component');
|
|
175
|
-
if (componentProp?.value?.type === 'StringLiteral') {
|
|
176
|
-
dependencies.add(componentProp.value.value);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
});
|
|
435
|
+
if (routesProp) {
|
|
436
|
+
const routesArrayNode = resolveRoutesArray(routesProp.value, path.scope);
|
|
437
|
+
addMultiRouteDependencies(routesArrayNode);
|
|
180
438
|
}
|
|
181
439
|
}
|
|
182
440
|
// Regular slice.build() calls
|
|
@@ -418,4 +676,4 @@ export default class DependencyAnalyzer {
|
|
|
418
676
|
console.log(` ${i + 1}. ${comp.name} - ${comp.routes} routes - ${(comp.size / 1024).toFixed(1)} KB`);
|
|
419
677
|
});
|
|
420
678
|
}
|
|
421
|
-
}
|
|
679
|
+
}
|
|
@@ -95,7 +95,7 @@ class UpdateManager {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
console.log('');
|
|
98
|
-
Print.warning('📦 Available Updates:');
|
|
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: '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
|
-
]);
|
|
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(`Updating ${packageName}...`).start();
|
|
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} 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
|
-
}
|
|
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('Checking for updates...').start();
|
|
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('Could not check for updates. Verify your internet connection.');
|
|
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('✅ All components are up to date!');
|
|
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('✅ All components are up to date!');
|
|
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 packages selected for update.');
|
|
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('🧭 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
|
-
});
|
|
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
|
-
message: 'Global CLI detected. Add the global CLI update to the plan?',
|
|
310
|
-
default: true
|
|
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('🧭 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
|
-
});
|
|
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('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
|
-
}
|
|
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: 'Do you want to proceed with the update according to the plan shown?',
|
|
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('Update cancelled.');
|
|
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('📥 Installing updates...');
|
|
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} package(s) updated successfully!`);
|
|
362
|
-
} else {
|
|
363
|
-
Print.warning(`⚠️ ${successCount} successful, ${failCount} failed`);
|
|
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('💡 It is recommended to restart the development server if it is running.');
|
|
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 during update: ${error.message}`);
|
|
376
|
-
return false;
|
|
377
|
-
}
|
|
375
|
+
Print.error(`Error during update: ${error.message}`);
|
|
376
|
+
return false;
|
|
377
|
+
}
|
|
378
378
|
}
|
|
379
379
|
}
|
|
380
380
|
|