slicejs-cli 2.7.6 → 2.7.8
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.
|
@@ -19,6 +19,10 @@ export default async function bundle(options = {}) {
|
|
|
19
19
|
// Validate that it's a Slice.js project
|
|
20
20
|
await validateProject(projectRoot);
|
|
21
21
|
|
|
22
|
+
// Create default bundle config if needed
|
|
23
|
+
const bundleGenerator = new BundleGenerator(import.meta.url, null);
|
|
24
|
+
await bundleGenerator.createDefaultBundleConfig();
|
|
25
|
+
|
|
22
26
|
// Phase 1: Analysis
|
|
23
27
|
Print.buildProgress('Analyzing project...');
|
|
24
28
|
const analyzer = new DependencyAnalyzer(import.meta.url);
|
|
@@ -110,7 +114,8 @@ function printSummary(result, startTime) {
|
|
|
110
114
|
|
|
111
115
|
for (const [key, bundle] of Object.entries(bundles.routes)) {
|
|
112
116
|
console.log(` ${key}:`);
|
|
113
|
-
|
|
117
|
+
const routeDisplay = Array.isArray(bundle.path) ? `${bundle.path.length} routes` : (bundle.path || key);
|
|
118
|
+
console.log(` Route: ${routeDisplay}`);
|
|
114
119
|
console.log(` Components: ${bundle.components.length}`);
|
|
115
120
|
console.log(` Size: ${(bundle.size / 1024).toFixed(1)} KB`);
|
|
116
121
|
console.log(` File: ${bundle.file}`);
|
|
@@ -9,6 +9,7 @@ export default class BundleGenerator {
|
|
|
9
9
|
this.moduleUrl = moduleUrl;
|
|
10
10
|
this.analysisData = analysisData;
|
|
11
11
|
this.srcPath = getSrcPath(moduleUrl);
|
|
12
|
+
this.bundlesPath = path.join(this.srcPath, 'bundles');
|
|
12
13
|
this.componentsPath = path.dirname(getComponentsJsPath(moduleUrl));
|
|
13
14
|
|
|
14
15
|
// Configuration
|
|
@@ -35,6 +36,9 @@ export default class BundleGenerator {
|
|
|
35
36
|
async generate() {
|
|
36
37
|
console.log('🔨 Generating bundles...');
|
|
37
38
|
|
|
39
|
+
// 0. Create bundles directory
|
|
40
|
+
await fs.ensureDir(this.bundlesPath);
|
|
41
|
+
|
|
38
42
|
// 1. Determine optimal strategy
|
|
39
43
|
this.determineStrategy();
|
|
40
44
|
|
|
@@ -70,9 +74,9 @@ export default class BundleGenerator {
|
|
|
70
74
|
if (totalComponents < 20 || sharedPercentage > 60) {
|
|
71
75
|
this.config.strategy = 'global';
|
|
72
76
|
console.log('📦 Strategy: Global Bundle (small project or highly shared)');
|
|
73
|
-
} else if (totalComponents <
|
|
77
|
+
} else if (totalComponents < 100) {
|
|
74
78
|
this.config.strategy = 'hybrid';
|
|
75
|
-
console.log('📦 Strategy: Hybrid (critical +
|
|
79
|
+
console.log('📦 Strategy: Hybrid (critical + grouped routes)');
|
|
76
80
|
} else {
|
|
77
81
|
this.config.strategy = 'per-route';
|
|
78
82
|
console.log('📦 Strategy: Per Route (large project)');
|
|
@@ -95,8 +99,8 @@ export default class BundleGenerator {
|
|
|
95
99
|
const isStructural = comp.categoryType === 'Structural' ||
|
|
96
100
|
['Navbar', 'Footer', 'Layout'].includes(comp.name);
|
|
97
101
|
|
|
98
|
-
// Small and highly used components
|
|
99
|
-
const isSmallAndUseful = comp.size <
|
|
102
|
+
// Small and highly used components (only if used in 3+ routes)
|
|
103
|
+
const isSmallAndUseful = comp.size < 2000 && comp.routes.size >= 3;
|
|
100
104
|
|
|
101
105
|
return isShared || isStructural || isSmallAndUseful;
|
|
102
106
|
})
|
|
@@ -109,13 +113,27 @@ export default class BundleGenerator {
|
|
|
109
113
|
|
|
110
114
|
// Fill critical bundle up to limit
|
|
111
115
|
for (const comp of candidates) {
|
|
112
|
-
const
|
|
113
|
-
const
|
|
116
|
+
const dependencies = this.getComponentDependencies(comp);
|
|
117
|
+
const totalSize = comp.size + dependencies.reduce((sum, dep) => sum + dep.size, 0);
|
|
118
|
+
const totalCount = 1 + dependencies.length;
|
|
119
|
+
|
|
120
|
+
const wouldExceedSize = this.bundles.critical.size + totalSize > this.config.maxCriticalSize;
|
|
121
|
+
const wouldExceedCount = this.bundles.critical.components.length + totalCount > this.config.maxCriticalComponents;
|
|
122
|
+
|
|
123
|
+
if (wouldExceedSize || wouldExceedCount) continue;
|
|
114
124
|
|
|
115
|
-
|
|
125
|
+
// Add component and its dependencies
|
|
126
|
+
if (!this.bundles.critical.components.find(c => c.name === comp.name)) {
|
|
127
|
+
this.bundles.critical.components.push(comp);
|
|
128
|
+
this.bundles.critical.size += comp.size;
|
|
129
|
+
}
|
|
116
130
|
|
|
117
|
-
|
|
118
|
-
|
|
131
|
+
for (const dep of dependencies) {
|
|
132
|
+
if (!this.bundles.critical.components.find(c => c.name === dep.name)) {
|
|
133
|
+
this.bundles.critical.components.push(dep);
|
|
134
|
+
this.bundles.critical.size += dep.size;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
119
137
|
}
|
|
120
138
|
|
|
121
139
|
console.log(`✓ Critical bundle: ${this.bundles.critical.components.length} components, ${(this.bundles.critical.size / 1024).toFixed(1)} KB`);
|
|
@@ -127,12 +145,34 @@ export default class BundleGenerator {
|
|
|
127
145
|
assignRouteComponents() {
|
|
128
146
|
const criticalNames = new Set(this.bundles.critical.components.map(c => c.name));
|
|
129
147
|
|
|
130
|
-
|
|
148
|
+
if (this.config.strategy === 'hybrid') {
|
|
149
|
+
this.assignHybridBundles(criticalNames);
|
|
150
|
+
} else {
|
|
151
|
+
this.assignPerRouteBundles(criticalNames);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Assigns components to per-route bundles
|
|
157
|
+
*/
|
|
158
|
+
assignPerRouteBundles(criticalNames) {
|
|
159
|
+
for (const route of this.analysisData.routes) {
|
|
160
|
+
const routePath = route.path;
|
|
131
161
|
// Get all route dependencies
|
|
132
162
|
const routeComponents = this.getRouteComponents(route.component);
|
|
133
163
|
|
|
164
|
+
// Include dependencies for all route components
|
|
165
|
+
const allComponents = new Set();
|
|
166
|
+
for (const comp of routeComponents) {
|
|
167
|
+
allComponents.add(comp);
|
|
168
|
+
const dependencies = this.getComponentDependencies(comp);
|
|
169
|
+
for (const dep of dependencies) {
|
|
170
|
+
allComponents.add(dep);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
134
174
|
// Filter those already in critical
|
|
135
|
-
const uniqueComponents =
|
|
175
|
+
const uniqueComponents = Array.from(allComponents).filter(comp =>
|
|
136
176
|
!criticalNames.has(comp.name)
|
|
137
177
|
);
|
|
138
178
|
|
|
@@ -152,6 +192,105 @@ export default class BundleGenerator {
|
|
|
152
192
|
}
|
|
153
193
|
}
|
|
154
194
|
|
|
195
|
+
/**
|
|
196
|
+
* Gets all component dependencies transitively
|
|
197
|
+
*/
|
|
198
|
+
getComponentDependencies(component, visited = new Set()) {
|
|
199
|
+
if (visited.has(component.name)) return [];
|
|
200
|
+
visited.add(component.name);
|
|
201
|
+
|
|
202
|
+
const dependencies = [];
|
|
203
|
+
|
|
204
|
+
// Add direct dependencies
|
|
205
|
+
for (const depName of component.dependencies) {
|
|
206
|
+
const depComp = this.analysisData.components.find(c => c.name === depName);
|
|
207
|
+
if (depComp && !visited.has(depName)) {
|
|
208
|
+
dependencies.push(depComp);
|
|
209
|
+
// Add transitive dependencies
|
|
210
|
+
dependencies.push(...this.getComponentDependencies(depComp, visited));
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return dependencies;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Assigns components to hybrid bundles (grouped by category)
|
|
219
|
+
*/
|
|
220
|
+
assignHybridBundles(criticalNames) {
|
|
221
|
+
const routeGroups = new Map();
|
|
222
|
+
|
|
223
|
+
// Group routes by category
|
|
224
|
+
for (const route of this.analysisData.routes) {
|
|
225
|
+
const category = this.categorizeRoute(route.path);
|
|
226
|
+
if (!routeGroups.has(category)) {
|
|
227
|
+
routeGroups.set(category, []);
|
|
228
|
+
}
|
|
229
|
+
routeGroups.get(category).push(route);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Create bundles for each group
|
|
233
|
+
for (const [category, routes] of routeGroups) {
|
|
234
|
+
const allComponents = new Set();
|
|
235
|
+
|
|
236
|
+
// Collect all unique components for this category (including dependencies)
|
|
237
|
+
for (const route of routes) {
|
|
238
|
+
const routeComponents = this.getRouteComponents(route.component);
|
|
239
|
+
for (const comp of routeComponents) {
|
|
240
|
+
allComponents.add(comp);
|
|
241
|
+
// Add transitive dependencies
|
|
242
|
+
const dependencies = this.getComponentDependencies(comp);
|
|
243
|
+
for (const dep of dependencies) {
|
|
244
|
+
allComponents.add(dep);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Filter those already in critical
|
|
250
|
+
const uniqueComponents = Array.from(allComponents).filter(comp =>
|
|
251
|
+
!criticalNames.has(comp.name)
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
if (uniqueComponents.length === 0) continue;
|
|
255
|
+
|
|
256
|
+
const totalSize = uniqueComponents.reduce((sum, c) => sum + c.size, 0);
|
|
257
|
+
const routePaths = routes.map(r => r.path);
|
|
258
|
+
|
|
259
|
+
this.bundles.routes[category] = {
|
|
260
|
+
paths: routePaths,
|
|
261
|
+
components: uniqueComponents,
|
|
262
|
+
size: totalSize,
|
|
263
|
+
file: `slice-bundle.${category}.js`
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
console.log(`✓ Bundle ${category}: ${uniqueComponents.length} components, ${(totalSize / 1024).toFixed(1)} KB (${routes.length} routes)`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Categorizes a route path for grouping
|
|
272
|
+
*/
|
|
273
|
+
categorizeRoute(routePath) {
|
|
274
|
+
const path = routePath.toLowerCase();
|
|
275
|
+
|
|
276
|
+
if (path === '/' || path === '/home') return 'home';
|
|
277
|
+
if (path.includes('docum') || path.includes('documentation')) return 'documentation';
|
|
278
|
+
if (path.includes('component') || path.includes('visual') || path.includes('card') ||
|
|
279
|
+
path.includes('button') || path.includes('input') || path.includes('switch') ||
|
|
280
|
+
path.includes('checkbox') || path.includes('select') || path.includes('details') ||
|
|
281
|
+
path.includes('grid') || path.includes('loading') || path.includes('layout') ||
|
|
282
|
+
path.includes('navbar') || path.includes('treeview') || path.includes('multiroute')) return 'components';
|
|
283
|
+
if (path.includes('theme') || path.includes('slice') || path.includes('config')) return 'configuration';
|
|
284
|
+
if (path.includes('routing') || path.includes('guard')) return 'routing';
|
|
285
|
+
if (path.includes('service') || path.includes('command')) return 'services';
|
|
286
|
+
if (path.includes('structural') || path.includes('lifecycle') || path.includes('static') ||
|
|
287
|
+
path.includes('build')) return 'advanced';
|
|
288
|
+
if (path.includes('playground') || path.includes('creator')) return 'tools';
|
|
289
|
+
if (path.includes('about') || path.includes('404')) return 'misc';
|
|
290
|
+
|
|
291
|
+
return 'general';
|
|
292
|
+
}
|
|
293
|
+
|
|
155
294
|
/**
|
|
156
295
|
* Gets all components needed for a route
|
|
157
296
|
*/
|
|
@@ -199,7 +338,7 @@ export default class BundleGenerator {
|
|
|
199
338
|
const routeFile = await this.createBundleFile(
|
|
200
339
|
bundle.components,
|
|
201
340
|
'route',
|
|
202
|
-
bundle.path
|
|
341
|
+
bundle.path || routeKey // Use routeKey as fallback for hybrid bundles
|
|
203
342
|
);
|
|
204
343
|
files.push(routeFile);
|
|
205
344
|
}
|
|
@@ -213,7 +352,7 @@ export default class BundleGenerator {
|
|
|
213
352
|
async createBundleFile(components, type, routePath) {
|
|
214
353
|
const routeKey = routePath ? this.routeToFileName(routePath) : 'critical';
|
|
215
354
|
const fileName = `slice-bundle.${routeKey}.js`;
|
|
216
|
-
const filePath = path.join(this.
|
|
355
|
+
const filePath = path.join(this.bundlesPath, fileName);
|
|
217
356
|
|
|
218
357
|
const bundleContent = await this.generateBundleContent(
|
|
219
358
|
components,
|
|
@@ -235,6 +374,50 @@ export default class BundleGenerator {
|
|
|
235
374
|
};
|
|
236
375
|
}
|
|
237
376
|
|
|
377
|
+
/**
|
|
378
|
+
* Analyzes dependencies of a JavaScript file using simple regex
|
|
379
|
+
*/
|
|
380
|
+
analyzeDependencies(jsContent, componentPath) {
|
|
381
|
+
const dependencies = [];
|
|
382
|
+
|
|
383
|
+
try {
|
|
384
|
+
// Simple regex to find import statements
|
|
385
|
+
const importRegex = /import\s+.*?\s+from\s+['"`]([^'"`]+)['"`]/g;
|
|
386
|
+
let match;
|
|
387
|
+
|
|
388
|
+
while ((match = importRegex.exec(jsContent)) !== null) {
|
|
389
|
+
const importPath = match[1];
|
|
390
|
+
|
|
391
|
+
// Only process relative imports (starting with ./ or ../)
|
|
392
|
+
if (importPath.startsWith('./') || importPath.startsWith('../')) {
|
|
393
|
+
// Resolve the absolute path
|
|
394
|
+
const resolvedPath = path.resolve(componentPath, importPath);
|
|
395
|
+
|
|
396
|
+
// If no extension, try common extensions
|
|
397
|
+
let finalPath = resolvedPath;
|
|
398
|
+
const ext = path.extname(resolvedPath);
|
|
399
|
+
if (!ext) {
|
|
400
|
+
const extensions = ['.js', '.json', '.mjs'];
|
|
401
|
+
for (const ext of extensions) {
|
|
402
|
+
if (fs.existsSync(resolvedPath + ext)) {
|
|
403
|
+
finalPath = resolvedPath + ext;
|
|
404
|
+
break;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
if (fs.existsSync(finalPath)) {
|
|
410
|
+
dependencies.push(finalPath);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
} catch (error) {
|
|
415
|
+
console.warn(`Warning: Could not analyze dependencies for ${componentPath}:`, error.message);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return dependencies;
|
|
419
|
+
}
|
|
420
|
+
|
|
238
421
|
/**
|
|
239
422
|
* Generates the content of a bundle
|
|
240
423
|
*/
|
|
@@ -242,10 +425,23 @@ export default class BundleGenerator {
|
|
|
242
425
|
const componentsData = {};
|
|
243
426
|
|
|
244
427
|
for (const comp of components) {
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
428
|
+
const jsPath = path.join(comp.path, `${comp.name}.js`);
|
|
429
|
+
const jsContent = await fs.readFile(jsPath, 'utf-8');
|
|
430
|
+
|
|
431
|
+
// Analyze dependencies
|
|
432
|
+
const dependencies = this.analyzeDependencies(jsContent, comp.path);
|
|
433
|
+
const dependencyContents = {};
|
|
434
|
+
|
|
435
|
+
// Read all dependency files
|
|
436
|
+
for (const depPath of dependencies) {
|
|
437
|
+
try {
|
|
438
|
+
const depContent = await fs.readFile(depPath, 'utf-8');
|
|
439
|
+
const depName = path.basename(depPath, path.extname(depPath));
|
|
440
|
+
dependencyContents[depName] = depContent;
|
|
441
|
+
} catch (error) {
|
|
442
|
+
console.warn(`Warning: Could not read dependency ${depPath}:`, error.message);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
249
445
|
|
|
250
446
|
let htmlContent = null;
|
|
251
447
|
let cssContent = null;
|
|
@@ -266,10 +462,11 @@ export default class BundleGenerator {
|
|
|
266
462
|
category: comp.category,
|
|
267
463
|
categoryType: comp.categoryType,
|
|
268
464
|
js: this.cleanJavaScript(jsContent),
|
|
465
|
+
externalDependencies: dependencyContents, // Files imported with import statements
|
|
466
|
+
componentDependencies: Array.from(comp.dependencies), // Other components this one depends on
|
|
269
467
|
html: htmlContent,
|
|
270
468
|
css: cssContent,
|
|
271
|
-
size: comp.size
|
|
272
|
-
dependencies: Array.from(comp.dependencies)
|
|
469
|
+
size: comp.size
|
|
273
470
|
};
|
|
274
471
|
}
|
|
275
472
|
|
|
@@ -355,7 +552,7 @@ if (window.slice && window.slice.controller) {
|
|
|
355
552
|
|
|
356
553
|
for (const [key, bundle] of Object.entries(this.bundles.routes)) {
|
|
357
554
|
config.bundles.routes[key] = {
|
|
358
|
-
path: bundle.path,
|
|
555
|
+
path: bundle.path || bundle.paths || key, // Support both single path and array of paths, fallback to key
|
|
359
556
|
file: bundle.file,
|
|
360
557
|
size: bundle.size,
|
|
361
558
|
components: bundle.components.map(c => c.name),
|
|
@@ -382,8 +579,76 @@ if (window.slice && window.slice.controller) {
|
|
|
382
579
|
* Saves the configuration to file
|
|
383
580
|
*/
|
|
384
581
|
async saveBundleConfig(config) {
|
|
385
|
-
|
|
582
|
+
// Ensure bundles directory exists
|
|
583
|
+
await fs.ensureDir(this.bundlesPath);
|
|
584
|
+
|
|
585
|
+
// Save JSON config
|
|
586
|
+
const configPath = path.join(this.bundlesPath, 'bundle.config.json');
|
|
386
587
|
await fs.writeJson(configPath, config, { spaces: 2 });
|
|
588
|
+
|
|
589
|
+
// Generate JavaScript module for direct import
|
|
590
|
+
const jsConfigPath = path.join(this.bundlesPath, 'bundle.config.js');
|
|
591
|
+
const jsConfig = this.generateBundleConfigJS(config);
|
|
592
|
+
await fs.writeFile(jsConfigPath, jsConfig, 'utf-8');
|
|
593
|
+
|
|
387
594
|
console.log(`✓ Configuration saved to ${configPath}`);
|
|
595
|
+
console.log(`✓ JavaScript config generated: ${jsConfigPath}`);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* Creates a default bundle config file if none exists
|
|
600
|
+
*/
|
|
601
|
+
async createDefaultBundleConfig() {
|
|
602
|
+
const defaultConfigPath = path.join(this.srcPath, 'bundles', 'bundle.config.js');
|
|
603
|
+
|
|
604
|
+
// Only create if it doesn't exist
|
|
605
|
+
if (await fs.pathExists(defaultConfigPath)) {
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
await fs.ensureDir(path.dirname(defaultConfigPath));
|
|
610
|
+
|
|
611
|
+
const defaultConfig = `/**
|
|
612
|
+
* Slice.js Bundle Configuration
|
|
613
|
+
* Default empty configuration - no bundles available
|
|
614
|
+
* Run 'slice bundle' to generate optimized bundles
|
|
615
|
+
*/
|
|
616
|
+
|
|
617
|
+
// No bundles available - using individual component loading
|
|
618
|
+
export const SLICE_BUNDLE_CONFIG = null;
|
|
619
|
+
|
|
620
|
+
// No auto-initialization needed for default config
|
|
621
|
+
`;
|
|
622
|
+
|
|
623
|
+
await fs.writeFile(defaultConfigPath, defaultConfig, 'utf-8');
|
|
624
|
+
console.log(`✓ Default bundle config created: ${defaultConfigPath}`);
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* Generates JavaScript module for direct import
|
|
629
|
+
*/
|
|
630
|
+
generateBundleConfigJS(config) {
|
|
631
|
+
return `/**
|
|
632
|
+
* Slice.js Bundle Configuration
|
|
633
|
+
* Generated: ${new Date().toISOString()}
|
|
634
|
+
* Strategy: ${config.strategy}
|
|
635
|
+
*/
|
|
636
|
+
|
|
637
|
+
// Direct bundle configuration (no fetch required)
|
|
638
|
+
export const SLICE_BUNDLE_CONFIG = ${JSON.stringify(config, null, 2)};
|
|
639
|
+
|
|
640
|
+
// Auto-initialization if slice is available
|
|
641
|
+
if (typeof window !== 'undefined' && window.slice && window.slice.controller) {
|
|
642
|
+
window.slice.controller.bundleConfig = SLICE_BUNDLE_CONFIG;
|
|
643
|
+
|
|
644
|
+
// Load critical bundle automatically
|
|
645
|
+
if (SLICE_BUNDLE_CONFIG.bundles.critical && !window.slice.controller.criticalBundleLoaded) {
|
|
646
|
+
import('./slice-bundle.critical.js').catch(err =>
|
|
647
|
+
console.warn('Failed to load critical bundle:', err)
|
|
648
|
+
);
|
|
649
|
+
window.slice.controller.criticalBundleLoaded = true;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
`;
|
|
388
653
|
}
|
|
389
654
|
}
|
|
@@ -62,8 +62,8 @@ export default class DependencyAnalyzer {
|
|
|
62
62
|
// Read and parse components.js
|
|
63
63
|
const content = await fs.readFile(componentsConfigPath, 'utf-8');
|
|
64
64
|
|
|
65
|
-
// Extract configuration using simple regex
|
|
66
|
-
const configMatch = content.match(/
|
|
65
|
+
// Extract configuration using simple regex - look for the components object
|
|
66
|
+
const configMatch = content.match(/const components\s*=\s*({[\s\S]*?});/);
|
|
67
67
|
if (!configMatch) {
|
|
68
68
|
throw new Error('Could not parse components.js');
|
|
69
69
|
}
|
|
@@ -71,9 +71,26 @@ export default class DependencyAnalyzer {
|
|
|
71
71
|
// Evaluate safely (in production use a more robust parser)
|
|
72
72
|
const config = eval(`(${configMatch[1]})`);
|
|
73
73
|
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
|
|
74
|
+
// Group components by category
|
|
75
|
+
const categoryMap = new Map();
|
|
76
|
+
|
|
77
|
+
// Build category map from component assignments
|
|
78
|
+
for (const [componentName, categoryName] of Object.entries(config)) {
|
|
79
|
+
if (!categoryMap.has(categoryName)) {
|
|
80
|
+
categoryMap.set(categoryName, []);
|
|
81
|
+
}
|
|
82
|
+
categoryMap.get(categoryName).push(componentName);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Process each category
|
|
86
|
+
for (const [categoryName, componentList] of categoryMap) {
|
|
87
|
+
// Determine category type based on category name
|
|
88
|
+
let categoryType = 'Visual'; // default
|
|
89
|
+
if (categoryName === 'Service') categoryType = 'Service';
|
|
90
|
+
if (categoryName === 'AppComponents') categoryType = 'Visual'; // AppComponents are visual
|
|
91
|
+
|
|
92
|
+
// Find category path
|
|
93
|
+
const categoryPath = path.join(this.componentsPath, categoryName);
|
|
77
94
|
|
|
78
95
|
if (await fs.pathExists(categoryPath)) {
|
|
79
96
|
const files = await fs.readdir(categoryPath);
|
|
@@ -82,11 +99,11 @@ export default class DependencyAnalyzer {
|
|
|
82
99
|
const componentPath = path.join(categoryPath, file);
|
|
83
100
|
const stat = await fs.stat(componentPath);
|
|
84
101
|
|
|
85
|
-
if (stat.isDirectory()) {
|
|
102
|
+
if (stat.isDirectory() && componentList.includes(file)) {
|
|
86
103
|
this.components.set(file, {
|
|
87
104
|
name: file,
|
|
88
|
-
category,
|
|
89
|
-
categoryType:
|
|
105
|
+
category: categoryName,
|
|
106
|
+
categoryType: categoryType,
|
|
90
107
|
path: componentPath,
|
|
91
108
|
dependencies: new Set(),
|
|
92
109
|
usedBy: new Set(),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "slicejs-cli",
|
|
3
|
-
"version": "2.7.
|
|
3
|
+
"version": "2.7.8",
|
|
4
4
|
"description": "Command client for developing web applications with Slice.js framework",
|
|
5
5
|
"main": "client.js",
|
|
6
6
|
"bin": {
|
|
@@ -39,5 +39,9 @@
|
|
|
39
39
|
"ora": "^8.2.0",
|
|
40
40
|
"slicejs-web-framework": "latest",
|
|
41
41
|
"terser": "^5.43.1"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@babel/parser": "^7.28.5",
|
|
45
|
+
"@babel/traverse": "^7.28.5"
|
|
42
46
|
}
|
|
43
47
|
}
|