slicejs-cli 3.3.0 → 3.4.1

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.
Files changed (46) hide show
  1. package/AGENTS.md +247 -0
  2. package/LICENSE +21 -21
  3. package/client.js +663 -626
  4. package/commands/Print.js +163 -167
  5. package/commands/Validations.js +92 -103
  6. package/commands/build/build.js +40 -40
  7. package/commands/buildProduction/buildProduction.js +576 -579
  8. package/commands/bundle/bundle.js +234 -235
  9. package/commands/createComponent/VisualComponentTemplate.js +55 -55
  10. package/commands/createComponent/createComponent.js +124 -126
  11. package/commands/deleteComponent/deleteComponent.js +77 -77
  12. package/commands/doctor/doctor.js +366 -369
  13. package/commands/getComponent/getComponent.js +684 -747
  14. package/commands/init/init.js +269 -261
  15. package/commands/listComponents/listComponents.js +172 -175
  16. package/commands/startServer/startServer.js +261 -264
  17. package/commands/startServer/watchServer.js +79 -79
  18. package/commands/types/types.js +69 -27
  19. package/commands/utils/LocalCliDelegation.js +53 -53
  20. package/commands/utils/PathHelper.js +75 -68
  21. package/commands/utils/VersionChecker.js +167 -167
  22. package/commands/utils/bundling/BundleGenerator.js +2292 -2292
  23. package/commands/utils/bundling/DependencyAnalyzer.js +925 -933
  24. package/commands/utils/loadConfig.js +31 -0
  25. package/commands/utils/updateManager.js +452 -453
  26. package/docs/superpowers/specs/2026-05-10-pwa-generate-design.md +105 -105
  27. package/package.json +58 -46
  28. package/post.js +66 -65
  29. package/tests/bundle-generator.test.js +691 -708
  30. package/tests/bundle-v2-register-output.test.js +470 -470
  31. package/tests/client-launcher-contract.test.js +211 -211
  32. package/tests/client-update-flow-contract.test.js +272 -272
  33. package/tests/component-registry-parse.test.js +34 -0
  34. package/tests/dependency-analyzer.test.js +24 -24
  35. package/tests/fixtures/components.js +8 -0
  36. package/tests/fixtures/sliceConfig.json +74 -0
  37. package/tests/getcomponent.test.js +407 -0
  38. package/tests/helpers/setup.js +97 -0
  39. package/tests/init-command-contract.test.js +46 -0
  40. package/tests/local-cli-delegation.test.js +81 -79
  41. package/tests/path-helper.test.js +206 -0
  42. package/tests/types-breakage.test.js +491 -0
  43. package/tests/types-generator-errors.test.js +361 -0
  44. package/tests/types-generator.test.js +172 -184
  45. package/tests/update-manager-notifications.test.js +88 -88
  46. package/.github/workflows/docs-render-cicd.yml +0 -65
@@ -1,235 +1,234 @@
1
- // cli/commands/bundle/bundle.js
2
- import path from 'path';
3
- import fs from 'fs-extra';
4
- import DependencyAnalyzer from '../utils/bundling/DependencyAnalyzer.js';
5
- import BundleGenerator from '../utils/bundling/BundleGenerator.js';
6
- import Print from '..//Print.js';
7
-
8
- /**
9
- * Main bundling command
10
- */
11
- export default async function bundle(options = {}) {
12
- const startTime = Date.now();
13
- const projectRoot = process.cwd();
14
-
15
- try {
16
- Print.title('📦 Slice.js Bundle Generator');
17
- Print.newLine();
18
-
19
- // Validate that it's a Slice.js project
20
- await validateProject(projectRoot);
21
-
22
- // Create default bundle config if needed
23
- const bundleGenerator = new BundleGenerator(import.meta.url, null);
24
- await bundleGenerator.createDefaultBundleConfig();
25
-
26
- // Phase 1: Analysis
27
- Print.buildProgress('Analyzing project...');
28
- const analyzer = new DependencyAnalyzer(import.meta.url);
29
- const analysisData = await analyzer.analyze();
30
-
31
- // Show report if in verbose mode
32
- if (options.verbose || options.analyze) {
33
- Print.newLine();
34
- analyzer.generateReport(analysisData.metrics);
35
- Print.newLine();
36
- }
37
-
38
- // If only analysis is requested, finish here
39
- if (options.analyze) {
40
- Print.success('Analysis completed');
41
- return;
42
- }
43
-
44
- // Phase 2: Bundle generation
45
- Print.buildProgress('Generating bundles...');
46
- const generator = new BundleGenerator(import.meta.url, analysisData, {
47
- minify: !!options.minify,
48
- obfuscate: !!options.obfuscate,
49
- output: options.output || 'src'
50
- });
51
- const result = await generator.generate();
52
-
53
- // Phase 3: Save configuration
54
- Print.buildProgress('Saving configuration...');
55
- await generator.saveBundleConfig(result.config);
56
-
57
- // Phase 4: Summary
58
- Print.newLine();
59
- printSummary(result, startTime);
60
-
61
- // Show next step
62
- Print.newLine();
63
- Print.info('💡 Next step:');
64
- console.log(' Update your Slice.js to use the generated bundles');
65
- console.log(' Bundles will load automatically in production\n');
66
-
67
- } catch (error) {
68
- Print.error('Error generating bundles:', error.message);
69
- console.error('\n📍 Complete stack trace:');
70
- console.error(error.stack);
71
-
72
- if (error.code) {
73
- console.error('\n📍 Error code:', error.code);
74
- }
75
-
76
- process.exit(1);
77
- }
78
- }
79
-
80
- /**
81
- * Validates that the project has the correct structure
82
- */
83
- async function validateProject(projectRoot) {
84
- const requiredPaths = [
85
- 'src/Components/components.js',
86
- 'src/routes.js'
87
- ];
88
-
89
- for (const reqPath of requiredPaths) {
90
- const fullPath = path.join(projectRoot, reqPath);
91
- if (!await fs.pathExists(fullPath)) {
92
- throw new Error(`Required file not found: ${reqPath}`);
93
- }
94
- }
95
- }
96
-
97
- /**
98
- * Prints summary of generated bundles
99
- */
100
- function printSummary(result, startTime) {
101
- const { bundles, config, files } = result;
102
- const duration = ((Date.now() - startTime) / 1000).toFixed(2);
103
-
104
- Print.success(`Bundles generated in ${duration}s\n`);
105
-
106
- // Critical bundle
107
- if (bundles.critical.components.length > 0) {
108
- Print.info('📦 Critical Bundle:');
109
- console.log(` Components: ${bundles.critical.components.length}`);
110
- console.log(` Size: ${(bundles.critical.size / 1024).toFixed(1)} KB`);
111
- console.log(` File: ${bundles.critical.file}\n`);
112
- }
113
-
114
- // Route bundles
115
- const routeCount = Object.keys(bundles.routes).length;
116
- if (routeCount > 0) {
117
- Print.info(`📦 Route Bundles (${routeCount}):`);
118
-
119
- for (const [key, bundle] of Object.entries(bundles.routes)) {
120
- console.log(` ${key}:`);
121
- const routeDisplay = Array.isArray(bundle.path) ? `${bundle.path.length} routes` : (bundle.path || key);
122
- console.log(` Route: ${routeDisplay}`);
123
- console.log(` Components: ${bundle.components.length}`);
124
- console.log(` Size: ${(bundle.size / 1024).toFixed(1)} KB`);
125
- console.log(` File: ${bundle.file}`);
126
- }
127
- Print.newLine();
128
- }
129
-
130
- // Global statistics
131
- Print.info('📊 Statistics:');
132
- console.log(` Strategy: ${config.strategy}`);
133
- console.log(` Total components: ${config.stats.totalComponents}`);
134
- console.log(` Shared components: ${config.stats.sharedComponents}`);
135
- console.log(` Generated files: ${files.length}`);
136
-
137
- // Calculate estimated improvement
138
- const beforeRequests = config.stats.totalComponents;
139
- const afterRequests = files.length;
140
- const improvement = Math.round((1 - afterRequests / beforeRequests) * 100);
141
-
142
- console.log(` Request reduction: ${improvement}% (${beforeRequests} → ${afterRequests})`);
143
- }
144
-
145
- /**
146
- * Subcommand: Clean bundles
147
- */
148
- export async function cleanBundles() {
149
- const projectRoot = process.cwd();
150
- const srcPath = path.join(projectRoot, 'src');
151
-
152
- try {
153
- Print.title('🧹 Cleaning bundles...');
154
-
155
- const files = await fs.readdir(srcPath);
156
- const bundleFiles = files.filter(f => f.startsWith('slice-bundle.'));
157
-
158
- if (bundleFiles.length === 0) {
159
- Print.warning('No bundles found to clean');
160
- return;
161
- }
162
-
163
- for (const file of bundleFiles) {
164
- await fs.remove(path.join(srcPath, file));
165
- console.log(` ✓ Deleted: ${file}`);
166
- }
167
-
168
- // Remove config
169
- const configPath = path.join(srcPath, 'bundle.config.json');
170
- if (await fs.pathExists(configPath)) {
171
- await fs.remove(configPath);
172
- console.log(` ✓ Deleted: bundle.config.json`);
173
- }
174
-
175
- Print.newLine();
176
- Print.success(`${bundleFiles.length} files deleted`);
177
-
178
- } catch (error) {
179
- Print.error('Error cleaning bundles:', error.message);
180
- process.exit(1);
181
- }
182
- }
183
-
184
- /**
185
- * Subcommand: Bundle information
186
- */
187
- export async function bundleInfo() {
188
- const projectRoot = process.cwd();
189
- const configPath = path.join(projectRoot, 'src/bundle.config.json');
190
-
191
- try {
192
- if (!await fs.pathExists(configPath)) {
193
- Print.warning('Bundle configuration not found');
194
- Print.info('Run "slice bundle" to generate bundles');
195
- return;
196
- }
197
-
198
- const config = await fs.readJson(configPath);
199
-
200
- Print.title('📦 Bundle Information');
201
- Print.newLine();
202
-
203
- Print.info('Configuration:');
204
- console.log(` Version: ${config.version}`);
205
- console.log(` Strategy: ${config.strategy}`);
206
- console.log(` Generated: ${new Date(config.generated).toLocaleString()}`);
207
- Print.newLine();
208
-
209
- Print.info('Statistics:');
210
- console.log(` Total components: ${config.stats.totalComponents}`);
211
- console.log(` Total routes: ${config.stats.totalRoutes}`);
212
- console.log(` Shared components: ${config.stats.sharedComponents} (${config.stats.sharedPercentage}%)`);
213
- console.log(` Total size: ${(config.stats.totalSize / 1024).toFixed(1)} KB`);
214
- Print.newLine();
215
-
216
- Print.info('Bundles:');
217
-
218
- // Critical
219
- if (config.bundles.critical) {
220
- console.log(` Critical: ${config.bundles.critical.components.length} components, ${(config.bundles.critical.size / 1024).toFixed(1)} KB`);
221
- }
222
-
223
- // Routes
224
- const routeCount = Object.keys(config.bundles.routes).length;
225
- console.log(` Routes: ${routeCount} bundles`);
226
-
227
- for (const [key, bundle] of Object.entries(config.bundles.routes)) {
228
- console.log(` ${key}: ${bundle.components.length} components, ${(bundle.size / 1024).toFixed(1)} KB`);
229
- }
230
-
231
- } catch (error) {
232
- Print.error('Error reading information:', error.message);
233
- process.exit(1);
234
- }
235
- }
1
+ // cli/commands/bundle/bundle.js
2
+ import path from 'path';
3
+ import fs from 'fs-extra';
4
+ import DependencyAnalyzer from '../utils/bundling/DependencyAnalyzer.js';
5
+ import BundleGenerator from '../utils/bundling/BundleGenerator.js';
6
+ import Print from '..//Print.js';
7
+ import { getProjectRoot, getSrcPath } from '../utils/PathHelper.js';
8
+
9
+ /**
10
+ * Main bundling command
11
+ */
12
+ export default async function bundle(options = {}) {
13
+ const startTime = Date.now();
14
+ const projectRoot = getProjectRoot(import.meta.url);
15
+
16
+ try {
17
+ Print.title('📦 Slice.js Bundle Generator');
18
+ Print.newLine();
19
+
20
+ // Validate that it's a Slice.js project
21
+ await validateProject(projectRoot);
22
+
23
+ // Create default bundle config if needed
24
+ const bundleGenerator = new BundleGenerator(import.meta.url, null);
25
+ await bundleGenerator.createDefaultBundleConfig();
26
+
27
+ // Phase 1: Analysis
28
+ Print.buildProgress('Analyzing project...');
29
+ const analyzer = new DependencyAnalyzer(import.meta.url);
30
+ const analysisData = await analyzer.analyze();
31
+
32
+ // Show report if in verbose mode
33
+ if (options.verbose || options.analyze) {
34
+ Print.newLine();
35
+ analyzer.generateReport(analysisData.metrics);
36
+ Print.newLine();
37
+ }
38
+
39
+ // If only analysis is requested, finish here
40
+ if (options.analyze) {
41
+ Print.success('Analysis completed');
42
+ return;
43
+ }
44
+
45
+ // Phase 2: Bundle generation
46
+ Print.buildProgress('Generating bundles...');
47
+ const generator = new BundleGenerator(import.meta.url, analysisData, {
48
+ minify: !!options.minify,
49
+ obfuscate: !!options.obfuscate,
50
+ output: options.output || 'src'
51
+ });
52
+ const result = await generator.generate();
53
+
54
+ // Phase 3: Save configuration
55
+ Print.buildProgress('Saving configuration...');
56
+ await generator.saveBundleConfig(result.config);
57
+
58
+ // Phase 4: Summary
59
+ Print.newLine();
60
+ printSummary(result, startTime);
61
+
62
+ // Show next step
63
+ Print.newLine();
64
+ Print.info('💡 Next step:');
65
+ console.log(' Update your Slice.js to use the generated bundles');
66
+ console.log(' Bundles will load automatically in production\n');
67
+
68
+ } catch (error) {
69
+ Print.error('Error generating bundles:', error.message);
70
+ console.error('\n📍 Complete stack trace:');
71
+ console.error(error.stack);
72
+
73
+ if (error.code) {
74
+ console.error('\n📍 Error code:', error.code);
75
+ }
76
+
77
+ process.exit(1);
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Validates that the project has the correct structure
83
+ */
84
+ async function validateProject(projectRoot) {
85
+ const requiredPaths = [
86
+ getSrcPath(import.meta.url, 'Components', 'components.js'),
87
+ getSrcPath(import.meta.url, 'routes.js')
88
+ ];
89
+
90
+ for (const fullPath of requiredPaths) {
91
+ if (!await fs.pathExists(fullPath)) {
92
+ const relativePath = path.relative(projectRoot, fullPath);
93
+ throw new Error(`Required file not found: ${relativePath}`);
94
+ }
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Prints summary of generated bundles
100
+ */
101
+ function printSummary(result, startTime) {
102
+ const { bundles, config, files } = result;
103
+ const duration = ((Date.now() - startTime) / 1000).toFixed(2);
104
+
105
+ Print.success(`Bundles generated in ${duration}s\n`);
106
+
107
+ // Critical bundle
108
+ if (bundles.critical.components.length > 0) {
109
+ Print.info('📦 Critical Bundle:');
110
+ console.log(` Components: ${bundles.critical.components.length}`);
111
+ console.log(` Size: ${(bundles.critical.size / 1024).toFixed(1)} KB`);
112
+ console.log(` File: ${bundles.critical.file}\n`);
113
+ }
114
+
115
+ // Route bundles
116
+ const routeCount = Object.keys(bundles.routes).length;
117
+ if (routeCount > 0) {
118
+ Print.info(`📦 Route Bundles (${routeCount}):`);
119
+
120
+ for (const [key, bundle] of Object.entries(bundles.routes)) {
121
+ console.log(` ${key}:`);
122
+ const routeDisplay = Array.isArray(bundle.path) ? `${bundle.path.length} routes` : (bundle.path || key);
123
+ console.log(` Route: ${routeDisplay}`);
124
+ console.log(` Components: ${bundle.components.length}`);
125
+ console.log(` Size: ${(bundle.size / 1024).toFixed(1)} KB`);
126
+ console.log(` File: ${bundle.file}`);
127
+ }
128
+ Print.newLine();
129
+ }
130
+
131
+ // Global statistics
132
+ Print.info('📊 Statistics:');
133
+ console.log(` Strategy: ${config.strategy}`);
134
+ console.log(` Total components: ${config.stats.totalComponents}`);
135
+ console.log(` Shared components: ${config.stats.sharedComponents}`);
136
+ console.log(` Generated files: ${files.length}`);
137
+
138
+ // Calculate estimated improvement
139
+ const beforeRequests = config.stats.totalComponents;
140
+ const afterRequests = files.length;
141
+ const improvement = Math.round((1 - afterRequests / beforeRequests) * 100);
142
+
143
+ console.log(` Request reduction: ${improvement}% (${beforeRequests} → ${afterRequests})`);
144
+ }
145
+
146
+ /**
147
+ * Subcommand: Clean bundles
148
+ */
149
+ export async function cleanBundles() {
150
+ const srcPath = getSrcPath(import.meta.url);
151
+
152
+ try {
153
+ Print.title('🧹 Cleaning bundles...');
154
+
155
+ const files = await fs.readdir(srcPath);
156
+ const bundleFiles = files.filter(f => f.startsWith('slice-bundle.'));
157
+
158
+ if (bundleFiles.length === 0) {
159
+ Print.warning('No bundles found to clean');
160
+ return;
161
+ }
162
+
163
+ for (const file of bundleFiles) {
164
+ await fs.remove(path.join(srcPath, file));
165
+ console.log(` ✓ Deleted: ${file}`);
166
+ }
167
+
168
+ // Remove config
169
+ const configPath = getSrcPath(import.meta.url, 'bundle.config.json');
170
+ if (await fs.pathExists(configPath)) {
171
+ await fs.remove(configPath);
172
+ console.log(` ✓ Deleted: bundle.config.json`);
173
+ }
174
+
175
+ Print.newLine();
176
+ Print.success(`${bundleFiles.length} files deleted`);
177
+
178
+ } catch (error) {
179
+ Print.error('Error cleaning bundles:', error.message);
180
+ process.exit(1);
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Subcommand: Bundle information
186
+ */
187
+ export async function bundleInfo() {
188
+ const configPath = getSrcPath(import.meta.url, 'bundle.config.json');
189
+
190
+ try {
191
+ if (!await fs.pathExists(configPath)) {
192
+ Print.warning('Bundle configuration not found');
193
+ Print.info('Run "slice bundle" to generate bundles');
194
+ return;
195
+ }
196
+
197
+ const config = await fs.readJson(configPath);
198
+
199
+ Print.title('📦 Bundle Information');
200
+ Print.newLine();
201
+
202
+ Print.info('Configuration:');
203
+ console.log(` Version: ${config.version}`);
204
+ console.log(` Strategy: ${config.strategy}`);
205
+ console.log(` Generated: ${new Date(config.generated).toLocaleString()}`);
206
+ Print.newLine();
207
+
208
+ Print.info('Statistics:');
209
+ console.log(` Total components: ${config.stats.totalComponents}`);
210
+ console.log(` Total routes: ${config.stats.totalRoutes}`);
211
+ console.log(` Shared components: ${config.stats.sharedComponents} (${config.stats.sharedPercentage}%)`);
212
+ console.log(` Total size: ${(config.stats.totalSize / 1024).toFixed(1)} KB`);
213
+ Print.newLine();
214
+
215
+ Print.info('Bundles:');
216
+
217
+ // Critical
218
+ if (config.bundles.critical) {
219
+ console.log(` Critical: ${config.bundles.critical.components.length} components, ${(config.bundles.critical.size / 1024).toFixed(1)} KB`);
220
+ }
221
+
222
+ // Routes
223
+ const routeCount = Object.keys(config.bundles.routes).length;
224
+ console.log(` Routes: ${routeCount} bundles`);
225
+
226
+ for (const [key, bundle] of Object.entries(config.bundles.routes)) {
227
+ console.log(` ${key}: ${bundle.components.length} components, ${(bundle.size / 1024).toFixed(1)} KB`);
228
+ }
229
+
230
+ } catch (error) {
231
+ Print.error('Error reading information:', error.message);
232
+ process.exit(1);
233
+ }
234
+ }
@@ -1,55 +1,55 @@
1
- export default class componentTemplates{
2
-
3
- static visual(componentName){
4
- return `export default class ${componentName} extends HTMLElement {
5
-
6
- static props = {
7
- // Define your component props here
8
- // Example:
9
- /*
10
- "value": {
11
- type: 'string',
12
- default: 'Button',
13
- required: false
14
- },
15
- */
16
- }
17
-
18
- constructor(props) {
19
- super();
20
- slice.attachTemplate(this);
21
- slice.controller.setComponentProps(this, props);
22
- }
23
-
24
- init() {
25
- // Component initialization logic (can be async)
26
- }
27
-
28
- update() {
29
- // Component update logic (can be async)
30
- }
31
-
32
- // Add your custom methods here
33
- }
34
-
35
- customElements.define("slice-${componentName.toLowerCase()}", ${componentName});
36
- `;
37
- }
38
-
39
- static service(componentName) {
40
- return `export default class ${componentName} {
41
- constructor(props) {
42
- // Initialize service with props
43
- this.props = props || {};
44
- }
45
-
46
- init() {
47
- // Service initialization logic (can be async)
48
- }
49
-
50
- // Add your service methods here
51
- }
52
- `;
53
- }
54
- }
55
-
1
+ export default class componentTemplates{
2
+
3
+ static visual(componentName){
4
+ return `export default class ${componentName} extends HTMLElement {
5
+
6
+ static props = {
7
+ // Define your component props here
8
+ // Example:
9
+ /*
10
+ "value": {
11
+ type: 'string',
12
+ default: 'Button',
13
+ required: false
14
+ },
15
+ */
16
+ }
17
+
18
+ constructor(props) {
19
+ super();
20
+ slice.attachTemplate(this);
21
+ slice.controller.setComponentProps(this, props);
22
+ }
23
+
24
+ init() {
25
+ // Component initialization logic (can be async)
26
+ }
27
+
28
+ update() {
29
+ // Component update logic (can be async)
30
+ }
31
+
32
+ // Add your custom methods here
33
+ }
34
+
35
+ customElements.define("slice-${componentName.toLowerCase()}", ${componentName});
36
+ `;
37
+ }
38
+
39
+ static service(componentName) {
40
+ return `export default class ${componentName} {
41
+ constructor(props) {
42
+ // Initialize service with props
43
+ this.props = props || {};
44
+ }
45
+
46
+ init() {
47
+ // Service initialization logic (can be async)
48
+ }
49
+
50
+ // Add your service methods here
51
+ }
52
+ `;
53
+ }
54
+ }
55
+