Adaptando Style Dictionary a la nueva especificación
Vemos como podemos escribir nuestros JSONs con el futuro estándar sin renunciar a herramientas como Style Dictionary
Hace algunas semanas hablábamos de cómo se estaba intentando crear un estándar de design tokens, pero que lamentablemente herramientas como Style Dictionary no soportaban esta especificación aún por encontrarse en un estado de definición.
Si bien es cierto que hay que tener cuidado cuando adaptamos herramientas a especificaciones que aún están en una fase de borrador, puesto que pueden venir cambios en el futuro que vuelvan obsoletas las adaptaciones.
Problemas de incompatibilidad
En este artículo comentábamos que el principal problema de incompatibilidad de la nueva especificación con Style Dictionary era que este último usaba una jerarquía propia para categorizar y organizar los tokens. Esta nomenclatura se denomina CTI, y Style Dictionary, a priori, no puede transformar tokens que no usen esta nomenclatura.
Además, existe otro problema que impacta directamente en cómo la herramienta interpreta y lee el archivo JSON de tokens antes de transformarlo:
Style Dictionary espera encontrar una propiedad ‘value’ con el valor de un token. En la nueva especificación, nos encontramos con que esta propiedad se llama ‘$value’.
Style Dictionary usa una propiedad llamada ‘comment’ para generar comentarios en algunos formatos. Sin embargo, en la nueva especificación, se usa la propiedad ‘$description’.
Estos cambios sutiles hacen que ni siquiera podamos interpretar los tokens dentro de Style Dictionary, y ni hablar de transformarlos.
Hay algunas personas que consideran contraproducente el uso del símbolo $ para definir propiedades en un JSON, pero parece que este es el camino por el que se está optando en la especificación.
Traduciendo el fichero JSON de tokens
La mejor forma de poder usar la futura especificación en nuestros JSONs y aún así poder utilizar Style Dictionary para transformar nuestros tokens es aplicar nosotros mismos una conversión previa a Style Dictionary para adaptarlo a un formato que este pueda entender.
La forma más intuitiva de hacer esto sería:
Abrir el fichero .json.
Buscar todas las ocurrencias de $
value
y $comment
.Reemplazarlas por
value
ydescription
, respectivamente.
Evidentemente, no tiene sentido hacer esto a mano, puesto que podemos tener muchos ficheros de gran tamaño y no sería eficiente mantenerlos.
Para ello, vamos a montar un pequeño programa rápidamente para adaptar nuestros ficheros, usando Node.js.
Teniendo Node.js instalado en nuestro sistema (versión 18+), podemos ir a una carpeta en nuestra terminal y ejecutar:
npm init -y
Esto genera un nuevo proyecto NPM en la carpeta donde nos encontremos.
La idea es hacer una utilidad de consola rápidamente para poder ejecutarla de la siguiente manera:
node tokens-file-transforms.js /path/to/json/file
Y que nos genere un fichero llamado output.json
en el sitio donde estemos con el resultado.
Ahora vamos a crear un fichero nuevo llamado tokens-file-transform.js
con el siguiente contenido:
const process = require('process');
const fs = require('fs').promises;
async function main () {
const filePath = process.argv[2];
let contents = await fs.readFile(filePath, { encoding: 'utf8' });
contents = contents.replace(/"\$value"/g, '"value"');
contents = contents.replace(/"\$description"/g, '"comment"');
await fs.writeFile('./output.json', contents);
}
main().catch(console.error);
Quitando imports y algunos detalles del entorno que estamos usando, nuestro programa es esto:
const filePath = process.argv[2];
let contents = await fs.readFile(filePath, { encoding: 'utf8' });
contents = contents.replace(/"\$value"/g, '"value"');
contents = contents.replace(/"\$description"/g, '"comment"');
await fs.writeFile('./output.json', contents);
Parece muy loco, pero en realidad estamos haciendo algo sencillo.
const filePath = process.argv[2];
Esto obtiene el path al fichero que le pasamos al ejecutar el programa de la lista de argumentos usando el módulo process. Esta lista tiene muchas cosas; la primera es la ruta del ejecutable de node, el segundo es el programa (nuestro tokens-file-transform.js
) y el tercero es el path al fichero de tokens que le pasamos al ejecutarlo. Este último es el que nos interesa. Las listas empiezan en 0, por lo que el tercer elemento se encuentra en la posición ‘2’.
let contents = await fs.readFile(filePath, { encoding: 'utf8' });
Esto lee el fichero como una cadena de texto y lo guarda en la variable contents
.
contents = contents.replace(/"\$value"/g, '"value"');
contents = contents.replace(/"\$description"/g, '"comment"');
Esto aplica los reemplazamientos con algunas expresiones regulares sencillas.
await fs.writeFile('./output.json', contents);
Finalmente, esto escribe el nuevo contenido en un fichero llamado output.json
.
Si ahora ejecutamos el programa con un fichero así:
{
"color": {
"$description": "this is a color desc",
"$value": "#fffff"
},
"size": {
"$description": "this is a size desc",
"$value": "2px"
}
}
node tokens-file-transforms.js /my-tokens-file.json
Obtendremos:
{
"color": {
"description": "this is a color desc",
"value": "#fffff"
},
"size": {
"description": "this is a size desc",
"value": "2px"
}
}
¡Y ya tendremos nuestros JSONs adaptados para que puedan ser interpretados por Style Dictionary!
Si tienes dudas sobre el código, déjanos un comentario debajo :)
Conclusión
Aunque la nueva especificación todavía no es estándar, podemos empezar a utilizarla en nuestros desarrollos implementando pequeños programas que adapten los ficheros JSON que siguen la nueva nomenclatura a la antigua.
El día que la especificación se convierta en un estándar y herramientas como Style Dictionary la implementen de forma nativa, solo tendremos que eliminar nuestras herramientas de traducción de la ecuación.
En futuras entregas, seguiremos adaptando Style Dictionary para poder definir un pipeline completo en el que generemos nuestros tokens siguiendo la especificación de design tokens y los transformemos en código que los navegadores puedan entender.