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,175 +1,172 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import { fileURLToPath } from 'url';
4
- import Table from 'cli-table3';
5
- import chalk from 'chalk';
6
- import Print from '../Print.js';
7
- import { getSrcPath, getComponentsJsPath, getConfigPath } from '../utils/PathHelper.js';
8
-
9
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
10
-
11
- /**
12
- * Carga la configuración desde sliceConfig.json
13
- * @returns {object} - Objeto de configuración
14
- */
15
- const loadConfig = () => {
16
- try {
17
- const configPath = getConfigPath(import.meta.url);
18
- if (!fs.existsSync(configPath)) {
19
- Print.error('sliceConfig.json not found');
20
- Print.info('Run "slice init" to initialize your project');
21
- return null;
22
- }
23
- const rawData = fs.readFileSync(configPath, 'utf-8');
24
- return JSON.parse(rawData);
25
- } catch (error) {
26
- Print.error(`Failed to load configuration: ${error.message}`);
27
- Print.info('Check that sliceConfig.json is valid JSON');
28
- return null;
29
- }
30
- };
31
-
32
- /**
33
- * Lista los archivos en una carpeta dada, filtrando solo los archivos .js
34
- * @param {string} folderPath - Ruta de la carpeta a leer
35
- * @returns {string[]} - Lista de archivos encontrados
36
- */
37
- const listComponents = (folderPath) => {
38
- try {
39
- if (!fs.existsSync(folderPath)) {
40
- return [];
41
- }
42
- const result = fs.readdirSync(folderPath);
43
- return result;
44
- } catch (error) {
45
- Print.error(`Failed to read directory ${folderPath}: ${error.message}`);
46
- return [];
47
- }
48
- };
49
-
50
- /**
51
- * Cuenta archivos en un directorio de componente
52
- */
53
- const countComponentFiles = (componentPath) => {
54
- try {
55
- if (!fs.existsSync(componentPath)) return 0;
56
- const files = fs.readdirSync(componentPath);
57
- return files.filter(f => fs.statSync(path.join(componentPath, f)).isFile()).length;
58
- } catch {
59
- return 0;
60
- }
61
- };
62
-
63
- /**
64
- * Obtiene los componentes dinámicamente desde sliceConfig.json
65
- * @returns {object} - Mapeo de componentes con su categoría
66
- */
67
- const getComponents = () => {
68
- const config = loadConfig();
69
- if (!config) return {};
70
-
71
- const folderSuffix = 'src'; // Siempre usar 'src' para desarrollo
72
- const componentPaths = config.paths?.components || {};
73
- let allComponents = new Map();
74
-
75
- Object.entries(componentPaths).forEach(([category, { path: folderPath }]) => {
76
- const cleanFolderPath = folderPath ? folderPath.replace(/^[/\\]+/, '') : '';
77
- const fullPath = getSrcPath(import.meta.url, cleanFolderPath);
78
- const files = listComponents(fullPath);
79
-
80
- files.forEach(file => {
81
- const componentPath = path.join(fullPath, file);
82
- if (fs.statSync(componentPath).isDirectory()) {
83
- const fileCount = countComponentFiles(componentPath);
84
- allComponents.set(file, { category, files: fileCount });
85
- }
86
- });
87
- });
88
-
89
- return Object.fromEntries(allComponents);
90
- };
91
-
92
- function listComponentsReal() {
93
- try {
94
- // Obtener componentes dinámicamente
95
- const components = getComponents();
96
-
97
- if (Object.keys(components).length === 0) {
98
- Print.warning('No components found in your project');
99
- Print.info('Create your first component with "slice component create"');
100
- return;
101
- }
102
-
103
- // Crear tabla con cli-table3
104
- const table = new Table({
105
- head: [
106
- chalk.cyan.bold('Component'),
107
- chalk.cyan.bold('Category'),
108
- chalk.cyan.bold('Files')
109
- ],
110
- colWidths: [30, 20, 10],
111
- style: {
112
- head: [],
113
- border: ['gray']
114
- }
115
- });
116
-
117
- // Agrupar por categoría para mejor visualización
118
- const byCategory = {};
119
- Object.entries(components).forEach(([name, data]) => {
120
- if (!byCategory[data.category]) {
121
- byCategory[data.category] = [];
122
- }
123
- byCategory[data.category].push({ name, files: data.files });
124
- });
125
-
126
- // Agregar filas a la tabla
127
- Object.entries(byCategory).forEach(([category, comps]) => {
128
- comps.forEach((comp, index) => {
129
- if (index === 0) {
130
- // Primera fila de la categoría
131
- table.push([
132
- chalk.bold(comp.name),
133
- chalk.yellow(category),
134
- comp.files.toString()
135
- ]);
136
- } else {
137
- // Resto de componentes en la categoría
138
- table.push([
139
- chalk.bold(comp.name),
140
- chalk.gray('″'), // Ditto mark
141
- comp.files.toString()
142
- ]);
143
- }
144
- });
145
- });
146
-
147
- Print.newLine();
148
- Print.title('📦 Local Components');
149
- Print.newLine();
150
- console.log(table.toString());
151
- Print.newLine();
152
- Print.info(`Total: ${Object.keys(components).length} component${Object.keys(components).length !== 1 ? 's' : ''} found`);
153
-
154
- // Ruta donde se generará components.js
155
- const outputPath = getComponentsJsPath(import.meta.url);
156
-
157
- // Asegurar que el directorio existe
158
- const outputDir = path.dirname(outputPath);
159
- if (!fs.existsSync(outputDir)) {
160
- fs.mkdirSync(outputDir, { recursive: true });
161
- }
162
-
163
- // Generar archivo components.js con los componentes detectados
164
- const componentsForExport = Object.fromEntries(
165
- Object.entries(components).map(([name, data]) => [name, data.category])
166
- );
167
- fs.writeFileSync(outputPath, `const components = ${JSON.stringify(componentsForExport, null, 2)};\n\nexport default components;\n`);
168
-
169
- } catch (error) {
170
- Print.error(`Failed to list components: ${error.message}`);
171
- Print.info('Make sure your project structure is correct');
172
- }
173
- }
174
-
175
- export default listComponentsReal;
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import Table from 'cli-table3';
4
+ import chalk from 'chalk';
5
+ import Print from '../Print.js';
6
+ import { getSrcPath, getComponentsJsPath, getConfigPath } from '../utils/PathHelper.js';
7
+
8
+ /**
9
+ * Loads configuration from sliceConfig.json
10
+ * @returns {object} - Configuration object
11
+ */
12
+ const loadConfig = () => {
13
+ try {
14
+ const configPath = getConfigPath(import.meta.url);
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
+ }
20
+ const rawData = fs.readFileSync(configPath, 'utf-8');
21
+ return JSON.parse(rawData);
22
+ } catch (error) {
23
+ Print.error(`Failed to load configuration: ${error.message}`);
24
+ Print.info('Check that sliceConfig.json is valid JSON');
25
+ return null;
26
+ }
27
+ };
28
+
29
+ /**
30
+ * Lists files in a given folder, filtering only .js files
31
+ * @param {string} folderPath - Path of the folder to read
32
+ * @returns {string[]} - List of found files
33
+ */
34
+ const listComponents = (folderPath) => {
35
+ try {
36
+ if (!fs.existsSync(folderPath)) {
37
+ return [];
38
+ }
39
+ const result = fs.readdirSync(folderPath);
40
+ return result;
41
+ } catch (error) {
42
+ Print.error(`Failed to read directory ${folderPath}: ${error.message}`);
43
+ return [];
44
+ }
45
+ };
46
+
47
+ /**
48
+ * Counts files in a component directory
49
+ */
50
+ const countComponentFiles = (componentPath) => {
51
+ try {
52
+ if (!fs.existsSync(componentPath)) return 0;
53
+ const files = fs.readdirSync(componentPath);
54
+ return files.filter(f => fs.statSync(path.join(componentPath, f)).isFile()).length;
55
+ } catch {
56
+ return 0;
57
+ }
58
+ };
59
+
60
+ /**
61
+ * Gets components dynamically from sliceConfig.json
62
+ * @returns {object} - Component mapping with their category
63
+ */
64
+ const getComponents = () => {
65
+ const config = loadConfig();
66
+ if (!config) return {};
67
+
68
+ const folderSuffix = 'src'; // Always use 'src' for development
69
+ const componentPaths = config.paths?.components || {};
70
+ let allComponents = new Map();
71
+
72
+ Object.entries(componentPaths).forEach(([category, { path: folderPath }]) => {
73
+ const cleanFolderPath = folderPath ? folderPath.replace(/^[/\\]+/, '') : '';
74
+ const fullPath = getSrcPath(import.meta.url, cleanFolderPath);
75
+ const files = listComponents(fullPath);
76
+
77
+ files.forEach(file => {
78
+ const componentPath = path.join(fullPath, file);
79
+ if (fs.statSync(componentPath).isDirectory()) {
80
+ const fileCount = countComponentFiles(componentPath);
81
+ allComponents.set(file, { category, files: fileCount });
82
+ }
83
+ });
84
+ });
85
+
86
+ return Object.fromEntries(allComponents);
87
+ };
88
+
89
+ function listComponentsReal() {
90
+ try {
91
+ // Get components dynamically
92
+ const components = getComponents();
93
+
94
+ if (Object.keys(components).length === 0) {
95
+ Print.warning('No components found in your project');
96
+ Print.info('Create your first component with "slice component create"');
97
+ return;
98
+ }
99
+
100
+ // Create table with cli-table3
101
+ const table = new Table({
102
+ head: [
103
+ chalk.cyan.bold('Component'),
104
+ chalk.cyan.bold('Category'),
105
+ chalk.cyan.bold('Files')
106
+ ],
107
+ colWidths: [30, 20, 10],
108
+ style: {
109
+ head: [],
110
+ border: ['gray']
111
+ }
112
+ });
113
+
114
+ // Group by category for better visualization
115
+ const byCategory = {};
116
+ Object.entries(components).forEach(([name, data]) => {
117
+ if (!byCategory[data.category]) {
118
+ byCategory[data.category] = [];
119
+ }
120
+ byCategory[data.category].push({ name, files: data.files });
121
+ });
122
+
123
+ // Add rows to the table
124
+ Object.entries(byCategory).forEach(([category, comps]) => {
125
+ comps.forEach((comp, index) => {
126
+ if (index === 0) {
127
+ // First row of the category
128
+ table.push([
129
+ chalk.bold(comp.name),
130
+ chalk.yellow(category),
131
+ comp.files.toString()
132
+ ]);
133
+ } else {
134
+ // Rest of components in the category
135
+ table.push([
136
+ chalk.bold(comp.name),
137
+ chalk.gray('″'), // Ditto mark
138
+ comp.files.toString()
139
+ ]);
140
+ }
141
+ });
142
+ });
143
+
144
+ Print.newLine();
145
+ Print.title('📦 Local Components');
146
+ Print.newLine();
147
+ console.log(table.toString());
148
+ Print.newLine();
149
+ Print.info(`Total: ${Object.keys(components).length} component${Object.keys(components).length !== 1 ? 's' : ''} found`);
150
+
151
+ // Path where components.js will be generated
152
+ const outputPath = getComponentsJsPath(import.meta.url);
153
+
154
+ // Ensure the directory exists
155
+ const outputDir = path.dirname(outputPath);
156
+ if (!fs.existsSync(outputDir)) {
157
+ fs.mkdirSync(outputDir, { recursive: true });
158
+ }
159
+
160
+ // Generate components.js file with detected components
161
+ const componentsForExport = Object.fromEntries(
162
+ Object.entries(components).map(([name, data]) => [name, data.category])
163
+ );
164
+ fs.writeFileSync(outputPath, `const components = ${JSON.stringify(componentsForExport, null, 2)};\n\nexport default components;\n`);
165
+
166
+ } catch (error) {
167
+ Print.error(`Failed to list components: ${error.message}`);
168
+ Print.info('Make sure your project structure is correct');
169
+ }
170
+ }
171
+
172
+ export default listComponentsReal;