@hiscovega/grisso 1.0.5 → 1.0.6

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Grisso
2
2
 
3
- > Librería de utility CSS de Griddo — similar a Tailwind CSS pero con valores basados en CSS custom properties (design tokens).
3
+ > Librería de utility CSS de Griddo con valores basados en CSS custom properties (design tokens).
4
4
 
5
5
  ## Instalación
6
6
 
@@ -10,24 +10,9 @@ npm install @hiscovega/grisso
10
10
 
11
11
  ## Uso
12
12
 
13
- ### Opción A: CSS directo
14
-
15
- Importa el CSS pre-compilado directamente. Útil para desarrollo.
16
-
17
- ```css
18
- /* En tu CSS global */
19
- @import "@hiscovega/grisso";
20
- ```
21
-
22
- O en HTML:
23
-
24
- ```html
25
- <link rel="stylesheet" href="node_modules/@hiscovega/grisso/dist/grisso.css" />
26
- ```
27
-
28
- ### Opción B: CLI
13
+ ### CLI
29
14
 
30
- Genera CSS desde la terminal. Ideal para scripts de build y CI/CD.
15
+ Genera CSS desde la terminal. Forma recomendada de usar Grisso, ideal para scripts de build y CI/CD.
31
16
 
32
17
  ```bash
33
18
  # CSS completo a stdout
@@ -42,6 +27,9 @@ npx grisso build --config grisso.config.mjs --output dist/grisso.css
42
27
  # Tree-shaking (solo clases usadas)
43
28
  npx grisso build --content "src/**/*.tsx" --content "src/**/*.css" --output dist/grisso.css
44
29
 
30
+ # Proteger clases del tree-shaking
31
+ npx grisso build --content "src/**/*.tsx" --safelist "^p-" --safelist "^m-" --output dist/grisso.css
32
+
45
33
  # Sin minificar (útil para depuración)
46
34
  npx grisso build --no-minify --output dist/grisso.css
47
35
 
@@ -51,17 +39,61 @@ npx grisso build | pbcopy
51
39
 
52
40
  **Flags de `grisso build`:**
53
41
 
54
- | Flag | Descripción |
55
- |---|---|
56
- | `--config <ruta>` | Ruta a `grisso.config.mjs` |
57
- | `--content <glob>` | Globs para tree-shaking (repetible) |
58
- | `--output <ruta>` | Archivo de salida (sin `--output` → stdout) |
59
- | `--no-minify` | Deshabilitar minificación |
60
- | `--help, -h` | Ayuda del comando |
42
+ | Flag | Descripción |
43
+ | -------------------- | ------------------------------------------- |
44
+ | `--config <ruta>` | Ruta a `grisso.config.mjs` |
45
+ | `--content <glob>` | Globs para tree-shaking (repetible) |
46
+ | `--safelist <regex>` | Patrones de clases a preservar (repetible) |
47
+ | `--output <ruta>` | Archivo de salida (sin `--output` → stdout) |
48
+ | `--no-minify` | Deshabilitar minificación |
49
+ | `--help, -h` | Ayuda del comando |
61
50
 
62
51
  Sin `--output`, el CSS va a stdout y los mensajes de estado a stderr, siguiendo la convención Unix.
63
52
 
64
- ### Opción C: API programática
53
+ #### `grisso tokens`
54
+
55
+ Genera un scaffold con todas las CSS custom properties (design tokens) que necesitas definir. Extrae dinámicamente los tokens de la config resuelta.
56
+
57
+ ```bash
58
+ # Scaffold CSS a stdout
59
+ npx grisso tokens
60
+
61
+ # Escribir a archivo
62
+ npx grisso tokens --output tokens.css
63
+
64
+ # Con config personalizada (refleja extends/overrides)
65
+ npx grisso tokens --config grisso.config.mjs --output tokens.css
66
+
67
+ # Config resuelta como JSON
68
+ npx grisso tokens --format json
69
+ ```
70
+
71
+ **Flags de `grisso tokens`:**
72
+
73
+ | Flag | Descripción |
74
+ | ----------------- | ------------------------------------------------- |
75
+ | `--config <ruta>` | Ruta a `grisso.config.mjs` |
76
+ | `--format <fmt>` | Formato de salida: `css` (default) o `json` |
77
+ | `--output <ruta>` | Archivo de salida (sin `--output` → stdout) |
78
+ | `--help, -h` | Ayuda del comando |
79
+
80
+ El scaffold CSS genera un `:root { }` con todas las properties vacías, agrupadas por sección, listo para rellenar:
81
+
82
+ ```css
83
+ :root {
84
+ /* ─── Spacing ─── */
85
+ --spc-4xs: ;
86
+ --spc-3xs: ;
87
+ /* ... */
88
+
89
+ /* ─── Colors: marca ─── */
90
+ --brand-1: ;
91
+ --brand-2: ;
92
+ /* ... */
93
+ }
94
+ ```
95
+
96
+ ### API programática
65
97
 
66
98
  Usa `buildCSS()` directamente desde Node.js. Genera, purga y optimiza CSS — ideal para scripts de build, herramientas custom o integración con cualquier bundler.
67
99
 
@@ -74,11 +106,12 @@ const css = await buildCSS();
74
106
 
75
107
  **Opciones de `buildCSS()`:**
76
108
 
77
- | Opción | Tipo | Default | Descripción |
78
- |---|---|---|---|
79
- | `config` | `string` | — | Ruta a `grisso.config.mjs` personalizado |
80
- | `content` | `string[]` | — | Globs de archivos a escanear para tree-shaking |
81
- | `minify` | `boolean` | `true` | Minificar el CSS de salida |
109
+ | Opción | Tipo | Default | Descripción |
110
+ | ---------- | ---------------------- | ------- | ---------------------------------------------------------------- |
111
+ | `config` | `string` | — | Ruta a `grisso.config.mjs` personalizado |
112
+ | `content` | `string[]` | — | Globs de archivos a escanear para tree-shaking |
113
+ | `safelist` | `(string \| RegExp)[]` | — | Patrones de clases a preservar (se mergea con `config.safelist`) |
114
+ | `minify` | `boolean` | `true` | Minificar el CSS de salida |
82
115
 
83
116
  Sin `content`, se incluye todo el CSS. Con `content`, se eliminan las clases no usadas via PurgeCSS.
84
117
 
@@ -144,6 +177,30 @@ export default {
144
177
  };
145
178
  ```
146
179
 
180
+ #### `extractTokens()` — scaffold de tokens
181
+
182
+ Usa `extractTokens()` para generar programáticamente el scaffold de custom properties (o JSON) desde la config resuelta.
183
+
184
+ ```js
185
+ import { extractTokens } from "@hiscovega/grisso/tokens";
186
+
187
+ // Scaffold CSS con todas las custom properties
188
+ const css = await extractTokens();
189
+
190
+ // JSON con los token maps resueltos
191
+ const json = await extractTokens({
192
+ format: "json",
193
+ config: "./grisso.config.mjs",
194
+ });
195
+ ```
196
+
197
+ **Opciones de `extractTokens()`:**
198
+
199
+ | Opción | Tipo | Default | Descripción |
200
+ | -------- | ---------------- | ------- | ----------------------------------------- |
201
+ | `config` | `string` | — | Ruta a `grisso.config.mjs` personalizado |
202
+ | `format` | `"css" \| "json"` | `"css"` | Formato de salida |
203
+
147
204
  **Servidor de desarrollo** — generar CSS on-the-fly:
148
205
 
149
206
  ```js
@@ -161,7 +218,7 @@ app.get("/grisso.css", async (req, res) => {
161
218
 
162
219
  ## Configuración personalizada
163
220
 
164
- Crea un `grisso.config.mjs` en la raíz de tu proyecto para extender o reemplazar los tokens por defecto. Sigue el patrón de Tailwind v3:
221
+ Crea un `grisso.config.mjs` en la raíz de tu proyecto para extender o reemplazar los tokens por defecto.
165
222
 
166
223
  ```js
167
224
  // grisso.config.mjs
@@ -173,7 +230,7 @@ export default {
173
230
  lg: "24px",
174
231
  },
175
232
 
176
- // `extend` MERGEA con los defaults
233
+ // `extend` MERGEA con los defaults (arrays se concatenan)
177
234
  extend: {
178
235
  foregroundColors: {
179
236
  5: "var(--text-5)",
@@ -181,17 +238,28 @@ export default {
181
238
  shadows: {
182
239
  "2xl": "var(--box-shadow-2xl)",
183
240
  },
241
+ // Se concatena con el default []
242
+ safelist: [/^p-/],
184
243
  },
185
244
  };
186
245
  ```
187
246
 
247
+ La `safelist` controla qué clases se protegen del tree-shaking. Por defecto está vacía. En top-level reemplaza, en `extend` se concatena. Acepta `RegExp` y `string`.
248
+
188
249
  Si no se pasa `config` a `buildCSS()`, busca automáticamente `grisso.config.mjs` en el directorio de trabajo. Si no existe, usa los defaults.
189
250
 
190
251
  Los defaults se pueden consultar importando `@hiscovega/grisso/config`.
191
252
 
192
253
  ## Design Tokens (CSS custom properties)
193
254
 
194
- Grisso usa CSS custom properties para todos los valores. Copia `tokens-example.css` y adapta los valores a tu design system:
255
+ Grisso usa CSS custom properties para todos los valores. Genera un scaffold con todas las properties que necesitas definir:
256
+
257
+ ```bash
258
+ # Genera scaffold dinámico desde tu config resuelta
259
+ npx grisso tokens --output src/tokens.css
260
+ ```
261
+
262
+ Alternativamente, copia el ejemplo estático:
195
263
 
196
264
  ```bash
197
265
  cp node_modules/@hiscovega/grisso/tokens-example.css src/tokens.css
@@ -236,17 +304,17 @@ Ejemplos: `flex`, `tablet-flex`, `p-md`, `desktop-mt-lg`, `text-center`, `w-1/2`
236
304
 
237
305
  ### Categorías
238
306
 
239
- | Categoría | Ejemplos |
240
- | -------------- | ----------------------------------------------------------------------------- |
307
+ | Categoría | Ejemplos |
308
+ | -------------- | ----------------------------------------------------------------------------------------------------- |
241
309
  | **Layout** | `flex`, `block`, `hidden`, `relative`, `absolute`, `overflow-hidden`, `inset-0`, `inset-x-sm`, `z-10` |
242
- | **Flex/Grid** | `flex-col`, `flex-wrap`, `items-center`, `justify-between`, `gap-md` |
243
- | **Spacing** | `p-sm`, `pt-lg`, `mx-auto`, `mt-xs`, `mb-md` |
244
- | **Sizing** | `w-full`, `h-full`, `w-1/2`, `w-2/3`, `h-1/4`, `max-w-full` |
245
- | **Tipografía** | `text-1`, `text-center`, `font-bold`, `font-light`, `leading-snug`, `tracking-tight` |
246
- | **Fondos** | `bg-1`, `bg-ui`, `bg-cover`, `bg-center` |
247
- | **Bordes** | `border-sm`, `border-1`, `border-t-sm`, `divide-x`, `outline-none` |
248
- | **Efectos** | `shadow-md`, `opacity-3`, `overlay-2` |
249
- | **Iconos** | `icon-1`, `icon-3` |
310
+ | **Flex/Grid** | `flex-col`, `flex-wrap`, `items-center`, `justify-between`, `gap-md` |
311
+ | **Spacing** | `p-sm`, `pt-lg`, `mx-auto`, `mt-xs`, `mb-md` |
312
+ | **Sizing** | `w-full`, `h-full`, `w-1/2`, `w-2/3`, `h-1/4`, `max-w-full` |
313
+ | **Tipografía** | `text-1`, `text-center`, `font-bold`, `font-light`, `leading-snug`, `tracking-tight` |
314
+ | **Fondos** | `bg-1`, `bg-ui`, `bg-cover`, `bg-center` |
315
+ | **Bordes** | `border-sm`, `border-1`, `border-t-sm`, `divide-x`, `outline-none` |
316
+ | **Efectos** | `shadow-md`, `opacity-3`, `overlay-2` |
317
+ | **Iconos** | `icon-1`, `icon-3` |
250
318
 
251
319
  ## Build
252
320
 
@@ -261,7 +329,7 @@ npm run playground # Build + tree-shake + abre playground/index.html
261
329
 
262
330
  ### CLI
263
331
 
264
- El CLI se usa internamente y está disponible para consumidores via `npx grisso build`. Ver [Opción B: CLI](#opción-b-cli) para detalles completos.
332
+ El CLI se usa internamente y está disponible para consumidores via `npx grisso build`. Ver [CLI](#cli) para detalles completos.
265
333
 
266
334
  Con `--content`, se usa PurgeCSS para eliminar clases no usadas (~154 KB → ~4 KB en el playground).
267
335
 
package/lib/build.d.ts CHANGED
@@ -5,6 +5,8 @@ export interface BuildOptions {
5
5
  content?: string[];
6
6
  /** Minificar el CSS de salida (default: true) */
7
7
  minify?: boolean;
8
+ /** Patrones de clases protegidas del tree-shaking (se mergean con config.safelist) */
9
+ safelist?: (string | RegExp)[];
8
10
  }
9
11
  /**
10
12
  * API principal de Grisso — genera, purga y optimiza CSS
package/lib/build.js CHANGED
@@ -1,6 +1,13 @@
1
1
  import { generateCSS } from "./index.js";
2
2
  import { optimizeCSS } from "./optimize.js";
3
3
  import { purgeCSS } from "./purge.js";
4
+ import { resolveConfig } from "./resolve-config.js";
5
+ /** Convierte strings a RegExp, deja RegExp intactos */
6
+ function toRegExpArray(list) {
7
+ if (!list)
8
+ return [];
9
+ return list.map((item) => (item instanceof RegExp ? item : new RegExp(item)));
10
+ }
4
11
  /**
5
12
  * API principal de Grisso — genera, purga y optimiza CSS
6
13
  * sin depender de PostCSS.
@@ -16,12 +23,18 @@ import { purgeCSS } from "./purge.js";
16
23
  * });
17
24
  */
18
25
  export async function buildCSS(options = {}) {
19
- const { config, content, minify = true } = options;
26
+ const { config, content, minify = true, safelist: optsSafelist } = options;
20
27
  // 1. Generar CSS raw desde los generators
21
28
  let css = await generateCSS(config);
22
29
  // 2. Tree-shaking si hay rutas de contenido
23
30
  if (content && content.length > 0) {
24
- css = await purgeCSS(css, { content });
31
+ // Resolver config para extraer safelist configurada
32
+ const resolved = await resolveConfig(config);
33
+ const mergedSafelist = [
34
+ ...toRegExpArray(resolved.safelist),
35
+ ...toRegExpArray(optsSafelist),
36
+ ];
37
+ css = await purgeCSS(css, { content, safelist: mergedSafelist });
25
38
  }
26
39
  // 3. Optimizar (nesting, autoprefixer, minificación)
27
40
  css = await optimizeCSS(css, { minify });
package/lib/cli.js CHANGED
@@ -19,6 +19,7 @@ Uso:
19
19
 
20
20
  Comandos:
21
21
  build Genera CSS de utilidades
22
+ tokens Genera scaffold de tokens (custom properties)
22
23
 
23
24
  Opciones globales:
24
25
  --help, -h Muestra esta ayuda
@@ -34,6 +35,7 @@ Uso:
34
35
  Opciones:
35
36
  --config <ruta> Ruta a grisso.config.mjs
36
37
  --content <glob> Globs para tree-shaking (repetible)
38
+ --safelist <regex> Patrones de clases a preservar (repetible)
37
39
  --output <ruta> Archivo de salida (sin --output → stdout)
38
40
  --no-minify Deshabilitar minificación
39
41
  --help, -h Muestra esta ayuda
@@ -42,6 +44,7 @@ Ejemplos:
42
44
  grisso build # CSS completo a stdout
43
45
  grisso build --output dist/grisso.css # Escribir a archivo
44
46
  grisso build --content "src/**/*.tsx" --output out.css # Tree-shaking
47
+ grisso build --safelist "^p-" --safelist "^m-" # Proteger clases
45
48
  grisso build --no-minify # Sin minificar`);
46
49
  }
47
50
  /** Comando build: genera CSS */
@@ -51,6 +54,7 @@ async function runBuild(argv) {
51
54
  options: {
52
55
  config: { type: "string" },
53
56
  content: { type: "string", multiple: true },
57
+ safelist: { type: "string", multiple: true },
54
58
  output: { type: "string" },
55
59
  minify: { type: "boolean", default: true },
56
60
  help: { type: "boolean", short: "h", default: false },
@@ -65,6 +69,7 @@ async function runBuild(argv) {
65
69
  // Import dinámico para que --help sea instantáneo
66
70
  const { buildCSS } = await import("./build.js");
67
71
  const content = values.content && values.content.length > 0 ? values.content : undefined;
72
+ const safelist = values.safelist && values.safelist.length > 0 ? values.safelist : undefined;
68
73
  if (values.output) {
69
74
  const label = content
70
75
  ? "Generando CSS con tree-shaking..."
@@ -75,6 +80,7 @@ async function runBuild(argv) {
75
80
  config: values.config,
76
81
  content,
77
82
  minify: values.minify,
83
+ safelist,
78
84
  });
79
85
  if (values.output) {
80
86
  const outputPath = path.resolve(values.output);
@@ -90,6 +96,63 @@ async function runBuild(argv) {
90
96
  process.stdout.write(css);
91
97
  }
92
98
  }
99
+ /** Texto de ayuda del comando tokens */
100
+ function printTokensHelp() {
101
+ console.log(`grisso tokens — Genera scaffold de tokens (custom properties)
102
+
103
+ Uso:
104
+ grisso tokens [opciones]
105
+
106
+ Opciones:
107
+ --config <ruta> Ruta a grisso.config.mjs
108
+ --format <fmt> Formato de salida: css (default) o json
109
+ --output <ruta> Archivo de salida (sin --output → stdout)
110
+ --help, -h Muestra esta ayuda
111
+
112
+ Ejemplos:
113
+ grisso tokens # Scaffold CSS a stdout
114
+ grisso tokens --output tokens.css # Escribir a archivo
115
+ grisso tokens --config grisso.config.mjs # Usa config custom
116
+ grisso tokens --format json # Config como JSON`);
117
+ }
118
+ /** Comando tokens: genera scaffold de tokens */
119
+ async function runTokens(argv) {
120
+ const { values } = parseArgs({
121
+ args: argv,
122
+ options: {
123
+ config: { type: "string" },
124
+ format: { type: "string" },
125
+ output: { type: "string" },
126
+ help: { type: "boolean", short: "h", default: false },
127
+ },
128
+ strict: true,
129
+ });
130
+ if (values.help) {
131
+ printTokensHelp();
132
+ return;
133
+ }
134
+ const format = values.format;
135
+ if (format && format !== "css" && format !== "json") {
136
+ console.error(`Formato no soportado: ${format} (usa "css" o "json")`);
137
+ process.exit(1);
138
+ }
139
+ // Import dinámico para que --help sea instantáneo
140
+ const { extractTokens } = await import("./tokens.js");
141
+ const output = await extractTokens({ config: values.config, format });
142
+ if (values.output) {
143
+ const outputPath = path.resolve(values.output);
144
+ const dir = path.dirname(outputPath);
145
+ if (!fs.existsSync(dir)) {
146
+ fs.mkdirSync(dir, { recursive: true });
147
+ }
148
+ fs.writeFileSync(outputPath, output);
149
+ const kb = (Buffer.byteLength(output, "utf8") / 1024).toFixed(1);
150
+ console.error(`Generado ${path.relative(process.cwd(), outputPath)} (${kb} KB)`);
151
+ }
152
+ else {
153
+ process.stdout.write(output);
154
+ }
155
+ }
93
156
  /** Punto de entrada */
94
157
  async function main() {
95
158
  const { values, positionals } = parseArgs({
@@ -116,9 +179,12 @@ async function main() {
116
179
  }
117
180
  switch (command) {
118
181
  case "build":
119
- // Pasar solo los args después de "build"
182
+ // Pasar solo los args después del comando
120
183
  await runBuild(process.argv.slice(3));
121
184
  break;
185
+ case "tokens":
186
+ await runTokens(process.argv.slice(3));
187
+ break;
122
188
  default:
123
189
  console.error(`Comando desconocido: ${command}`);
124
190
  printHelp();
package/lib/defaults.js CHANGED
@@ -4,6 +4,7 @@
4
4
  */
5
5
  const defaults = {
6
6
  columns: 12,
7
+ safelist: [],
7
8
  breakpoints: {
8
9
  tablet: "(min-width: 700px)",
9
10
  desktop: "(min-width: 1024px)",
package/lib/purge.js CHANGED
@@ -32,7 +32,7 @@ export async function purgeCSS(css, options) {
32
32
  },
33
33
  ],
34
34
  safelist: {
35
- greedy: [/^bg-/, ...(options.safelist ?? [])],
35
+ greedy: options.safelist ?? [],
36
36
  },
37
37
  });
38
38
  return result ? result.css : css;
@@ -1,7 +1,6 @@
1
1
  import type { GrissoConfig } from "./types.js";
2
2
  /**
3
3
  * Resuelve la configuración de Grisso.
4
- * Patrón Tailwind v3:
5
4
  * - Top-level keys reemplazan los defaults completamente
6
5
  * - `extend` mergea superficialmente con defaults
7
6
  */
@@ -3,7 +3,6 @@ import { pathToFileURL } from "node:url";
3
3
  import defaults from "./defaults.js";
4
4
  /**
5
5
  * Resuelve la configuración de Grisso.
6
- * Patrón Tailwind v3:
7
6
  * - Top-level keys reemplazan los defaults completamente
8
7
  * - `extend` mergea superficialmente con defaults
9
8
  */
@@ -36,7 +35,11 @@ export async function resolveConfig(configPath) {
36
35
  if (extend && typeof extend === "object" && !Array.isArray(extend)) {
37
36
  for (const [key, value] of Object.entries(extend)) {
38
37
  const current = config[key];
39
- if (key in config &&
38
+ if (key in config && Array.isArray(current) && Array.isArray(value)) {
39
+ // Arrays se concatenan (e.g. safelist)
40
+ config[key] = [...current, ...value];
41
+ }
42
+ else if (key in config &&
40
43
  typeof current === "object" &&
41
44
  current !== null &&
42
45
  !Array.isArray(current)) {
@@ -0,0 +1,14 @@
1
+ export interface TokensOptions {
2
+ /** Ruta a grisso.config.mjs del consumidor */
3
+ config?: string;
4
+ /** Formato de salida: CSS scaffold o JSON (default: "css") */
5
+ format?: "css" | "json";
6
+ }
7
+ /**
8
+ * Extrae tokens de la config resuelta y genera un scaffold CSS o JSON.
9
+ *
10
+ * @example
11
+ * const css = await extractTokens();
12
+ * const json = await extractTokens({ format: "json" });
13
+ */
14
+ export declare function extractTokens(options?: TokensOptions): Promise<string>;
package/lib/tokens.js ADDED
@@ -0,0 +1,132 @@
1
+ import { resolveConfig } from "./resolve-config.js";
2
+ /** Orden fijo de secciones — matchea defaults.ts y tokens-example.css */
3
+ const TOKEN_MAP_KEYS = [
4
+ "spacing",
5
+ "brandColors",
6
+ "foregroundColors",
7
+ "iconColors",
8
+ "supportColors",
9
+ "backgroundColors",
10
+ "overlayColors",
11
+ "borderWidth",
12
+ "opacity",
13
+ "shadows",
14
+ "borderColors",
15
+ ];
16
+ /** Labels para los headers CSS de cada sección */
17
+ const SECTION_LABELS = {
18
+ spacing: "Spacing",
19
+ brandColors: "Colors: marca",
20
+ foregroundColors: "Colors: texto",
21
+ iconColors: "Colors: iconos",
22
+ supportColors: "Colors: soporte",
23
+ backgroundColors: "Colors: fondo",
24
+ overlayColors: "Colors: overlays",
25
+ borderWidth: "Border widths",
26
+ opacity: "Opacidad",
27
+ shadows: "Sombras",
28
+ borderColors: "Colors: bordes",
29
+ };
30
+ /** Keys que NO son token maps */
31
+ const NON_TOKEN_KEYS = new Set([
32
+ "columns",
33
+ "breakpoints",
34
+ "safelist",
35
+ "extend",
36
+ ]);
37
+ const VAR_RE = /var\(--([\w-]+)\)/g;
38
+ /** Extrae nombres de custom properties de un token map, deduplicados y en orden */
39
+ function extractVarNames(tokenMap) {
40
+ const seen = new Set();
41
+ const result = [];
42
+ for (const value of Object.values(tokenMap)) {
43
+ for (const match of value.matchAll(VAR_RE)) {
44
+ const name = match[1];
45
+ if (!seen.has(name)) {
46
+ seen.add(name);
47
+ result.push(name);
48
+ }
49
+ }
50
+ }
51
+ return result;
52
+ }
53
+ /** Genera scaffold CSS con todas las custom properties */
54
+ function formatCSS(config) {
55
+ const lines = [];
56
+ lines.push("/* @hiscovega/grisso — tokens scaffold", " Define estas variables en :root o en el scope que prefieras.", " Generado desde la config resuelta de Grisso.", "*/", "", ":root {");
57
+ let hasSections = false;
58
+ // Secciones conocidas en orden fijo
59
+ for (const key of TOKEN_MAP_KEYS) {
60
+ const map = config[key];
61
+ if (!map || typeof map !== "object")
62
+ continue;
63
+ const vars = extractVarNames(map);
64
+ if (vars.length === 0)
65
+ continue;
66
+ const label = SECTION_LABELS[key] || key;
67
+ if (hasSections)
68
+ lines.push("");
69
+ lines.push(`\t/* ─── ${label} ${"─".repeat(Math.max(1, 55 - label.length))} */`);
70
+ for (const name of vars) {
71
+ lines.push(`\t--${name}: ;`);
72
+ }
73
+ hasSections = true;
74
+ }
75
+ // Secciones custom del consumidor (keys desconocidas que sean objetos)
76
+ for (const [key, value] of Object.entries(config)) {
77
+ if (NON_TOKEN_KEYS.has(key))
78
+ continue;
79
+ if (TOKEN_MAP_KEYS.includes(key))
80
+ continue;
81
+ if (!value || typeof value !== "object" || Array.isArray(value))
82
+ continue;
83
+ const vars = extractVarNames(value);
84
+ if (vars.length === 0)
85
+ continue;
86
+ if (hasSections)
87
+ lines.push("");
88
+ lines.push(`\t/* ─── ${key} ${"─".repeat(Math.max(1, 55 - key.length))} */`);
89
+ for (const name of vars) {
90
+ lines.push(`\t--${name}: ;`);
91
+ }
92
+ hasSections = true;
93
+ }
94
+ lines.push("}", "");
95
+ return lines.join("\n");
96
+ }
97
+ /** Genera JSON con los token maps de la config resuelta */
98
+ function formatJSON(config) {
99
+ const result = {};
100
+ for (const key of TOKEN_MAP_KEYS) {
101
+ const map = config[key];
102
+ if (map && typeof map === "object") {
103
+ result[key] = map;
104
+ }
105
+ }
106
+ // Incluir token maps custom del consumidor
107
+ for (const [key, value] of Object.entries(config)) {
108
+ if (NON_TOKEN_KEYS.has(key))
109
+ continue;
110
+ if (TOKEN_MAP_KEYS.includes(key))
111
+ continue;
112
+ if (!value || typeof value !== "object" || Array.isArray(value))
113
+ continue;
114
+ result[key] = value;
115
+ }
116
+ return JSON.stringify(result, null, "\t");
117
+ }
118
+ /**
119
+ * Extrae tokens de la config resuelta y genera un scaffold CSS o JSON.
120
+ *
121
+ * @example
122
+ * const css = await extractTokens();
123
+ * const json = await extractTokens({ format: "json" });
124
+ */
125
+ export async function extractTokens(options = {}) {
126
+ const { config: configPath, format = "css" } = options;
127
+ const config = await resolveConfig(configPath);
128
+ if (format === "json") {
129
+ return formatJSON(config);
130
+ }
131
+ return formatCSS(config);
132
+ }
package/lib/types.d.ts CHANGED
@@ -19,6 +19,8 @@ export interface GrissoConfig {
19
19
  opacity: TokenMap;
20
20
  shadows: TokenMap;
21
21
  borderColors: TokenMap;
22
+ /** Patrones de clases protegidas del tree-shaking */
23
+ safelist: (string | RegExp)[];
22
24
  [key: string]: unknown;
23
25
  }
24
26
  /** Función parcial que genera CSS a partir de la config */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hiscovega/grisso",
3
3
  "description": "Griddo CSS utility class library",
4
- "version": "1.0.5",
4
+ "version": "1.0.6",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,
7
7
  "type": "module",
@@ -10,6 +10,7 @@
10
10
  "style": "./dist/grisso.css"
11
11
  },
12
12
  "./build": "./lib/build.js",
13
+ "./tokens": "./lib/tokens.js",
13
14
  "./config": "./lib/defaults.js",
14
15
  "./tokens-example.css": "./tokens-example.css"
15
16
  },