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.
package/config.json ADDED
@@ -0,0 +1,365 @@
1
+ {
2
+ "prefix": "hg",
3
+ "category": "typo",
4
+ "fontFamilyMap": {
5
+ "primary": "arial, sans-serif",
6
+ "secondary": "\"ms-serif\", serif"
7
+ },
8
+ "breakpoints": {
9
+ "mobile": "0px",
10
+ "desktop": "992px"
11
+ },
12
+ "spacingMap": {
13
+ "0": "0",
14
+ "4": "4px",
15
+ "8": "8px",
16
+ "12": "12px",
17
+ "16": "16px",
18
+ "20": "20px",
19
+ "24": "24px",
20
+ "32": "32px",
21
+ "36": "36px",
22
+ "40": "40px",
23
+ "64": "64px",
24
+ "72": "72px",
25
+ "80": "80px",
26
+ "88": "88px",
27
+ "96": "96px",
28
+ "104": "104px",
29
+ "112": "112px",
30
+ "120": "120px",
31
+ "128": "128px",
32
+ "136": "136px",
33
+ "144": "144px",
34
+ "152": "152px",
35
+ "160": "160px",
36
+ "20-percent": "20%",
37
+ "25-percent": "25%",
38
+ "33-percent": "33.333333%",
39
+ "40-percent": "40%",
40
+ "50-percent": "50%",
41
+ "60-percent": "60%",
42
+ "66-percent": "66.666667%",
43
+ "75-percent": "75%",
44
+ "100-percent": "100%"
45
+ },
46
+ "spacingImportant": ["0"],
47
+ "colors": {
48
+ "white": "#ffffff",
49
+ "black": "#000000",
50
+ "dark-grey": "#737373",
51
+ "middle-grey": "#a9a9a9",
52
+ "light-grey": "#f0f0f0",
53
+ "primary": "#000000",
54
+ "error": "#b40016",
55
+ "info": "#1a32a4",
56
+ "success": "#76ae4a",
57
+ "warning": "#ffc700",
58
+ "feel": "#fb9962",
59
+ "feel-dark": "#c94c07",
60
+ "special": "#b99d6b",
61
+ "bg-light": "#F0F0F0",
62
+ "c-bg-light": "#000000",
63
+ "sk-grey": "#e3e3e3",
64
+ "bg-cream": "#f4f2ed"
65
+ },
66
+ "helpers": {
67
+ "display": {
68
+ "property": "display",
69
+ "class": "d",
70
+ "responsive": true,
71
+ "description": "Tipo de caja de renderizado",
72
+ "values": ["contents", "inline", "inline-block", "block", "flex", "inline-flex", "none"]
73
+ },
74
+ "flex-direction": {
75
+ "property": "flex-direction",
76
+ "class": "flex",
77
+ "responsive": true,
78
+ "description": "Dirección del eje principal (horizontal o vertical)",
79
+ "values": {
80
+ "row": "row",
81
+ "column": "column"
82
+ }
83
+ },
84
+ "flex-wrap": {
85
+ "property": "flex-wrap",
86
+ "class": "flex",
87
+ "responsive": true,
88
+ "description": "Permite o no el ajuste en múltiples líneas",
89
+ "values": {
90
+ "nowrap": "nowrap",
91
+ "wrap": "wrap"
92
+ }
93
+ },
94
+ "flex-grow": {
95
+ "property": "flex-grow",
96
+ "class": "grow",
97
+ "responsive": true,
98
+ "description": "Capacidad de crecer para ocupar espacio disponible",
99
+ "values": {
100
+ "0": "0",
101
+ "1": "1",
102
+ "2": "2",
103
+ "3": "3",
104
+ "auto": "auto"
105
+ }
106
+ },
107
+ "flex-shrink": {
108
+ "property": "flex-shrink",
109
+ "class": "shrink",
110
+ "responsive": true,
111
+ "description": "Capacidad de encogerse cuando el espacio es limitado",
112
+ "values": {
113
+ "0": "0",
114
+ "1": "1",
115
+ "2": "2",
116
+ "3": "3",
117
+ "auto": "auto"
118
+ }
119
+ },
120
+ "order": {
121
+ "property": "order",
122
+ "class": "order",
123
+ "responsive": true,
124
+ "description": "Orden de visualización independiente del HTML",
125
+ "values": {
126
+ "3-neg": "-3",
127
+ "2-neg": "-2",
128
+ "1-neg": "-1",
129
+ "0": "0",
130
+ "1": "1",
131
+ "2": "2",
132
+ "3": "3",
133
+ "first": "-9999",
134
+ "last": "9999"
135
+ }
136
+ },
137
+ "justify-content": {
138
+ "property": "justify-content",
139
+ "class": "justify",
140
+ "responsive": true,
141
+ "description": "Alineación en el eje principal",
142
+ "values": {
143
+ "stretch": "stretch",
144
+ "start": "flex-start",
145
+ "end": "flex-end",
146
+ "center": "center",
147
+ "between": "space-between",
148
+ "around": "space-around",
149
+ "evenly": "space-evenly"
150
+ }
151
+ },
152
+ "justify-items": {
153
+ "property": "justify-items",
154
+ "class": "justify-items",
155
+ "responsive": true,
156
+ "description": "Alineación horizontal en grid",
157
+ "values": {
158
+ "stretch": "stretch",
159
+ "start": "flex-start",
160
+ "end": "flex-end",
161
+ "center": "center",
162
+ "between": "space-between",
163
+ "around": "space-around",
164
+ "evenly": "space-evenly"
165
+ }
166
+ },
167
+ "align-content": {
168
+ "property": "align-content",
169
+ "class": "content",
170
+ "responsive": true,
171
+ "description": "Alineación de líneas en el eje cruzado",
172
+ "values": {
173
+ "stretch": "stretch",
174
+ "start": "flex-start",
175
+ "end": "flex-end",
176
+ "center": "center",
177
+ "between": "space-between",
178
+ "around": "space-around",
179
+ "evenly": "space-evenly"
180
+ }
181
+ },
182
+ "align-items": {
183
+ "property": "align-items",
184
+ "class": "items",
185
+ "responsive": true,
186
+ "description": "Alineación en el eje cruzado",
187
+ "values": {
188
+ "stretch": "stretch",
189
+ "start": "flex-start",
190
+ "end": "flex-end",
191
+ "center": "center",
192
+ "baseline": "baseline"
193
+ }
194
+ },
195
+ "row-gap": {
196
+ "property": "row-gap",
197
+ "class": "gap-y",
198
+ "responsive": true,
199
+ "description": "Espacio entre filas",
200
+ "useSpacing": true
201
+ },
202
+ "column-gap": {
203
+ "property": "column-gap",
204
+ "class": "gap-x",
205
+ "responsive": true,
206
+ "description": "Espacio entre columnas",
207
+ "useSpacing": true
208
+ },
209
+ "gap": {
210
+ "property": "gap",
211
+ "class": "gap",
212
+ "responsive": true,
213
+ "description": "Espacio entre filas y columnas",
214
+ "useSpacing": true
215
+ }
216
+ },
217
+
218
+ "classes": {
219
+ "h2": {
220
+ "fontFamily": "arial, sans-serif",
221
+ "fontWeight": "900",
222
+ "letterSpacing": "0rem",
223
+ "textTransform": "none",
224
+ "mobile": {
225
+ "fontSize": "18px",
226
+ "lineHeight": "1.976"
227
+ },
228
+ "desktop": {
229
+ "fontSize": "24px",
230
+ "lineHeight": "1.2"
231
+ }
232
+ },
233
+ "title-l-b": {
234
+ "fontFamily": "arial, sans-serif",
235
+ "fontWeight": "700",
236
+ "letterSpacing": "0rem",
237
+ "textTransform": "uppercase",
238
+ "mobile": {
239
+ "fontSize": "14px",
240
+ "lineHeight": "1.2"
241
+ },
242
+ "desktop": {
243
+ "fontSize": "14px",
244
+ "lineHeight": "1.4"
245
+ }
246
+ },
247
+ "title-s": {
248
+ "fontFamily": "arial, sans-serif",
249
+ "fontWeight": "400",
250
+ "mobile": {
251
+ "fontSize": "12px",
252
+ "lineHeight": "1.4"
253
+ },
254
+ "desktop": {
255
+ "fontSize": "12px",
256
+ "lineHeight": "1.4"
257
+ }
258
+ },
259
+ "suisse-1": {
260
+ "fontFamily": "\"ms-serif\", serif",
261
+ "mobile": {
262
+ "fontSize": "16px",
263
+ "lineHeight": "1.5"
264
+ },
265
+ "desktop": {
266
+ "fontSize": "20px",
267
+ "lineHeight": "1.5"
268
+ }
269
+ },
270
+ "suisse-2": {
271
+ "fontFamily": "\"ms-serif\", serif",
272
+ "mobile": {
273
+ "fontSize": "13px",
274
+ "lineHeight": "1.1"
275
+ },
276
+ "desktop": {
277
+ "fontSize": "14px",
278
+ "lineHeight": "1.1"
279
+ }
280
+ },
281
+ "suisse-body": {
282
+ "fontFamily": "\"ms-serif\", serif",
283
+ "mobile": {
284
+ "fontSize": "10px",
285
+ "lineHeight": "1.1"
286
+ },
287
+ "desktop": {
288
+ "fontSize": "12px",
289
+ "lineHeight": "1.1"
290
+ }
291
+ },
292
+ "p-tag": {
293
+ "fontFamily": "arial, sans-serif",
294
+ "fontWeight": "100",
295
+ "mobile": {
296
+ "fontSize": "8px",
297
+ "lineHeight": "1"
298
+ },
299
+ "desktop": {
300
+ "fontSize": "8px",
301
+ "lineHeight": "1"
302
+ }
303
+ },
304
+ "semantic": {
305
+ "fontFamily": "arial, sans-serif",
306
+ "fontWeight": "100",
307
+ "mobile": {
308
+ "fontSize": "13px",
309
+ "lineHeight": "1"
310
+ },
311
+ "desktop": {
312
+ "fontSize": "13px",
313
+ "lineHeight": "1"
314
+ }
315
+ },
316
+ "title-l": {
317
+ "fontFamily": "arial, sans-serif",
318
+ "fontWeight": "100",
319
+ "mobile": {
320
+ "fontSize": "14px",
321
+ "lineHeight": "1.4"
322
+ },
323
+ "desktop": {
324
+ "fontSize": "14px",
325
+ "lineHeight": "1.4"
326
+ }
327
+ },
328
+ "title-m": {
329
+ "fontFamily": "arial, sans-serif",
330
+ "fontWeight": "100",
331
+ "mobile": {
332
+ "fontSize": "12px",
333
+ "lineHeight": "1.4"
334
+ },
335
+ "desktop": {
336
+ "fontSize": "12px",
337
+ "lineHeight": "1.4"
338
+ }
339
+ },
340
+ "text-m": {
341
+ "fontFamily": "arial, sans-serif",
342
+ "fontWeight": "100",
343
+ "mobile": {
344
+ "fontSize": "12px",
345
+ "lineHeight": "1.5"
346
+ },
347
+ "desktop": {
348
+ "fontSize": "13px",
349
+ "lineHeight": "1.5"
350
+ }
351
+ },
352
+ "text-l": {
353
+ "fontFamily": "arial, sans-serif",
354
+ "fontWeight": "100",
355
+ "mobile": {
356
+ "fontSize": "12px",
357
+ "lineHeight": "1.5"
358
+ },
359
+ "desktop": {
360
+ "fontSize": "12px",
361
+ "lineHeight": "1.5"
362
+ }
363
+ }
364
+ }
365
+ }
package/generator.js ADDED
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env node
2
+
3
+ // Orquestador principal - Genera CSS y HTML desde JSON
4
+
5
+ const path = require('path');
6
+ const { loadConfig } = require('./src/config');
7
+ const { generateCSS } = require('./src/parser');
8
+ const { generateHTML } = require('./src/guide');
9
+ const { writeFile } = require('./src/utils');
10
+
11
+ // Ejecución principal
12
+ if (require.main === module) {
13
+ try {
14
+ // Parsear argumentos de línea de comandos
15
+ const args = process.argv.slice(2);
16
+ const configPath = args.find(arg => arg.startsWith('--config='))?.split('=')[1] || path.join(__dirname, 'config.json');
17
+ const outputPath = args.find(arg => arg.startsWith('--output='))?.split('=')[1] || path.join(__dirname, 'dist', 'output.css');
18
+ const htmlPath = args.find(arg => arg.startsWith('--html='))?.split('=')[1] || path.join(__dirname, 'dist', 'index.html');
19
+
20
+ // Cargar configuración
21
+ const configData = loadConfig(configPath);
22
+
23
+ // Generar CSS
24
+ const cssContent = generateCSS(configData);
25
+ writeFile(outputPath, cssContent, 'CSS');
26
+
27
+ // Generar HTML (ajustar ruta del CSS en el HTML si está en carpeta diferente)
28
+ let htmlContent = generateHTML(configData);
29
+
30
+ // Si el HTML y CSS están en carpetas diferentes, ajustar la ruta del CSS
31
+ const outputDir = path.dirname(outputPath);
32
+ const htmlDir = path.dirname(htmlPath);
33
+
34
+ // Si el HTML y CSS están en carpetas diferentes, ajustar la ruta del CSS
35
+ // Si están en la misma carpeta (dist/), usar ruta relativa simple
36
+ if (outputDir !== htmlDir) {
37
+ // Calcular ruta relativa del HTML al CSS
38
+ const relativePath = path.relative(htmlDir, outputDir);
39
+ const cssFileName = path.basename(outputPath);
40
+ const cssRelativePath = path.join(relativePath, cssFileName).replace(/\\/g, '/');
41
+ // Reemplazar href con o sin query string
42
+ htmlContent = htmlContent.replace(/href="output\.css[^"]*"/, `href="${cssRelativePath}"`);
43
+ } else {
44
+ // Si están en la misma carpeta, usar solo el nombre del archivo
45
+ htmlContent = htmlContent.replace(/href="output\.css[^"]*"/, `href="output.css"`);
46
+ }
47
+
48
+ writeFile(htmlPath, htmlContent, 'HTML');
49
+
50
+ console.log('\n🎉 Generación completada exitosamente!');
51
+ } catch (error) {
52
+ console.error('❌ Error:', error.message);
53
+ process.exit(1);
54
+ }
55
+ }
56
+
57
+ // Exportar funciones
58
+ module.exports = { generateCSS, generateHTML };
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "holygrail5",
3
+ "version": "1.0.2",
4
+ "description": "Framework CSS generator con Node.js - Genera CSS optimizado con variables CSS desde un archivo JSON de configuración",
5
+ "main": "generator.js",
6
+ "bin": {
7
+ "holygrail5": "./generator.js"
8
+ },
9
+ "scripts": {
10
+ "generate": "node generator.js",
11
+ "start": "node generator.js && NODE_NO_WARNINGS=1 npx http-server dist -p 3000 -o index.html",
12
+ "dev": "node src/dev.js",
13
+ "watch": "node src/watch.js",
14
+ "serve": "NODE_NO_WARNINGS=1 npx http-server dist -p 3000 -o index.html",
15
+ "test": "node tests/run-all.js",
16
+ "prepublishOnly": "npm run generate",
17
+ "vars:list": "node src/cli-variables.js list",
18
+ "vars:report": "node src/cli-variables.js report",
19
+ "vars:remove": "node src/cli-variables.js remove",
20
+ "vars:remove-all-unused": "node src/cli-variables.js remove-all-unused",
21
+ "vars:show-all": "node src/cli-variables.js show-all"
22
+ },
23
+ "keywords": [
24
+ "css",
25
+ "framework",
26
+ "generator",
27
+ "css-variables",
28
+ "responsive",
29
+ "typography",
30
+ "css-framework",
31
+ "design-tokens"
32
+ ],
33
+ "author": "HolyGrail CSS",
34
+ "license": "MIT",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/holygrailcss/holygrail5.git"
38
+ },
39
+ "files": [
40
+ "generator.js",
41
+ "config.json",
42
+ "README.md",
43
+ "src/**/*"
44
+ ],
45
+ "engines": {
46
+ "node": ">=12.0.0"
47
+ }
48
+ }
@@ -0,0 +1,147 @@
1
+ #!/usr/bin/env node
2
+
3
+ // CLI para gestionar variables CSS
4
+ // Permite listar variables no usadas y eliminar variables del historial
5
+
6
+ const {
7
+ listUnusedVariables,
8
+ showVariablesReport,
9
+ getAllHistoricalVariables,
10
+ removeVariableFromHistory,
11
+ removeVariablesFromHistory,
12
+ loadHistoricalVariables
13
+ } = require('./variables-manager');
14
+
15
+ const path = require('path');
16
+
17
+ // Función para mostrar ayuda
18
+ function showHelp() {
19
+ console.log(`
20
+ 📦 Gestor de Variables CSS
21
+
22
+ Uso:
23
+ node src/cli-variables.js <comando> [opciones]
24
+
25
+ Comandos:
26
+ list Lista todas las variables no usadas
27
+ report Muestra un reporte completo de variables
28
+ remove <variable> Elimina una variable específica del historial
29
+ remove-all-unused Elimina todas las variables no usadas del historial
30
+ show-all Muestra todas las variables históricas almacenadas
31
+
32
+ Opciones:
33
+ --css=<ruta> Ruta al archivo CSS (por defecto: dist/output.css)
34
+ --history=<ruta> Ruta al archivo de variables históricas (por defecto: .data/.historical-variables.json)
35
+
36
+ Ejemplos:
37
+ node src/cli-variables.js list
38
+ node src/cli-variables.js report
39
+ node src/cli-variables.js remove --hg-typo-font-size-18
40
+ node src/cli-variables.js remove-all-unused
41
+ node src/cli-variables.js show-all
42
+ `);
43
+ }
44
+
45
+ // Función principal
46
+ function main() {
47
+ const args = process.argv.slice(2);
48
+
49
+ if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
50
+ showHelp();
51
+ return;
52
+ }
53
+
54
+ const command = args[0];
55
+ const cssPath = args.find(arg => arg.startsWith('--css='))?.split('=')[1] || null;
56
+ const historyPath = args.find(arg => arg.startsWith('--history='))?.split('=')[1] || null;
57
+
58
+ try {
59
+ switch (command) {
60
+ case 'list':
61
+ {
62
+ const unused = listUnusedVariables(cssPath, historyPath);
63
+ if (unused.length === 0) {
64
+ console.log('\n✅ No hay variables no usadas. Todas las variables están en uso.\n');
65
+ } else {
66
+ console.log(`\n⚠️ Variables no usadas (${unused.length}):\n`);
67
+ unused.forEach((varName, index) => {
68
+ console.log(` ${index + 1}. ${varName}`);
69
+ });
70
+ console.log('\n💡 Usa "remove-all-unused" para eliminarlas del historial\n');
71
+ }
72
+ }
73
+ break;
74
+
75
+ case 'report':
76
+ showVariablesReport(cssPath, historyPath);
77
+ break;
78
+
79
+ case 'remove':
80
+ {
81
+ const varName = args[1];
82
+ if (!varName) {
83
+ console.error('❌ Error: Debes especificar el nombre de la variable a eliminar');
84
+ console.log(' Ejemplo: node src/cli-variables.js remove --hg-typo-font-size-18');
85
+ process.exit(1);
86
+ }
87
+
88
+ const removed = removeVariableFromHistory(varName, historyPath);
89
+ if (removed) {
90
+ console.log(`\n✅ Variable "${varName}" eliminada del historial\n`);
91
+ } else {
92
+ console.log(`\n⚠️ Variable "${varName}" no encontrada en el historial\n`);
93
+ }
94
+ }
95
+ break;
96
+
97
+ case 'remove-all-unused':
98
+ {
99
+ const unused = listUnusedVariables(cssPath, historyPath);
100
+ if (unused.length === 0) {
101
+ console.log('\n✅ No hay variables no usadas para eliminar\n');
102
+ } else {
103
+ console.log(`\n⚠️ Eliminando ${unused.length} variables no usadas del historial...\n`);
104
+ const removedCount = removeVariablesFromHistory(unused, historyPath);
105
+ console.log(`✅ ${removedCount} variables eliminadas del historial\n`);
106
+ console.log('💡 Ejecuta "node generator.js" para regenerar el CSS sin estas variables\n');
107
+ }
108
+ }
109
+ break;
110
+
111
+ case 'show-all':
112
+ {
113
+ const historicalVars = loadHistoricalVariables(historyPath);
114
+ const allVars = getAllHistoricalVariables(historicalVars);
115
+
116
+ if (allVars.length === 0) {
117
+ console.log('\n📚 No hay variables históricas almacenadas\n');
118
+ } else {
119
+ console.log(`\n📚 Variables históricas (${allVars.length}):\n`);
120
+ allVars.forEach((varData, index) => {
121
+ console.log(` ${index + 1}. ${varData.varName}`);
122
+ console.log(` Categoría: ${varData.category}`);
123
+ console.log(` Valor: ${varData.value}`);
124
+ console.log('');
125
+ });
126
+ }
127
+ }
128
+ break;
129
+
130
+ default:
131
+ console.error(`❌ Comando desconocido: ${command}`);
132
+ showHelp();
133
+ process.exit(1);
134
+ }
135
+ } catch (error) {
136
+ console.error('❌ Error:', error.message);
137
+ process.exit(1);
138
+ }
139
+ }
140
+
141
+ // Ejecutar si es el módulo principal
142
+ if (require.main === module) {
143
+ main();
144
+ }
145
+
146
+ module.exports = { main };
147
+
package/src/config.js ADDED
@@ -0,0 +1,62 @@
1
+ // Carga y validación de configuración
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ const BREAKPOINTS = ['mobile', 'desktop'];
7
+
8
+ function loadConfig(configPath = path.join(__dirname, '..', 'config.json')) {
9
+ try {
10
+ if (!fs.existsSync(configPath)) {
11
+ throw new Error(`Archivo de configuración no encontrado: ${configPath}`);
12
+ }
13
+
14
+ const configContent = fs.readFileSync(configPath, 'utf8');
15
+ const config = JSON.parse(configContent);
16
+
17
+ // Validar estructura básica
18
+ if (!config.classes || typeof config.classes !== 'object') {
19
+ throw new Error('La configuración debe tener un objeto "classes"');
20
+ }
21
+
22
+ if (!config.breakpoints || typeof config.breakpoints !== 'object') {
23
+ throw new Error('La configuración debe tener un objeto "breakpoints"');
24
+ }
25
+
26
+ if (!config.breakpoints.mobile || !config.breakpoints.desktop) {
27
+ throw new Error('Los breakpoints deben tener propiedades "mobile" y "desktop"');
28
+ }
29
+
30
+ // Validar clases
31
+ Object.entries(config.classes).forEach(([className, cls]) => {
32
+ if (!cls || typeof cls !== 'object') {
33
+ throw new Error(`La clase "${className}" debe ser un objeto`);
34
+ }
35
+
36
+ // Validar que tenga al menos un breakpoint
37
+ if (!cls.mobile && !cls.desktop) {
38
+ throw new Error(`La clase "${className}" debe tener al menos un breakpoint (mobile o desktop)`);
39
+ }
40
+
41
+ // Validar propiedades de breakpoints
42
+ BREAKPOINTS.forEach(bp => {
43
+ if (cls[bp] && (!cls[bp].fontSize && !cls[bp].lineHeight)) {
44
+ console.warn(`Advertencia: La clase "${className}" tiene breakpoint "${bp}" sin fontSize ni lineHeight`);
45
+ }
46
+ });
47
+ });
48
+
49
+ return config;
50
+ } catch (error) {
51
+ if (error instanceof SyntaxError) {
52
+ throw new Error(`Error al parsear JSON: ${error.message}`);
53
+ }
54
+ throw error;
55
+ }
56
+ }
57
+
58
+ module.exports = {
59
+ loadConfig,
60
+ BREAKPOINTS
61
+ };
62
+