holygrail5 1.0.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.
@@ -0,0 +1,248 @@
1
+ // Gestor de variables CSS
2
+ // Permite detectar variables no usadas y eliminar variables del historial
3
+
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+
7
+ // Carga las variables históricas desde el archivo
8
+ function loadHistoricalVariables(historicalVarsPath = null) {
9
+ const defaultPath = historicalVarsPath || path.join(__dirname, '..', '.data', '.historical-variables.json');
10
+ try {
11
+ if (fs.existsSync(defaultPath)) {
12
+ const content = fs.readFileSync(defaultPath, 'utf8');
13
+ return JSON.parse(content);
14
+ }
15
+ } catch (error) {
16
+ console.error('❌ Error al cargar variables históricas:', error.message);
17
+ }
18
+ return {
19
+ fontFamilyVars: {},
20
+ lineHeightVars: {},
21
+ fontWeightVars: {},
22
+ letterSpacingVars: {},
23
+ textTransformVars: {},
24
+ fontSizeVars: {}
25
+ };
26
+ }
27
+
28
+ // Guarda las variables históricas en el archivo
29
+ function saveHistoricalVariables(variables, historicalVarsPath = null) {
30
+ const defaultPath = historicalVarsPath || path.join(__dirname, '..', '.data', '.historical-variables.json');
31
+ try {
32
+ const dir = path.dirname(defaultPath);
33
+ if (!fs.existsSync(dir)) {
34
+ fs.mkdirSync(dir, { recursive: true });
35
+ }
36
+ fs.writeFileSync(defaultPath, JSON.stringify(variables, null, 2), 'utf8');
37
+ return true;
38
+ } catch (error) {
39
+ console.error('❌ Error al guardar variables históricas:', error.message);
40
+ return false;
41
+ }
42
+ }
43
+
44
+ // Extrae todas las variables CSS definidas en :root del CSS generado
45
+ function extractDefinedVariables(cssContent) {
46
+ const variables = new Set();
47
+ // Buscar todas las variables en :root { ... }
48
+ const rootMatch = cssContent.match(/:root\s*\{([^}]+)\}/s);
49
+ if (rootMatch) {
50
+ const rootContent = rootMatch[1];
51
+ // Buscar todas las líneas que contienen --variable-name: value;
52
+ const varRegex = /--[\w-]+/g;
53
+ let match;
54
+ while ((match = varRegex.exec(rootContent)) !== null) {
55
+ variables.add(match[0]);
56
+ }
57
+ }
58
+ return variables;
59
+ }
60
+
61
+ // Extrae todas las variables CSS usadas en el CSS generado
62
+ function extractUsedVariables(cssContent) {
63
+ const variables = new Set();
64
+ // Buscar todos los usos de var(--variable-name)
65
+ const varRegex = /var\((--[\w-]+)\)/g;
66
+ let match;
67
+ while ((match = varRegex.exec(cssContent)) !== null) {
68
+ variables.add(match[1]);
69
+ }
70
+ return variables;
71
+ }
72
+
73
+ // Encuentra variables no usadas comparando las definidas con las usadas
74
+ // También incluye variables históricas que no están siendo generadas en el CSS
75
+ function findUnusedVariables(cssContent, historicalVarsPath = null) {
76
+ const defined = extractDefinedVariables(cssContent);
77
+ const used = extractUsedVariables(cssContent);
78
+ const unused = [];
79
+
80
+ // Variables definidas en CSS pero no usadas
81
+ defined.forEach(varName => {
82
+ if (!used.has(varName)) {
83
+ unused.push(varName);
84
+ }
85
+ });
86
+
87
+ // Variables históricas que no están siendo generadas en el CSS
88
+ const historicalVars = loadHistoricalVariables(historicalVarsPath);
89
+ const allHistorical = getAllHistoricalVariables(historicalVars);
90
+
91
+ allHistorical.forEach(varData => {
92
+ const varName = varData.varName;
93
+ // Si la variable histórica no está definida en el CSS y no se usa, es no usada
94
+ if (!defined.has(varName) && !used.has(varName)) {
95
+ // Solo agregar si no está ya en la lista (evitar duplicados)
96
+ if (!unused.includes(varName)) {
97
+ unused.push(varName);
98
+ }
99
+ }
100
+ });
101
+
102
+ return unused.sort();
103
+ }
104
+
105
+ // Obtiene todas las variables históricas como un array de objetos con información
106
+ function getAllHistoricalVariables(historicalVars) {
107
+ const allVars = [];
108
+
109
+ Object.entries(historicalVars).forEach(([category, vars]) => {
110
+ Object.entries(vars).forEach(([key, varData]) => {
111
+ allVars.push({
112
+ varName: varData.varName,
113
+ value: varData.value,
114
+ category: category.replace('Vars', ''),
115
+ key: key
116
+ });
117
+ });
118
+ });
119
+
120
+ return allVars.sort((a, b) => a.varName.localeCompare(b.varName));
121
+ }
122
+
123
+ // Elimina una variable específica del historial
124
+ function removeVariableFromHistory(varName, historicalVarsPath = null) {
125
+ const historicalVars = loadHistoricalVariables(historicalVarsPath);
126
+ let removed = false;
127
+
128
+ // Buscar y eliminar la variable en todas las categorías
129
+ Object.keys(historicalVars).forEach(category => {
130
+ if (historicalVars[category]) {
131
+ Object.keys(historicalVars[category]).forEach(key => {
132
+ if (historicalVars[category][key] && historicalVars[category][key].varName === varName) {
133
+ delete historicalVars[category][key];
134
+ removed = true;
135
+ }
136
+ });
137
+ }
138
+ });
139
+
140
+ if (removed) {
141
+ saveHistoricalVariables(historicalVars, historicalVarsPath);
142
+ }
143
+
144
+ return removed;
145
+ }
146
+
147
+ // Elimina múltiples variables del historial
148
+ function removeVariablesFromHistory(varNames, historicalVarsPath = null) {
149
+ const historicalVars = loadHistoricalVariables(historicalVarsPath);
150
+ let removedCount = 0;
151
+
152
+ varNames.forEach(varName => {
153
+ Object.keys(historicalVars).forEach(category => {
154
+ if (historicalVars[category]) {
155
+ Object.keys(historicalVars[category]).forEach(key => {
156
+ if (historicalVars[category][key] && historicalVars[category][key].varName === varName) {
157
+ delete historicalVars[category][key];
158
+ removedCount++;
159
+ }
160
+ });
161
+ }
162
+ });
163
+ });
164
+
165
+ if (removedCount > 0) {
166
+ saveHistoricalVariables(historicalVars, historicalVarsPath);
167
+ }
168
+
169
+ return removedCount;
170
+ }
171
+
172
+ // Función principal para listar variables no usadas
173
+ function listUnusedVariables(cssPath = null, historicalVarsPath = null) {
174
+ const defaultPath = cssPath || path.join(__dirname, '..', 'dist', 'output.css');
175
+ const historicalVarsPathDefault = historicalVarsPath || path.join(__dirname, '..', '.historical-variables.json');
176
+
177
+ if (!fs.existsSync(defaultPath)) {
178
+ console.error(`❌ No se encontró el archivo CSS en: ${defaultPath}`);
179
+ console.log('💡 Ejecuta primero: node generator.js');
180
+ return [];
181
+ }
182
+
183
+ const cssContent = fs.readFileSync(defaultPath, 'utf8');
184
+ const unused = findUnusedVariables(cssContent, historicalVarsPathDefault);
185
+
186
+ return unused;
187
+ }
188
+
189
+ // Función principal para mostrar un reporte de variables
190
+ function showVariablesReport(cssPath = null, historicalVarsPath = null) {
191
+ const cssDefaultPath = cssPath || path.join(__dirname, '..', 'dist', 'output.css');
192
+ const historicalVarsPathDefault = historicalVarsPath || path.join(__dirname, '..', '.historical-variables.json');
193
+ const historicalVars = loadHistoricalVariables(historicalVarsPathDefault);
194
+
195
+ console.log('\n📊 Reporte de Variables CSS\n');
196
+ console.log('═'.repeat(60));
197
+
198
+ // Mostrar variables definidas vs usadas
199
+ if (fs.existsSync(cssDefaultPath)) {
200
+ const cssContent = fs.readFileSync(cssDefaultPath, 'utf8');
201
+ const defined = extractDefinedVariables(cssContent);
202
+ const used = extractUsedVariables(cssContent);
203
+ const unused = findUnusedVariables(cssContent, historicalVarsPathDefault);
204
+
205
+ console.log(`\n📈 Estadísticas:`);
206
+ console.log(` Variables definidas en CSS: ${defined.size}`);
207
+ console.log(` Variables usadas: ${used.size}`);
208
+ console.log(` Variables no usadas: ${unused.length}`);
209
+
210
+ if (unused.length > 0) {
211
+ console.log(`\n⚠️ Variables no usadas (${unused.length}):`);
212
+ unused.forEach((varName, index) => {
213
+ console.log(` ${index + 1}. ${varName}`);
214
+ });
215
+ } else {
216
+ console.log(`\n✅ Todas las variables están en uso`);
217
+ }
218
+ } else {
219
+ console.log(`\n⚠️ No se encontró el archivo CSS. Ejecuta primero: node generator.js`);
220
+ }
221
+
222
+ // Mostrar variables históricas
223
+ const allHistorical = getAllHistoricalVariables(historicalVars);
224
+ console.log(`\n📚 Variables históricas almacenadas: ${allHistorical.length}`);
225
+
226
+ if (allHistorical.length > 0) {
227
+ console.log(`\n📋 Lista de variables históricas:`);
228
+ allHistorical.forEach((varData, index) => {
229
+ console.log(` ${index + 1}. ${varData.varName} (${varData.category})`);
230
+ });
231
+ }
232
+
233
+ console.log('\n' + '═'.repeat(60) + '\n');
234
+ }
235
+
236
+ module.exports = {
237
+ loadHistoricalVariables,
238
+ saveHistoricalVariables,
239
+ findUnusedVariables,
240
+ getAllHistoricalVariables,
241
+ removeVariableFromHistory,
242
+ removeVariablesFromHistory,
243
+ listUnusedVariables,
244
+ showVariablesReport,
245
+ extractDefinedVariables,
246
+ extractUsedVariables
247
+ };
248
+
package/src/watch.js ADDED
@@ -0,0 +1,88 @@
1
+ // Modo watch - Detecta cambios en config.json y regenera automáticamente
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { loadConfig } = require('./config');
6
+ const { generateCSS } = require('./parser');
7
+ const { generateHTML } = require('./guide');
8
+ const { writeFile } = require('./utils');
9
+
10
+ // Función para generar CSS y HTML
11
+ function generateFiles(configPath, outputPath, htmlPath) {
12
+ try {
13
+ const configData = loadConfig(configPath);
14
+
15
+ // Generar CSS
16
+ const cssContent = generateCSS(configData);
17
+ writeFile(outputPath, cssContent, 'CSS');
18
+
19
+ // Generar HTML (ajustar ruta del CSS en el HTML si está en carpeta diferente)
20
+ let htmlContent = generateHTML(configData);
21
+
22
+ // Si el HTML y CSS están en carpetas diferentes, ajustar la ruta del CSS
23
+ const outputDir = path.dirname(outputPath);
24
+ const htmlDir = path.dirname(htmlPath);
25
+
26
+ // Si el HTML y CSS están en carpetas diferentes, ajustar la ruta del CSS
27
+ // Si están en la misma carpeta (dist/), usar ruta relativa simple
28
+ if (outputDir !== htmlDir) {
29
+ const relativePath = path.relative(htmlDir, outputDir);
30
+ const cssFileName = path.basename(outputPath);
31
+ const cssRelativePath = path.join(relativePath, cssFileName).replace(/\\/g, '/');
32
+ htmlContent = htmlContent.replace(/href="output\.css[^"]*"/, `href="${cssRelativePath}?v=${Date.now()}"`);
33
+ } else {
34
+ // Si están en la misma carpeta, usar solo el nombre del archivo con timestamp
35
+ htmlContent = htmlContent.replace(/href="output\.css[^"]*"/, `href="output.css?v=${Date.now()}"`);
36
+ }
37
+
38
+ writeFile(htmlPath, htmlContent, 'HTML');
39
+
40
+ console.log(`\n🎉 Generación completada exitosamente! (${new Date().toLocaleTimeString('es-ES')})\n`);
41
+ } catch (error) {
42
+ console.error('❌ Error:', error.message);
43
+ }
44
+ }
45
+
46
+ // Función principal de watch
47
+ function watch(configPath = path.join(__dirname, '..', 'config.json'), outputPath = path.join(__dirname, '..', 'dist', 'output.css'), htmlPath = path.join(__dirname, '..', 'dist', 'index.html')) {
48
+ console.log('👀 Modo watch activado - Monitoreando cambios en config.json...\n');
49
+ console.log('📝 Presiona Ctrl+C para salir\n');
50
+ console.log('💡 Tip: Abre otro terminal y ejecuta "npm run serve" para levantar el servidor\n');
51
+
52
+ // Generar archivos inicialmente
53
+ generateFiles(configPath, outputPath, htmlPath);
54
+
55
+ // Monitorear cambios en config.json
56
+ let lastModified = fs.statSync(configPath).mtime.getTime();
57
+
58
+ fs.watchFile(configPath, { interval: 500 }, (curr, prev) => {
59
+ const currentModified = curr.mtime.getTime();
60
+
61
+ // Solo regenerar si el archivo realmente cambió
62
+ if (currentModified !== lastModified) {
63
+ lastModified = currentModified;
64
+ console.log('🔄 Detectado cambio en config.json, regenerando...\n');
65
+ generateFiles(configPath, outputPath, htmlPath);
66
+ console.log('✨ Archivos actualizados - Recarga el navegador para ver los cambios\n');
67
+ }
68
+ });
69
+
70
+ // Manejar cierre del proceso
71
+ process.on('SIGINT', () => {
72
+ console.log('\n\n👋 Modo watch detenido');
73
+ fs.unwatchFile(configPath);
74
+ process.exit(0);
75
+ });
76
+ }
77
+
78
+ if (require.main === module) {
79
+ const args = process.argv.slice(2);
80
+ const configPath = args.find(arg => arg.startsWith('--config='))?.split('=')[1] || path.join(__dirname, '..', 'config.json');
81
+ const outputPath = args.find(arg => arg.startsWith('--output='))?.split('=')[1] || path.join(__dirname, '..', 'dist', 'output.css');
82
+ const htmlPath = args.find(arg => arg.startsWith('--html='))?.split('=')[1] || path.join(__dirname, '..', 'dist', 'index.html');
83
+
84
+ watch(configPath, outputPath, htmlPath);
85
+ }
86
+
87
+ module.exports = { watch, generateFiles };
88
+