slicejs-cli 2.3.1 → 2.3.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/client.js CHANGED
@@ -115,8 +115,9 @@ componentCommand
115
115
  await runWithVersionCheck(async () => {
116
116
  const categories = getCategories();
117
117
  if (categories.length === 0) {
118
- Print.error("No categories available. Check your configuration");
119
- Print.info("Run 'slice init' to initialize your project");
118
+ Print.error("No categories found in your project configuration");
119
+ Print.info("Run 'slice init' to initialize your project first");
120
+ Print.commandExample("Initialize project", "slice init");
120
121
  return;
121
122
  }
122
123
 
@@ -125,7 +126,13 @@ componentCommand
125
126
  type: "input",
126
127
  name: "componentName",
127
128
  message: "Enter the component name:",
128
- validate: (input) => (input ? true : "Component name cannot be empty"),
129
+ validate: (input) => {
130
+ if (!input) return "Component name cannot be empty";
131
+ if (!/^[a-zA-Z][a-zA-Z0-9]*$/.test(input)) {
132
+ return "Component name must start with a letter and contain only alphanumeric characters";
133
+ }
134
+ return true;
135
+ },
129
136
  },
130
137
  {
131
138
  type: "list",
@@ -134,25 +141,10 @@ componentCommand
134
141
  choices: categories,
135
142
  }
136
143
  ]);
137
-
138
- if (validations.getCategoryType(answers.category) === 'Visual') {
139
- const properties = await inquirer.prompt([
140
- {
141
- type: "input",
142
- name: "properties",
143
- message: "Enter the properties (comma separated):",
144
- default: ""
145
- },
146
- ]);
147
- answers.properties = properties.properties
148
- ? properties.properties.split(",").map((prop) => prop.trim()).filter(Boolean)
149
- : [];
150
- } else {
151
- answers.properties = [];
152
- }
153
144
 
154
- if (createComponent(answers.componentName, answers.category, answers.properties)) {
155
- Print.success(`Component ${answers.componentName} created successfully`);
145
+ const result = createComponent(answers.componentName, answers.category);
146
+ if (result) {
147
+ Print.success(`Component '${answers.componentName}' created successfully in category '${answers.category}'`);
156
148
  Print.info("Listing updated components:");
157
149
  listComponents();
158
150
  }
@@ -186,7 +178,68 @@ componentCommand
186
178
  }
187
179
 
188
180
  try {
189
- await deleteComponent();
181
+ // Paso 1: Seleccionar categoría
182
+ const categoryAnswer = await inquirer.prompt([
183
+ {
184
+ type: "list",
185
+ name: "category",
186
+ message: "Select the component category:",
187
+ choices: categories,
188
+ }
189
+ ]);
190
+
191
+ // Paso 2: Listar componentes de esa categoría
192
+ const config = loadConfig();
193
+ if (!config) {
194
+ Print.error("Could not load configuration");
195
+ return;
196
+ }
197
+
198
+ const categoryPath = config.paths.components[categoryAnswer.category].path;
199
+ const fullPath = path.join(__dirname, "../../src", categoryPath);
200
+
201
+ if (!fs.existsSync(fullPath)) {
202
+ Print.error(`Category path does not exist: ${categoryPath}`);
203
+ return;
204
+ }
205
+
206
+ const components = fs.readdirSync(fullPath).filter(item => {
207
+ const itemPath = path.join(fullPath, item);
208
+ return fs.statSync(itemPath).isDirectory();
209
+ });
210
+
211
+ if (components.length === 0) {
212
+ Print.info(`No components found in category '${categoryAnswer.category}'`);
213
+ return;
214
+ }
215
+
216
+ // Paso 3: Seleccionar componente a eliminar
217
+ const componentAnswer = await inquirer.prompt([
218
+ {
219
+ type: "list",
220
+ name: "componentName",
221
+ message: "Select the component to delete:",
222
+ choices: components,
223
+ },
224
+ {
225
+ type: "confirm",
226
+ name: "confirm",
227
+ message: (answers) => `Are you sure you want to delete '${answers.componentName}'?`,
228
+ default: false,
229
+ }
230
+ ]);
231
+
232
+ if (!componentAnswer.confirm) {
233
+ Print.info("Delete operation cancelled");
234
+ return;
235
+ }
236
+
237
+ // Paso 4: Eliminar el componente
238
+ if (deleteComponent(componentAnswer.componentName, categoryAnswer.category)) {
239
+ Print.success(`Component ${componentAnswer.componentName} deleted successfully`);
240
+ Print.info("Listing updated components:");
241
+ listComponents();
242
+ }
190
243
  } catch (error) {
191
244
  Print.error(`Deleting component: ${error.message}`);
192
245
  }
@@ -21,13 +21,16 @@ class Validations {
21
21
  try {
22
22
  const configPath = path.join(__dirname, '../../../src/sliceConfig.json');
23
23
  if (!fs.existsSync(configPath)) {
24
- return null; // Evitar error si no existe
24
+ console.error('\x1b[31m', '❌ Error: sliceConfig.json not found', '\x1b[0m');
25
+ console.log('\x1b[36m', 'ℹ️ Info: Run "slice init" to initialize your project', '\x1b[0m');
26
+ return null;
25
27
  }
26
28
  const rawData = fs.readFileSync(configPath, 'utf-8');
27
29
 
28
30
  return JSON.parse(rawData);
29
31
  } catch (error) {
30
- console.error(`Error cargando configuración: ${error.message}`);
32
+ console.error('\x1b[31m', `❌ Error loading configuration: ${error.message}`, '\x1b[0m');
33
+ console.log('\x1b[36m', 'ℹ️ Info: Check that sliceConfig.json is valid JSON', '\x1b[0m');
31
34
  return null;
32
35
  }
33
36
  }
@@ -59,7 +62,8 @@ class Validations {
59
62
  const componentFilePath = path.join(__dirname, '../../../src/Components/components.js');
60
63
 
61
64
  if (!fs.existsSync(componentFilePath)) {
62
- console.error('❌ El archivo components.js no existe en la ruta esperada.');
65
+ console.error('\x1b[31m', 'Error: components.js not found in expected path', '\x1b[0m');
66
+ console.log('\x1b[36m', 'ℹ️ Info: Run "slice component list" to generate components.js', '\x1b[0m');
63
67
  return false;
64
68
  }
65
69
 
@@ -69,7 +73,8 @@ class Validations {
69
73
  return components.hasOwnProperty(componentName);
70
74
 
71
75
  } catch (error) {
72
- console.error(' Error al verificar el componente:', error);
76
+ console.error('\x1b[31m', `❌ Error checking component existence: ${error.message}`, '\x1b[0m');
77
+ console.log('\x1b[36m', 'ℹ️ Info: The components.js file may be corrupted', '\x1b[0m');
73
78
  return false;
74
79
  }
75
80
  }
@@ -1,28 +1,35 @@
1
1
  export default class componentTemplates{
2
2
 
3
- static visual(componentName, props){
4
- const propGettersSetters = props.map(prop => `
5
- get ${prop}() {
6
- return this._${prop};
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
+ */
7
16
  }
8
17
 
9
- set ${prop}(value) {
10
- this._${prop} = value;
11
- }
12
- `).join('\n');
13
-
14
- return `export default class ${componentName} extends HTMLElement {
15
18
  constructor(props) {
16
19
  super();
17
20
  slice.attachTemplate(this);
18
-
19
21
  slice.controller.setComponentProps(this, props);
20
- this.debuggerProps = [${props.map(prop => `"${prop}"`).join(',')}];
21
22
  }
22
23
 
23
- init() {}
24
+ init() {
25
+ // Component initialization logic (can be async)
26
+ }
24
27
 
25
- ${propGettersSetters}
28
+ update() {
29
+ // Component update logic (can be async)
30
+ }
31
+
32
+ // Add your custom methods here
26
33
  }
27
34
 
28
35
  customElements.define("slice-${componentName.toLowerCase()}", ${componentName});
@@ -30,18 +37,19 @@ customElements.define("slice-${componentName.toLowerCase()}", ${componentName});
30
37
  }
31
38
 
32
39
  static service(componentName) {
33
-
34
-
35
40
  return `export default class ${componentName} {
36
- constructor(props) {
37
- // Constructor
38
- }
39
-
40
- init() {
41
- // Método init
42
- }
43
- }
44
- `;
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
+ `;
45
53
  }
46
54
  }
47
55
 
@@ -7,29 +7,39 @@ import Validations from '../Validations.js';
7
7
  import Print from '../Print.js';
8
8
  const __dirname = path.dirname(new URL(import.meta.url).pathname);
9
9
 
10
- function createComponent(componentName, category, properties) {
10
+ function createComponent(componentName, category) {
11
+ // Validación: Nombre de componente requerido
11
12
  if (!componentName) {
12
13
  Print.error('Component name is required');
13
- return;
14
+ Print.commandExample("Create a component", "slice component create");
15
+ return false;
14
16
  }
15
17
 
18
+ // Validación: Nombre de componente válido
16
19
  if (!Validations.isValidComponentName(componentName)) {
17
- Print.error('Invalid component name. Please use only alphanumeric characters and start with a letter.');
18
- return;
20
+ Print.error(`Invalid component name: '${componentName}'`);
21
+ Print.info('Component name must start with a letter and contain only alphanumeric characters');
22
+ Print.commandExample("Valid names", "Button, UserCard, NavBar");
23
+ Print.commandExample("Invalid names", "1Button, user-card, Nav_Bar");
24
+ return false;
19
25
  }
20
26
 
27
+ // Validación: Componente ya existe
21
28
  if(Validations.componentExists(componentName)){
22
- Print.error(`Component '${componentName}' already exists. Please use a different name.`);
23
- return;
29
+ Print.error(`Component '${componentName}' already exists in your project`);
30
+ Print.info('Please use a different name or delete the existing component first');
31
+ Print.commandExample("Delete component", "slice component delete");
32
+ return false;
24
33
  }
25
34
 
35
+ // Validación: Categoría válida
26
36
  let flagCategory = Validations.isValidCategory(category);
27
37
 
28
-
29
-
30
38
  if (!flagCategory.isValid) {
31
- Print.error('Invalid category. Please use one of the following categories: Service, Visual, Provider, Structural');
32
- return;
39
+ Print.error(`Invalid category: '${category}'`);
40
+ const availableCategories = Object.keys(Validations.getCategories()).join(', ');
41
+ Print.info(`Available categories: ${availableCategories}`);
42
+ return false;
33
43
  }
34
44
  category = flagCategory.category;
35
45
 
@@ -40,46 +50,76 @@ function createComponent(componentName, category, properties) {
40
50
 
41
51
  const type = Validations.getCategoryType(category);
42
52
 
43
-
44
- if(type==='Visual'){
45
- template = componentTemplates.visual(className, properties);
46
- }
47
-
48
- if(type==='Service'){
53
+ // Generar template según el tipo
54
+ if(type === 'Visual'){
55
+ template = componentTemplates.visual(className);
56
+ } else if(type === 'Service'){
49
57
  template = componentTemplates.service(className);
50
- }
58
+ } else {
59
+ Print.error(`Unsupported component type: '${type}'`);
60
+ Print.info('Only Visual and Service components are currently supported');
61
+ return false;
62
+ }
51
63
 
52
64
  const categoryPath = Validations.getCategoryPath(category);
53
65
 
54
-
55
- // Determinar la ruta del archivo
66
+ // Determinar la ruta del directorio del componente
56
67
  let componentDir = path.join(__dirname, '../../../../src/', categoryPath, className);
57
- componentDir=componentDir.slice(1);
58
- fs.ensureDirSync(componentDir);
68
+ componentDir = componentDir.slice(1);
59
69
 
70
+ try {
71
+ // Crear directorio del componente
72
+ fs.ensureDirSync(componentDir);
73
+ } catch (error) {
74
+ Print.error(`Failed to create component directory: '${componentDir}'`);
75
+ Print.info(`Error details: ${error.message}`);
76
+ return false;
77
+ }
60
78
 
61
79
  // Determinar la ruta del archivo
62
80
  let componentPath = path.join(componentDir, fileName);
63
81
 
64
-
65
- // Verificar si el archivo ya existe
82
+ // Verificar si el archivo ya existe (doble verificación)
66
83
  if (fs.existsSync(componentPath)) {
67
- Print.error(`Component '${componentName}' already exists.`);
68
- return;
84
+ Print.error(`Component file already exists at: '${componentPath}'`);
85
+ Print.info('This component may have been created outside the CLI');
86
+ return false;
69
87
  }
70
88
 
71
-
72
-
73
- // Escribir el código del componente en el archivo
74
- fs.writeFileSync(componentPath, template);
75
-
76
- if(type==='Visual'){
77
- fs.writeFileSync(`${componentDir}/${className}.css`, '');
78
- fs.writeFileSync(`${componentDir}/${className}.html`, `<div>${componentName}</div>`);
89
+ try {
90
+ // Escribir el código del componente en el archivo
91
+ fs.writeFileSync(componentPath, template);
92
+
93
+ // Si es Visual, crear archivos adicionales (CSS y HTML)
94
+ if(type === 'Visual'){
95
+ const cssPath = `${componentDir}/${className}.css`;
96
+ const htmlPath = `${componentDir}/${className}.html`;
97
+
98
+ fs.writeFileSync(cssPath, '/* Styles for ' + componentName + ' component */\n');
99
+ fs.writeFileSync(htmlPath, `<div class="${componentName.toLowerCase()}">\n ${componentName}\n</div>`);
100
+
101
+ Print.info(`Created files: ${fileName}, ${className}.css, ${className}.html`);
102
+ } else {
103
+ Print.info(`Created file: ${fileName}`);
104
+ }
105
+
106
+ return true;
107
+ } catch (error) {
108
+ Print.error(`Failed to create component files`);
109
+ Print.info(`Error details: ${error.message}`);
110
+
111
+ // Intentar limpiar archivos parcialmente creados
112
+ try {
113
+ if (fs.existsSync(componentDir)) {
114
+ fs.removeSync(componentDir);
115
+ Print.info('Cleaned up partial files');
116
+ }
117
+ } catch (cleanupError) {
118
+ Print.warning('Could not clean up partial files. You may need to delete them manually');
119
+ }
120
+
121
+ return false;
79
122
  }
80
-
81
- Print.success(`Component '${componentName}' created successfully.`);
82
- return true;
83
123
  }
84
124
 
85
125
 
@@ -5,42 +5,73 @@ import Print from '../Print.js';
5
5
  const __dirname = path.dirname(new URL(import.meta.url).pathname);
6
6
 
7
7
  function deleteComponent(componentName, category) {
8
+ // Validación: Nombre de componente requerido
8
9
  if (!componentName) {
9
- Print.error('Component name is required');
10
- return;
10
+ Print.error('Component name is required to delete');
11
+ Print.commandExample("Delete a component", "slice component delete");
12
+ return false;
11
13
  }
12
14
 
15
+ // Validación: Nombre de componente válido
13
16
  if (!Validations.isValidComponentName(componentName)) {
14
- Print.error('Invalid component name. Please use only alphanumeric characters and start with a letter.');
15
- return;
17
+ Print.error(`Invalid component name: '${componentName}'`);
18
+ Print.info('Component name must start with a letter and contain only alphanumeric characters');
19
+ return false;
16
20
  }
17
21
 
22
+ // Validación: Categoría válida
18
23
  let flagCategory = Validations.isValidCategory(category);
19
24
 
20
25
  if (!flagCategory.isValid) {
21
- Print.error('Invalid category. Please use one of the following categories: Service, Visual, Provider, Structural');
22
- return;
26
+ Print.error(`Invalid category: '${category}'`);
27
+ const availableCategories = Object.keys(Validations.getCategories()).join(', ');
28
+ Print.info(`Available categories: ${availableCategories}`);
29
+ return false;
23
30
  }
24
31
  category = flagCategory.category;
25
32
 
26
33
  const categoryPath = Validations.getCategoryPath(category);
27
34
 
28
-
29
35
  // Construir la ruta del directorio del componente
30
36
  let componentDir = path.join(__dirname, '../../../../src/', categoryPath, componentName);
31
37
  componentDir = componentDir.slice(1);
32
38
 
33
39
  // Verificar si el directorio del componente existe
34
40
  if (!fs.existsSync(componentDir)) {
35
- Print.error(`Component '${componentName}' does not exist.`);
36
- return;
41
+ Print.error(`Component '${componentName}' does not exist in category '${category}'`);
42
+ Print.info('Make sure you selected the correct category');
43
+ Print.commandExample("List components", "slice component list");
44
+ return false;
37
45
  }
38
46
 
39
- // Eliminar el directorio del componente y su contenido
40
- fs.removeSync(componentDir);
47
+ // Verificar si es un directorio
48
+ try {
49
+ const stats = fs.statSync(componentDir);
50
+ if (!stats.isDirectory()) {
51
+ Print.error(`'${componentName}' is not a valid component directory`);
52
+ Print.info('Components must be stored in directories');
53
+ return false;
54
+ }
55
+ } catch (error) {
56
+ Print.error(`Failed to access component directory: '${componentDir}'`);
57
+ Print.info(`Error details: ${error.message}`);
58
+ return false;
59
+ }
41
60
 
42
- Print.success(`Component '${componentName}' deleted successfully.`);
43
- return true;
61
+ // Intentar eliminar el directorio del componente y su contenido
62
+ try {
63
+ const files = fs.readdirSync(componentDir);
64
+ Print.info(`Deleting ${files.length} file(s) from component directory...`);
65
+
66
+ fs.removeSync(componentDir);
67
+ return true;
68
+ } catch (error) {
69
+ Print.error(`Failed to delete component '${componentName}'`);
70
+ Print.info(`Error details: ${error.message}`);
71
+ Print.warning('You may need to delete the component files manually');
72
+ Print.info(`Component location: ${componentDir}`);
73
+ return false;
74
+ }
44
75
  }
45
76
 
46
77
  export default deleteComponent;
@@ -12,10 +12,16 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
12
  const loadConfig = () => {
13
13
  try {
14
14
  const configPath = path.join(__dirname, '../../../../src/sliceConfig.json');
15
+ if (!fs.existsSync(configPath)) {
16
+ Print.error('sliceConfig.json not found');
17
+ Print.info('Run "slice init" to initialize your project');
18
+ return null;
19
+ }
15
20
  const rawData = fs.readFileSync(configPath, 'utf-8');
16
21
  return JSON.parse(rawData);
17
22
  } catch (error) {
18
- console.error(`Error cargando configuración: ${error.message}`);
23
+ Print.error(`Failed to load configuration: ${error.message}`);
24
+ Print.info('Check that sliceConfig.json is valid JSON');
19
25
  return null;
20
26
  }
21
27
  };
@@ -27,10 +33,14 @@ const loadConfig = () => {
27
33
  */
28
34
  const listComponents = (folderPath) => {
29
35
  try {
30
- const result = fs.readdirSync(folderPath)
36
+ if (!fs.existsSync(folderPath)) {
37
+ Print.warning(`Component directory not found: ${folderPath}`);
38
+ return [];
39
+ }
40
+ const result = fs.readdirSync(folderPath);
31
41
  return result;
32
42
  } catch (error) {
33
- console.error(`Error leyendo carpeta ${folderPath}: ${error.message}`);
43
+ Print.error(`Failed to read directory ${folderPath}: ${error.message}`);
34
44
  return [];
35
45
  }
36
46
  };
@@ -66,16 +76,34 @@ const getComponents = () => {
66
76
  };
67
77
 
68
78
  function listComponentsReal(){
69
- // Obtener componentes dinámicamente
70
- const components = getComponents();
71
-
72
- // Ruta donde se generará components.js
73
- const outputPath = path.join(__dirname, '../../../../src/Components/components.js');
74
-
75
- // Generar archivo components.js con los componentes detectados
76
- fs.writeFileSync(outputPath, `const components = ${JSON.stringify(components, null, 2)}; export default components;`);
77
-
78
- Print.success('Lista de componentes actualizada dinámicamente');
79
+ try {
80
+ // Obtener componentes dinámicamente
81
+ const components = getComponents();
82
+
83
+ if (Object.keys(components).length === 0) {
84
+ Print.warning('No components found in your project');
85
+ Print.info('Create your first component with "slice component create"');
86
+ return;
87
+ }
88
+
89
+ // Ruta donde se generará components.js
90
+ const outputPath = path.join(__dirname, '../../../../src/Components/components.js');
91
+
92
+ // Asegurar que el directorio existe
93
+ const outputDir = path.dirname(outputPath);
94
+ if (!fs.existsSync(outputDir)) {
95
+ fs.mkdirSync(outputDir, { recursive: true });
96
+ Print.info('Created Components directory');
97
+ }
98
+
99
+ // Generar archivo components.js con los componentes detectados
100
+ fs.writeFileSync(outputPath, `const components = ${JSON.stringify(components, null, 2)};\n\nexport default components;\n`);
101
+
102
+ Print.success(`Component list updated successfully (${Object.keys(components).length} component${Object.keys(components).length !== 1 ? 's' : ''} found)`);
103
+ } catch (error) {
104
+ Print.error(`Failed to update component list: ${error.message}`);
105
+ Print.info('Make sure your project structure is correct');
106
+ }
79
107
  }
80
108
 
81
109
  export default listComponentsReal;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slicejs-cli",
3
- "version": "2.3.1",
3
+ "version": "2.3.2",
4
4
  "description": "Command client for developing web applications with Slice.js framework",
5
5
  "main": "client.js",
6
6
  "scripts": {