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,264 +1,261 @@
1
- // commands/startServer/startServer.js - MEJORADO CON VALIDACIÓN Y FEEDBACK
2
-
3
- import fs from 'fs-extra';
4
- import path from 'path';
5
- import { fileURLToPath } from 'url';
6
- import { spawn } from 'child_process';
7
- import { createServer } from 'net';
8
- import setupWatcher, { stopWatcher } from './watchServer.js';
9
- import Print from '../Print.js';
10
- import { getConfigPath, getApiPath, getSrcPath, getDistPath } from '../utils/PathHelper.js';
11
- import build from '../build/build.js';
12
-
13
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
14
-
15
- /**
16
- * Carga la configuración desde sliceConfig.json
17
- */
18
- const loadConfig = () => {
19
- try {
20
- const configPath = getConfigPath(import.meta.url);
21
- const rawData = fs.readFileSync(configPath, 'utf-8');
22
- return JSON.parse(rawData);
23
- } catch (error) {
24
- Print.error(`Loading configuration: ${error.message}`);
25
- return null;
26
- }
27
- };
28
-
29
- /**
30
- * Verifica si un puerto está disponible
31
- */
32
- async function isPortAvailable(port) {
33
- return new Promise((resolve) => {
34
- const server = createServer();
35
-
36
- server.once('error', (err) => {
37
- if (err.code === 'EADDRINUSE') {
38
- resolve(false);
39
- } else {
40
- resolve(false);
41
- }
42
- });
43
-
44
- server.once('listening', () => {
45
- server.close();
46
- resolve(true);
47
- });
48
-
49
- server.listen(port);
50
- });
51
- }
52
-
53
- /**
54
- * Verifica si existe un build de producción
55
- */
56
- async function checkProductionBuild() {
57
- const distDir = getDistPath(import.meta.url);
58
- const bundleConfigPath = path.join(distDir, 'bundles', 'bundle.config.json');
59
- return (await fs.pathExists(distDir)) && (await fs.pathExists(bundleConfigPath));
60
- }
61
-
62
- /**
63
- * Verifica si existe la estructura de desarrollo
64
- */
65
- async function checkDevelopmentStructure() {
66
- const srcDir = getSrcPath(import.meta.url);
67
- const apiDir = getApiPath(import.meta.url);
68
-
69
- return (await fs.pathExists(srcDir)) && (await fs.pathExists(apiDir));
70
- }
71
-
72
- /**
73
- * Inicia el servidor Node.js con argumentos y mejor feedback
74
- */
75
- function startNodeServer(port, mode) {
76
- return new Promise((resolve, reject) => {
77
- const apiIndexPath = getApiPath(import.meta.url, 'index.js');
78
-
79
- // Verificar que el archivo existe
80
- if (!fs.existsSync(apiIndexPath)) {
81
- reject(new Error(`Server file not found: ${apiIndexPath}`));
82
- return;
83
- }
84
-
85
- Print.serverStatus('starting', 'Starting server...');
86
-
87
- // Construir argumentos basados en el modo
88
- const args = [apiIndexPath];
89
- if (mode === 'production') {
90
- args.push('--production');
91
- } else {
92
- args.push('--development');
93
- }
94
-
95
- // Ensure the spawned server process receives NODE_ENV consistent with the
96
- // requested mode. This guarantees code that only checks process.env.NODE_ENV
97
- // (instead of CLI flags) will behave as expected.
98
- const serverEnv = {
99
- ...process.env,
100
- PORT: port,
101
- NODE_ENV: mode === 'production' ? 'production' : (process.env.NODE_ENV || 'development')
102
- };
103
-
104
- const serverProcess = spawn('node', args, {
105
- stdio: ['inherit', 'pipe', 'pipe'],
106
- env: serverEnv
107
- });
108
-
109
- let serverStarted = false;
110
- let outputBuffer = '';
111
-
112
- // Capturar la salida para detectar cuando el servidor está listo
113
- serverProcess.stdout.on('data', (data) => {
114
- const output = data.toString();
115
- outputBuffer += output;
116
-
117
- // Detectar mensajes comunes que indican que el servidor ha iniciado
118
- if (!serverStarted && (
119
- output.includes('Server running') ||
120
- output.includes('listening on') ||
121
- output.includes('Started on') ||
122
- output.includes(`port ${port}`)
123
- )) {
124
- serverStarted = true;
125
- Print.serverReady(port);
126
- }
127
-
128
- // Mostrar la salida del servidor
129
- process.stdout.write(output);
130
- });
131
-
132
- serverProcess.stderr.on('data', (data) => {
133
- const output = data.toString();
134
- process.stderr.write(output);
135
- });
136
-
137
- serverProcess.on('error', (error) => {
138
- if (!serverStarted) {
139
- Print.serverStatus('error', `Failed to start server: ${error.message}`);
140
- reject(error);
141
- }
142
- });
143
-
144
- serverProcess.on('exit', (code, signal) => {
145
- if (code !== null && code !== 0 && !serverStarted) {
146
- reject(new Error(`Server exited with code ${code}`));
147
- }
148
- });
149
-
150
- // Manejar Ctrl+C
151
- process.on('SIGINT', () => {
152
- Print.newLine();
153
- Print.info('Shutting down server...');
154
- serverProcess.kill('SIGINT');
155
- setTimeout(() => {
156
- process.exit(0);
157
- }, 100);
158
- });
159
-
160
- process.on('SIGTERM', () => {
161
- serverProcess.kill('SIGTERM');
162
- });
163
-
164
- // Si después de 3 segundos no detectamos inicio, asumimos que está listo
165
- setTimeout(() => {
166
- if (!serverStarted) {
167
- serverStarted = true;
168
- Print.serverReady(port);
169
- }
170
- resolve(serverProcess);
171
- }, 3000);
172
- });
173
- }
174
-
175
- /**
176
- * Función principal para iniciar servidor
177
- */
178
- export default async function startServer(options = {}) {
179
- const config = loadConfig();
180
- const defaultPort = config?.server?.port || 3000;
181
-
182
- const { mode = 'development', port = defaultPort, watch = false } = options;
183
-
184
- try {
185
- Print.title(`🚀 Starting Slice.js ${mode} server...`);
186
- Print.newLine();
187
-
188
- // Verificar estructura del proyecto
189
- if (!await checkDevelopmentStructure()) {
190
- throw new Error('Project structure not found. Run "slice init" first.');
191
- }
192
-
193
- let actualPort = await isPortAvailable(port) ? port : port + 1; // Try one more port
194
- if(actualPort !== port) {
195
- // Check if the fallback is available
196
- const fallbackAvailable = await isPortAvailable(actualPort);
197
- if(!fallbackAvailable) {
198
- throw new Error(`Ports ${port} and ${actualPort} are in use.`);
199
- }
200
- Print.info(`ℹ️ Port ${port} in use, using ${actualPort} instead.`);
201
- }
202
-
203
- Print.serverStatus('checking', `Port ${actualPort} available ✓`);
204
- Print.newLine();
205
-
206
- if (mode === 'production') {
207
- // Verificar que existe build de producción
208
- if (!await checkProductionBuild()) {
209
- Print.info('No production build found. Running "slice build"...');
210
- const success = await build({});
211
- if (!success) {
212
- throw new Error('Build failed. Cannot start production server.');
213
- }
214
- }
215
- Print.info('Production mode: serving optimized files from /dist');
216
- } else {
217
- Print.info('Development mode: serving files from /src (HMR enabled)');
218
- }
219
-
220
- Print.newLine();
221
-
222
- // Iniciar el servidor con argumentos
223
- let serverProcess = await startNodeServer(actualPort, mode);
224
-
225
- // Configurar watch mode si está habilitado
226
- if (watch) {
227
- Print.newLine();
228
- const watcher = setupWatcher(serverProcess, async (changedPath) => {
229
- if (serverProcess) {
230
- serverProcess.kill();
231
- }
232
-
233
- // Short delay to ensure port is freed
234
- await new Promise(r => setTimeout(r, 500));
235
-
236
- try {
237
- Print.info('🔄 File changed. Restarting server...');
238
-
239
- serverProcess = await startNodeServer(actualPort, mode);
240
- } catch (e) {
241
- Print.error(`Failed to restart server: ${e.message}`);
242
- }
243
- });
244
-
245
- // Cleanup en exit
246
- const cleanup = () => {
247
- stopWatcher(watcher);
248
- };
249
-
250
- process.on('SIGINT', cleanup);
251
- process.on('SIGTERM', cleanup);
252
- }
253
-
254
- } catch (error) {
255
- Print.newLine();
256
- Print.error(error.message);
257
- throw error;
258
- }
259
- }
260
-
261
- /**
262
- * Funciones de utilidad exportadas
263
- */
264
- export { checkProductionBuild, checkDevelopmentStructure, isPortAvailable };
1
+ // commands/startServer/startServer.js - IMPROVED WITH VALIDATION AND FEEDBACK
2
+
3
+ import fs from 'fs-extra';
4
+ import path from 'path';
5
+ import { spawn } from 'child_process';
6
+ import { createServer } from 'net';
7
+ import setupWatcher, { stopWatcher } from './watchServer.js';
8
+ import Print from '../Print.js';
9
+ import { getConfigPath, getApiPath, getSrcPath, getDistPath, getPath } from '../utils/PathHelper.js';
10
+ import build from '../build/build.js';
11
+
12
+ /**
13
+ * Loads configuration from sliceConfig.json
14
+ */
15
+ const loadConfig = () => {
16
+ try {
17
+ const configPath = getConfigPath(import.meta.url);
18
+ const rawData = fs.readFileSync(configPath, 'utf-8');
19
+ return JSON.parse(rawData);
20
+ } catch (error) {
21
+ Print.error(`Loading configuration: ${error.message}`);
22
+ return null;
23
+ }
24
+ };
25
+
26
+ /**
27
+ * Checks if a port is available
28
+ */
29
+ async function isPortAvailable(port) {
30
+ return new Promise((resolve) => {
31
+ const server = createServer();
32
+
33
+ server.once('error', (err) => {
34
+ if (err.code === 'EADDRINUSE') {
35
+ resolve(false);
36
+ } else {
37
+ resolve(false);
38
+ }
39
+ });
40
+
41
+ server.once('listening', () => {
42
+ server.close();
43
+ resolve(true);
44
+ });
45
+
46
+ server.listen(port);
47
+ });
48
+ }
49
+
50
+ /**
51
+ * Checks if a production build exists
52
+ */
53
+ async function checkProductionBuild() {
54
+ const distDir = getDistPath(import.meta.url);
55
+ const bundleConfigPath = getPath(import.meta.url, 'dist', 'bundles', 'bundle.config.json');
56
+ return (await fs.pathExists(distDir)) && (await fs.pathExists(bundleConfigPath));
57
+ }
58
+
59
+ /**
60
+ * Checks if the development structure exists
61
+ */
62
+ async function checkDevelopmentStructure() {
63
+ const srcDir = getSrcPath(import.meta.url);
64
+ const apiDir = getApiPath(import.meta.url);
65
+
66
+ return (await fs.pathExists(srcDir)) && (await fs.pathExists(apiDir));
67
+ }
68
+
69
+ /**
70
+ * Starts the Node.js server with arguments and improved feedback
71
+ */
72
+ function startNodeServer(port, mode) {
73
+ return new Promise((resolve, reject) => {
74
+ const apiIndexPath = getApiPath(import.meta.url, 'index.js');
75
+
76
+ // Verify the file exists
77
+ if (!fs.existsSync(apiIndexPath)) {
78
+ reject(new Error(`Server file not found: ${apiIndexPath}`));
79
+ return;
80
+ }
81
+
82
+ Print.serverStatus('starting', 'Starting server...');
83
+
84
+ // Build arguments based on mode
85
+ const args = [apiIndexPath];
86
+ if (mode === 'production') {
87
+ args.push('--production');
88
+ } else {
89
+ args.push('--development');
90
+ }
91
+
92
+ // Ensure the spawned server process receives NODE_ENV consistent with the
93
+ // requested mode. This guarantees code that only checks process.env.NODE_ENV
94
+ // (instead of CLI flags) will behave as expected.
95
+ const serverEnv = {
96
+ ...process.env,
97
+ PORT: port,
98
+ NODE_ENV: mode === 'production' ? 'production' : (process.env.NODE_ENV || 'development')
99
+ };
100
+
101
+ const serverProcess = spawn('node', args, {
102
+ stdio: ['inherit', 'pipe', 'pipe'],
103
+ env: serverEnv
104
+ });
105
+
106
+ let serverStarted = false;
107
+ let outputBuffer = '';
108
+
109
+ // Capture output to detect when the server is ready
110
+ serverProcess.stdout.on('data', (data) => {
111
+ const output = data.toString();
112
+ outputBuffer += output;
113
+
114
+ // Detect common messages indicating the server has started
115
+ if (!serverStarted && (
116
+ output.includes('Server running') ||
117
+ output.includes('listening on') ||
118
+ output.includes('Started on') ||
119
+ output.includes(`port ${port}`)
120
+ )) {
121
+ serverStarted = true;
122
+ Print.serverReady(port);
123
+ }
124
+
125
+ // Display server output
126
+ process.stdout.write(output);
127
+ });
128
+
129
+ serverProcess.stderr.on('data', (data) => {
130
+ const output = data.toString();
131
+ process.stderr.write(output);
132
+ });
133
+
134
+ serverProcess.on('error', (error) => {
135
+ if (!serverStarted) {
136
+ Print.serverStatus('error', `Failed to start server: ${error.message}`);
137
+ reject(error);
138
+ }
139
+ });
140
+
141
+ serverProcess.on('exit', (code, signal) => {
142
+ if (code !== null && code !== 0 && !serverStarted) {
143
+ reject(new Error(`Server exited with code ${code}`));
144
+ }
145
+ });
146
+
147
+ // Manejar Ctrl+C
148
+ process.on('SIGINT', () => {
149
+ Print.newLine();
150
+ Print.info('Shutting down server...');
151
+ serverProcess.kill('SIGINT');
152
+ setTimeout(() => {
153
+ process.exit(0);
154
+ }, 100);
155
+ });
156
+
157
+ process.on('SIGTERM', () => {
158
+ serverProcess.kill('SIGTERM');
159
+ });
160
+
161
+ // If after 3 seconds we haven't detected startup, assume it's ready
162
+ setTimeout(() => {
163
+ if (!serverStarted) {
164
+ serverStarted = true;
165
+ Print.serverReady(port);
166
+ }
167
+ resolve(serverProcess);
168
+ }, 3000);
169
+ });
170
+ }
171
+
172
+ /**
173
+ * Main function to start the server
174
+ */
175
+ export default async function startServer(options = {}) {
176
+ const config = loadConfig();
177
+ const defaultPort = config?.server?.port || 3000;
178
+
179
+ const { mode = 'development', port = defaultPort, watch = false } = options;
180
+
181
+ try {
182
+ Print.title(`🚀 Starting Slice.js ${mode} server...`);
183
+ Print.newLine();
184
+
185
+ // Verify project structure
186
+ if (!await checkDevelopmentStructure()) {
187
+ throw new Error('Project structure not found. Run "slice init" first.');
188
+ }
189
+
190
+ let actualPort = await isPortAvailable(port) ? port : port + 1; // Try one more port
191
+ if(actualPort !== port) {
192
+ // Check if the fallback is available
193
+ const fallbackAvailable = await isPortAvailable(actualPort);
194
+ if(!fallbackAvailable) {
195
+ throw new Error(`Ports ${port} and ${actualPort} are in use.`);
196
+ }
197
+ Print.info(`ℹ️ Port ${port} in use, using ${actualPort} instead.`);
198
+ }
199
+
200
+ Print.serverStatus('checking', `Port ${actualPort} available ✓`);
201
+ Print.newLine();
202
+
203
+ if (mode === 'production') {
204
+ // Verify production build exists
205
+ if (!await checkProductionBuild()) {
206
+ Print.info('No production build found. Running "slice build"...');
207
+ const success = await build({});
208
+ if (!success) {
209
+ throw new Error('Build failed. Cannot start production server.');
210
+ }
211
+ }
212
+ Print.info('Production mode: serving optimized files from /dist');
213
+ } else {
214
+ Print.info('Development mode: serving files from /src (HMR enabled)');
215
+ }
216
+
217
+ Print.newLine();
218
+
219
+ // Start the server with arguments
220
+ let serverProcess = await startNodeServer(actualPort, mode);
221
+
222
+ // Configure watch mode if enabled
223
+ if (watch) {
224
+ Print.newLine();
225
+ const watcher = setupWatcher(serverProcess, async (changedPath) => {
226
+ if (serverProcess) {
227
+ serverProcess.kill();
228
+ }
229
+
230
+ // Short delay to ensure port is freed
231
+ await new Promise(r => setTimeout(r, 500));
232
+
233
+ try {
234
+ Print.info('🔄 File changed. Restarting server...');
235
+
236
+ serverProcess = await startNodeServer(actualPort, mode);
237
+ } catch (e) {
238
+ Print.error(`Failed to restart server: ${e.message}`);
239
+ }
240
+ });
241
+
242
+ // Cleanup en exit
243
+ const cleanup = () => {
244
+ stopWatcher(watcher);
245
+ };
246
+
247
+ process.on('SIGINT', cleanup);
248
+ process.on('SIGTERM', cleanup);
249
+ }
250
+
251
+ } catch (error) {
252
+ Print.newLine();
253
+ Print.error(`Failed to start development server: ${error.message}`);
254
+ throw error;
255
+ }
256
+ }
257
+
258
+ /**
259
+ * Exported utility functions
260
+ */
261
+ export { checkProductionBuild, checkDevelopmentStructure, isPortAvailable };