slicejs-cli 2.1.10 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -109,8 +109,7 @@ class ComponentRegistry {
109
109
  updatableComponents.push({
110
110
  name,
111
111
  category,
112
- path: componentPath,
113
- description: this.getComponentDescription(name, category)
112
+ path: componentPath
114
113
  });
115
114
  }
116
115
  }
@@ -125,13 +124,25 @@ class ComponentRegistry {
125
124
  const components = {};
126
125
  Object.entries(this.componentsRegistry).forEach(([name, componentCategory]) => {
127
126
  if (!category || componentCategory === category) {
127
+ // ✅ CORREGIDO: Componentes especiales que no necesitan todos los archivos
128
+ let files;
129
+ if (componentCategory === 'Visual') {
130
+ // Componentes de routing lógico solo necesitan JS
131
+ if (['Route', 'MultiRoute', 'NotFound'].includes(name)) {
132
+ files = [`${name}.js`];
133
+ } else {
134
+ // Componentes visuales normales necesitan JS, HTML, CSS
135
+ files = [`${name}.js`, `${name}.html`, `${name}.css`];
136
+ }
137
+ } else {
138
+ // Service components solo necesitan JS
139
+ files = [`${name}.js`];
140
+ }
141
+
128
142
  components[name] = {
129
143
  name,
130
144
  category: componentCategory,
131
- files: componentCategory === 'Visual' ?
132
- [`${name}.js`, `${name}.html`, `${name}.css`] :
133
- [`${name}.js`],
134
- description: this.getComponentDescription(name, componentCategory)
145
+ files: files
135
146
  };
136
147
  }
137
148
  });
@@ -139,37 +150,42 @@ class ComponentRegistry {
139
150
  return components;
140
151
  }
141
152
 
142
- getComponentDescription(componentName, category) {
143
- const descriptions = {
144
- // Visual Components
145
- 'Button': 'Interactive button component with customizable styling and events',
146
- 'Card': 'Flexible container component for displaying content in card format',
147
- 'Input': 'Form input component with validation and multiple input types support',
148
- 'Checkbox': 'Checkbox input component with custom styling and state management',
149
- 'Switch': 'Toggle switch component for binary state selection',
150
- 'Select': 'Dropdown selection component with search and multi-select support',
151
- 'Details': 'Collapsible details component for expandable content sections',
152
- 'Grid': 'Responsive grid layout component for organizing content',
153
- 'Icon': 'Icon display component with multiple icon libraries support',
154
- 'Layout': 'Main layout component for application page structure',
155
- 'Loading': 'Loading indicator component with multiple animation styles',
156
- 'Navbar': 'Navigation bar component with responsive design and menu support',
157
- 'TreeView': 'Hierarchical tree view component for nested data display',
158
- 'TreeItem': 'Individual tree item component used within TreeView',
159
- 'DropDown': 'Dropdown menu component for contextual actions',
160
- 'Route': 'Single route component for client-side routing',
161
- 'MultiRoute': 'Multiple route handler component for complex routing',
162
- 'NotFound': '404 error page component for unmatched routes',
163
-
164
- // Service Components
165
- 'FetchManager': 'HTTP request manager service for API communication',
166
- 'LocalStorageManager': 'Local storage management service for browser storage',
167
- 'IndexedDbManager': 'IndexedDB database management service for client-side storage',
168
- 'Translator': 'Internationalization service for multi-language support',
169
- 'Link': 'Navigation link service for programmatic routing'
170
- };
171
-
172
- return descriptions[componentName] || `${componentName} component from Slice.js framework (${category})`;
153
+ displayAvailableComponents() {
154
+ if (!this.componentsRegistry) {
155
+ Print.error('❌ No se pudo cargar el registro de componentes');
156
+ return;
157
+ }
158
+
159
+ console.log('\n📚 Componentes disponibles en el repositorio oficial de Slice.js:\n');
160
+
161
+ const visualComponents = this.getAvailableComponents('Visual');
162
+ const serviceComponents = this.getAvailableComponents('Service');
163
+
164
+ // SIMPLIFICADO: Solo mostrar nombres sin descripciones
165
+ Print.info('🎨 Visual Components (UI):');
166
+ Object.keys(visualComponents).forEach(name => {
167
+ const files = visualComponents[name].files;
168
+ const fileIcons = files.map(file => {
169
+ if (file.endsWith('.js')) return '📜';
170
+ if (file.endsWith('.html')) return '🌐';
171
+ if (file.endsWith('.css')) return '🎨';
172
+ return '📄';
173
+ }).join(' ');
174
+ console.log(` • ${name} ${fileIcons}`);
175
+ });
176
+
177
+ Print.info('\n⚙️ Service Components (Logic):');
178
+ Object.keys(serviceComponents).forEach(name => {
179
+ console.log(` • ${name} 📜`);
180
+ });
181
+
182
+ Print.newLine();
183
+ Print.info(`Total: ${Object.keys(visualComponents).length} Visual + ${Object.keys(serviceComponents).length} Service components`);
184
+
185
+ console.log(`\n💡 Ejemplos de uso:`);
186
+ console.log(`slice get Button Card Input # Obtener componentes Visual`);
187
+ console.log(`slice get FetchManager --service # Obtener componente Service`);
188
+ console.log(`slice sync # Sincronizar componentes Visual`);
173
189
  }
174
190
 
175
191
  async downloadComponentFiles(componentName, category, targetPath) {
@@ -180,6 +196,7 @@ class ComponentRegistry {
180
196
  }
181
197
 
182
198
  const downloadedFiles = [];
199
+ const failedFiles = [];
183
200
  Print.info(`Downloading ${componentName} from official repository...`);
184
201
 
185
202
  for (const fileName of component.files) {
@@ -190,7 +207,9 @@ class ComponentRegistry {
190
207
  const response = await fetch(githubUrl);
191
208
 
192
209
  if (!response.ok) {
193
- throw new Error(`HTTP ${response.status}: ${response.statusText} for ${fileName}`);
210
+ Print.downloadError(fileName, `HTTP ${response.status}: ${response.statusText}`);
211
+ failedFiles.push(fileName);
212
+ continue; // ✅ CONTINUAR en lugar de lanzar error
194
213
  }
195
214
 
196
215
  const content = await response.text();
@@ -200,10 +219,24 @@ class ComponentRegistry {
200
219
  Print.downloadSuccess(fileName);
201
220
  } catch (error) {
202
221
  Print.downloadError(fileName, error.message);
203
- throw error;
222
+ failedFiles.push(fileName);
223
+ continue; // ✅ CONTINUAR en lugar de lanzar error
204
224
  }
205
225
  }
206
226
 
227
+ // ✅ NUEVO: Solo lanzar error si NO se descargó el archivo principal (.js)
228
+ const mainFileDownloaded = downloadedFiles.some(file => file.endsWith('.js'));
229
+
230
+ if (!mainFileDownloaded) {
231
+ throw new Error(`Failed to download main component file (${componentName}.js)`);
232
+ }
233
+
234
+ // ✅ ADVERTENCIA: Informar sobre archivos que fallaron (pero no detener el proceso)
235
+ if (failedFiles.length > 0) {
236
+ Print.warning(`Some files couldn't be downloaded: ${failedFiles.join(', ')}`);
237
+ Print.info('Component installed with available files');
238
+ }
239
+
207
240
  return downloadedFiles;
208
241
  }
209
242
 
@@ -295,18 +328,27 @@ class ComponentRegistry {
295
328
  // Update components registry
296
329
  await this.updateLocalRegistry(componentName, category);
297
330
 
298
- Print.success(`${componentName} updated successfully from official repository!`);
331
+ Print.success(`${componentName} installed successfully from official repository!`);
299
332
  console.log(`📁 Location: ${folderSuffix}/${categoryPath}/${componentName}/`);
300
333
  console.log(`📄 Files: ${downloadedFiles.join(', ')}`);
301
334
 
302
335
  return true;
303
336
 
304
337
  } catch (error) {
305
- Print.error(`Error updating ${componentName}: ${error.message}`);
306
- // Clean up partial installation
307
- if (await fs.pathExists(targetPath)) {
338
+ Print.error(`Error installing ${componentName}: ${error.message}`);
339
+
340
+ // ✅ MEJORADO: Solo borrar si el archivo principal (.js) no existe
341
+ const mainFilePath = path.join(targetPath, `${componentName}.js`);
342
+ const mainFileExists = await fs.pathExists(mainFilePath);
343
+
344
+ if (!mainFileExists && await fs.pathExists(targetPath)) {
345
+ // Solo limpiar si no se instaló el archivo principal
308
346
  await fs.remove(targetPath);
347
+ Print.info('Cleaned up failed installation');
348
+ } else if (mainFileExists) {
349
+ Print.warning('Component partially installed - main file exists');
309
350
  }
351
+
310
352
  throw error;
311
353
  }
312
354
  }
@@ -420,20 +462,31 @@ class ComponentRegistry {
420
462
  const visualComponents = this.getAvailableComponents('Visual');
421
463
  const serviceComponents = this.getAvailableComponents('Service');
422
464
 
465
+ // ✅ SIMPLIFICADO: Solo mostrar nombres sin descripciones
423
466
  Print.info('🎨 Visual Components (UI):');
424
- Object.entries(visualComponents).forEach(([name, info]) => {
425
- console.log(` • ${name}: ${info.description}`);
467
+ Object.keys(visualComponents).forEach(name => {
468
+ const files = visualComponents[name].files;
469
+ const fileIcons = files.map(file => {
470
+ if (file.endsWith('.js')) return '📜';
471
+ if (file.endsWith('.html')) return '🌐';
472
+ if (file.endsWith('.css')) return '🎨';
473
+ return '📄';
474
+ }).join(' ');
475
+ console.log(` • ${name} ${fileIcons}`);
426
476
  });
427
477
 
428
478
  Print.info('\n⚙️ Service Components (Logic):');
429
- Object.entries(serviceComponents).forEach(([name, info]) => {
430
- console.log(` • ${name}: ${info.description}`);
479
+ Object.keys(serviceComponents).forEach(name => {
480
+ console.log(` • ${name} 📜`);
431
481
  });
432
482
 
483
+ Print.newLine();
484
+ Print.info(`Total: ${Object.keys(visualComponents).length} Visual + ${Object.keys(serviceComponents).length} Service components`);
485
+
433
486
  console.log(`\n💡 Ejemplos de uso:`);
434
- console.log(`npm run slice:get Button Card Input`);
435
- console.log(`npm run slice:get FetchManager --service`);
436
- console.log(`npm run slice:sync # Actualizar componentes existentes`);
487
+ console.log(`slice get Button Card Input # Obtener componentes Visual`);
488
+ console.log(`slice get FetchManager --service # Obtener componente Service`);
489
+ console.log(`slice sync # Sincronizar componentes Visual`);
437
490
  }
438
491
 
439
492
  async interactiveInstall() {
@@ -450,8 +503,8 @@ class ComponentRegistry {
450
503
  ]);
451
504
 
452
505
  const availableComponents = this.getAvailableComponents(componentType);
453
- const componentChoices = Object.entries(availableComponents).map(([name, info]) => ({
454
- name: `${name} - ${info.description}`,
506
+ const componentChoices = Object.keys(availableComponents).map(name => ({
507
+ name: name,
455
508
  value: name
456
509
  }));
457
510
 
@@ -554,7 +607,7 @@ async function getComponents(componentNames = [], options = {}) {
554
607
 
555
608
  if (!componentInfo) {
556
609
  Print.error(`Component '${componentNames[0]}' not found in official repository`);
557
- Print.commandExample('View available components', 'npm run slice:browse');
610
+ Print.commandExample('View available components', 'slice browse');
558
611
  return false;
559
612
  }
560
613
 
@@ -614,4 +667,4 @@ async function syncComponents(options = {}) {
614
667
  }
615
668
 
616
669
  export default getComponents;
617
- export { listComponents, syncComponents };
670
+ export { listComponents, syncComponents, ComponentRegistry };
@@ -2,28 +2,21 @@ import fs from 'fs-extra';
2
2
  import path from 'path';
3
3
  import { fileURLToPath } from 'url';
4
4
  import Print from '../Print.js';
5
+
5
6
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
7
 
8
+ // Importar la clase ComponentRegistry del getComponent
9
+ import { ComponentRegistry } from '../getComponent/getComponent.js';
10
+
7
11
  export default async function initializeProject(projectType) {
8
12
  try {
9
- // Directorio de origen en el paquete
13
+ // Directorio de origen para API (mantener copia local)
10
14
  let sliceBaseDir = path.join(__dirname, '../../../slicejs-web-framework');
11
15
  let apiDir = path.join(sliceBaseDir, 'api');
12
16
  let srcDir = path.join(sliceBaseDir, 'src');
13
-
14
17
  let destinationApi = path.join(__dirname, '../../../../api');
15
18
  let destinationSrc = path.join(__dirname, '../../../../src');
16
19
 
17
- try {
18
- // Verificar si los directorios de origen existen
19
- if (!fs.existsSync(sliceBaseDir)) throw new Error(`No se encontró el directorio base: ${sliceBaseDir}`);
20
- if (!fs.existsSync(apiDir)) throw new Error(`No se encontró la carpeta api: ${apiDir}`);
21
- if (!fs.existsSync(srcDir)) throw new Error(`No se encontró la carpeta src: ${srcDir}`);
22
- } catch (error) {
23
- Print.error('Error validando directorios de origen:', error.message);
24
- return;
25
- }
26
-
27
20
  try {
28
21
  // Verificar si los directorios de destino ya existen
29
22
  if (fs.existsSync(destinationApi)) throw new Error(`El directorio "api" ya existe: ${destinationApi}`);
@@ -33,8 +26,9 @@ export default async function initializeProject(projectType) {
33
26
  return;
34
27
  }
35
28
 
29
+ // 1. COPIAR LA CARPETA API (mantener lógica original)
36
30
  try {
37
- // Copiar las carpetas
31
+ if (!fs.existsSync(apiDir)) throw new Error(`No se encontró la carpeta api: ${apiDir}`);
38
32
  await fs.copy(apiDir, destinationApi, { recursive: true });
39
33
  Print.success('Carpeta "api" copiada correctamente.');
40
34
  } catch (error) {
@@ -42,16 +36,119 @@ export default async function initializeProject(projectType) {
42
36
  return;
43
37
  }
44
38
 
39
+ // 2. CREAR ESTRUCTURA SRC BÁSICA (sin copiar componentes Visual)
45
40
  try {
46
- await fs.copy(srcDir, destinationSrc, { recursive: true });
47
- Print.success('Carpeta "src" copiada correctamente.');
41
+ if (!fs.existsSync(srcDir)) throw new Error(`No se encontró la carpeta src: ${srcDir}`);
42
+
43
+ // Copiar solo los archivos base de src, excluyendo Components/Visual
44
+ await fs.ensureDir(destinationSrc);
45
+
46
+ // Copiar archivos y carpetas de src excepto Components/Visual
47
+ const srcItems = await fs.readdir(srcDir);
48
+
49
+ for (const item of srcItems) {
50
+ const srcItemPath = path.join(srcDir, item);
51
+ const destItemPath = path.join(destinationSrc, item);
52
+ const stat = await fs.stat(srcItemPath);
53
+
54
+ if (stat.isDirectory()) {
55
+ if (item === 'Components') {
56
+ // Crear estructura de Components pero sin copiar Visual
57
+ await fs.ensureDir(destItemPath);
58
+
59
+ const componentItems = await fs.readdir(srcItemPath);
60
+ for (const componentItem of componentItems) {
61
+ const componentItemPath = path.join(srcItemPath, componentItem);
62
+ const destComponentItemPath = path.join(destItemPath, componentItem);
63
+
64
+ if (componentItem !== 'Visual') {
65
+ // Copiar Service y otros tipos de components
66
+ await fs.copy(componentItemPath, destComponentItemPath, { recursive: true });
67
+ } else {
68
+ // Solo crear el directorio Visual vacío
69
+ await fs.ensureDir(destComponentItemPath);
70
+ }
71
+ }
72
+ } else {
73
+ // Copiar otras carpetas normalmente
74
+ await fs.copy(srcItemPath, destItemPath, { recursive: true });
75
+ }
76
+ } else {
77
+ // Copiar archivos normalmente
78
+ await fs.copy(srcItemPath, destItemPath);
79
+ }
80
+ }
81
+
82
+ Print.success('Estructura "src" creada correctamente.');
48
83
  } catch (error) {
49
- Print.error('Error copiando la carpeta "src":', error.message);
84
+ Print.error('Error creando la estructura "src":', error.message);
50
85
  return;
51
86
  }
52
87
 
88
+ // 3. DESCARGAR TODOS LOS COMPONENTES VISUAL DESDE EL REPOSITORIO OFICIAL
89
+ try {
90
+ Print.info('Downloading all Visual components from official repository...');
91
+
92
+ const registry = new ComponentRegistry();
93
+ await registry.loadRegistry();
94
+
95
+ // Obtener TODOS los componentes Visual disponibles
96
+ const allVisualComponents = await getAllVisualComponents(registry);
97
+
98
+ if (allVisualComponents.length > 0) {
99
+ Print.info(`Installing ${allVisualComponents.length} Visual components...`);
100
+
101
+ const results = await registry.installMultipleComponents(
102
+ allVisualComponents,
103
+ 'Visual',
104
+ true // force = true para instalación inicial
105
+ );
106
+
107
+ const successful = results.filter(r => r.success).length;
108
+ const failed = results.filter(r => !r.success).length;
109
+
110
+ if (successful > 0) {
111
+ Print.success(`${successful} Visual components installed from official repository`);
112
+ }
113
+
114
+ if (failed > 0) {
115
+ Print.warning(`${failed} Visual components could not be installed`);
116
+ Print.info('You can install them later using "slice get <component-name>"');
117
+ }
118
+ } else {
119
+ Print.warning('No Visual components found in registry');
120
+ Print.info('You can add components later using "slice get <component-name>"');
121
+ }
122
+
123
+ } catch (error) {
124
+ Print.warning('Could not download Visual components from official repository');
125
+ Print.error(`Repository error: ${error.message}`);
126
+ Print.info('Project initialized without Visual components');
127
+ Print.info('You can add them later using "slice get <component-name>"');
128
+ }
129
+
53
130
  Print.success('Proyecto inicializado correctamente.');
131
+ Print.newLine();
132
+ Print.info('Next steps:');
133
+ console.log(' slice browse - View available components');
134
+ console.log(' slice get Button - Install specific components');
135
+ console.log(' slice sync - Update all components to latest versions');
136
+
54
137
  } catch (error) {
55
138
  Print.error('Error inesperado al inicializar el proyecto:', error.message);
56
139
  }
57
140
  }
141
+
142
+ /**
143
+ * Obtiene TODOS los componentes Visual disponibles en el registry
144
+ * @param {ComponentRegistry} registry - Instancia del registry cargado
145
+ * @returns {Array} - Array con todos los nombres de componentes Visual
146
+ */
147
+ async function getAllVisualComponents(registry) {
148
+ const availableComponents = registry.getAvailableComponents('Visual');
149
+ const allVisualComponents = Object.keys(availableComponents);
150
+
151
+ Print.info(`Found ${allVisualComponents.length} Visual components in official repository`);
152
+
153
+ return allVisualComponents;
154
+ }
@@ -0,0 +1,198 @@
1
+ // commands/startServer/startServer.js
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 Print from '../Print.js';
8
+
9
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
10
+
11
+ /**
12
+ * Verifica si existe un build de producción
13
+ */
14
+ async function checkProductionBuild() {
15
+ const distDir = path.join(__dirname, '../../../../dist');
16
+ return await fs.pathExists(distDir);
17
+ }
18
+
19
+ /**
20
+ * Verifica si existe la estructura de desarrollo
21
+ */
22
+ async function checkDevelopmentStructure() {
23
+ const srcDir = path.join(__dirname, '../../../../src');
24
+ const apiDir = path.join(__dirname, '../../../../api');
25
+
26
+ return (await fs.pathExists(srcDir)) && (await fs.pathExists(apiDir));
27
+ }
28
+
29
+ /**
30
+ * Modifica temporalmente el servidor Express para modo producción
31
+ */
32
+ async function createProductionIndexFile() {
33
+ try {
34
+ const apiDir = path.join(__dirname, '../../../../api');
35
+ const originalIndexPath = path.join(apiDir, 'index.js');
36
+ const backupIndexPath = path.join(apiDir, 'index.dev.js');
37
+ const prodIndexPath = path.join(apiDir, 'index.prod.js');
38
+
39
+ // Crear backup del index original si no existe
40
+ if (!await fs.pathExists(backupIndexPath)) {
41
+ await fs.copy(originalIndexPath, backupIndexPath);
42
+ }
43
+
44
+ // Leer el contenido original
45
+ const originalContent = await fs.readFile(originalIndexPath, 'utf8');
46
+
47
+ // Modificar para servir desde /dist en lugar de /src
48
+ const productionContent = originalContent.replace(
49
+ /express\.static\(['"`]src['"`]\)/g,
50
+ "express.static('dist')"
51
+ ).replace(
52
+ /express\.static\(path\.join\(__dirname,\s*['"`]\.\.\/src['"`]\)\)/g,
53
+ "express.static(path.join(__dirname, '../dist'))"
54
+ );
55
+
56
+ // Escribir archivo temporal de producción
57
+ await fs.writeFile(prodIndexPath, productionContent, 'utf8');
58
+
59
+ // Reemplazar index.js con versión de producción
60
+ await fs.copy(prodIndexPath, originalIndexPath);
61
+
62
+ Print.success('Express server configured for production mode');
63
+
64
+ return true;
65
+ } catch (error) {
66
+ Print.error(`Error configuring production server: ${error.message}`);
67
+ return false;
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Restaura el servidor Express al modo desarrollo
73
+ */
74
+ async function restoreDevelopmentIndexFile() {
75
+ try {
76
+ const apiDir = path.join(__dirname, '../../../../api');
77
+ const originalIndexPath = path.join(apiDir, 'index.js');
78
+ const backupIndexPath = path.join(apiDir, 'index.dev.js');
79
+
80
+ if (await fs.pathExists(backupIndexPath)) {
81
+ await fs.copy(backupIndexPath, originalIndexPath);
82
+ Print.success('Express server restored to development mode');
83
+ }
84
+
85
+ return true;
86
+ } catch (error) {
87
+ Print.error(`Error restoring development server: ${error.message}`);
88
+ return false;
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Inicia el servidor Node.js
94
+ */
95
+ function startNodeServer(port, mode) {
96
+ return new Promise((resolve, reject) => {
97
+ const apiIndexPath = path.join(__dirname, '../../../../api/index.js');
98
+
99
+ Print.info(`Starting ${mode} server on port ${port}...`);
100
+
101
+ const serverProcess = spawn('node', [apiIndexPath], {
102
+ stdio: 'inherit',
103
+ env: {
104
+ ...process.env,
105
+ PORT: port,
106
+ NODE_ENV: mode === 'production' ? 'production' : 'development'
107
+ }
108
+ });
109
+
110
+ serverProcess.on('error', (error) => {
111
+ Print.error(`Failed to start server: ${error.message}`);
112
+ reject(error);
113
+ });
114
+
115
+ // Manejar Ctrl+C para limpiar archivos temporales
116
+ process.on('SIGINT', async () => {
117
+ Print.info('Shutting down server...');
118
+
119
+ if (mode === 'production') {
120
+ await restoreDevelopmentIndexFile();
121
+ }
122
+
123
+ serverProcess.kill('SIGINT');
124
+ process.exit(0);
125
+ });
126
+
127
+ // Manejar cierre del proceso
128
+ process.on('SIGTERM', async () => {
129
+ if (mode === 'production') {
130
+ await restoreDevelopmentIndexFile();
131
+ }
132
+
133
+ serverProcess.kill('SIGTERM');
134
+ });
135
+
136
+ // El servidor se considera iniciado exitosamente después de un breve delay
137
+ setTimeout(() => {
138
+ Print.success(`${mode === 'production' ? 'Production' : 'Development'} server running at http://localhost:${port}`);
139
+ Print.info(`Serving files from /${mode === 'production' ? 'dist' : 'src'} directory`);
140
+ Print.info('Press Ctrl+C to stop the server');
141
+ resolve(serverProcess);
142
+ }, 1000);
143
+ });
144
+ }
145
+
146
+ /**
147
+ * Función principal para iniciar servidor
148
+ */
149
+ export default async function startServer(options = {}) {
150
+ const { mode = 'development', port = 3000 } = options;
151
+
152
+ try {
153
+ Print.title(`🚀 Starting Slice.js ${mode} server...`);
154
+ Print.newLine();
155
+
156
+ // Verificar estructura del proyecto
157
+ if (!await checkDevelopmentStructure()) {
158
+ throw new Error('Project structure not found. Run "slice init" first.');
159
+ }
160
+
161
+ if (mode === 'production') {
162
+ // Modo producción: verificar build y configurar servidor
163
+ if (!await checkProductionBuild()) {
164
+ throw new Error('No production build found. Run "slice build" first.');
165
+ }
166
+
167
+ // Configurar Express para modo producción
168
+ const configSuccess = await createProductionIndexFile();
169
+ if (!configSuccess) {
170
+ throw new Error('Failed to configure production server');
171
+ }
172
+
173
+ Print.info('Production mode: serving optimized files from /dist');
174
+ } else {
175
+ // Modo desarrollo: asegurar que está en modo desarrollo
176
+ await restoreDevelopmentIndexFile();
177
+ Print.info('Development mode: serving files from /src with hot reload');
178
+ }
179
+
180
+ // Iniciar el servidor
181
+ await startNodeServer(port, mode);
182
+
183
+ } catch (error) {
184
+ Print.error(`Failed to start server: ${error.message}`);
185
+
186
+ // Limpiar en caso de error
187
+ if (mode === 'production') {
188
+ await restoreDevelopmentIndexFile();
189
+ }
190
+
191
+ throw error;
192
+ }
193
+ }
194
+
195
+ /**
196
+ * Funciones de utilidad exportadas
197
+ */
198
+ export { checkProductionBuild, checkDevelopmentStructure };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slicejs-cli",
3
- "version": "2.1.10",
3
+ "version": "2.2.0",
4
4
  "description": "Command client for developing web applications with Slice.js framework",
5
5
  "main": "client.js",
6
6
  "scripts": {