From 2ae8f94fc4e278b6951c4492a0780f7326e05428 Mon Sep 17 00:00:00 2001 From: Kshitij Sobti Date: Thu, 9 Nov 2023 18:18:37 +0530 Subject: [PATCH] feat: Better support for multiple themes This change adds support for two CLI options to the build-tokens command. The first, --all-themes makes the build-tokens command process all themes in the source directory as opposed to specifying all the names via --theme. Secondly, --base-theme allows you to have multiple themes derived from the same common base. If specified, you can have a derived theme that still loads tokens from the light theme. For example, you can have a site theme called 'theme-one' and set the base theme to light so it will reuse the core light theme tokens and layer on changes from 'theme-one'. --- lib/build-tokens.js | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/lib/build-tokens.js b/lib/build-tokens.js index b9916ddb3d..72ddb7e267 100755 --- a/lib/build-tokens.js +++ b/lib/build-tokens.js @@ -1,3 +1,4 @@ +const fs = require('fs'); const path = require('path'); const minimist = require('minimist'); const { StyleDictionary, colorTransform, createCustomCSSVariables } = require('../tokens/style-dictionary'); @@ -9,13 +10,17 @@ const { createIndexCssFile } = require('../tokens/utils'); * @param {string[]} commandArgs - Command line arguments for building tokens. * @param {string} [commandArgs.build-dir='./build/'] - The directory where the build output will be placed. * @param {string} [commandArgs.source] - The source directory containing JSON token files. + * @param {string} [commandArgs.base-theme] - The base theme to use from Paragon if named differently than the theme. * @param {boolean} [commandArgs.source-tokens-only=false] - Indicates whether to include only source tokens. * @param {string|string[]} [commandArgs.themes=['light']] - The themes (variants) for which to build tokens. + * @param {boolean} [commandArgs.all-themes] - Indicated whether to process all themes. */ async function buildTokensCommand(commandArgs) { const defaultParams = { - themes: ['light'], + themes: 'light', + 'base-theme': null, 'build-dir': './build/', + 'all-themes': false, }; const alias = { @@ -28,7 +33,20 @@ async function buildTokensCommand(commandArgs) { source: tokensSource, 'source-tokens-only': hasSourceTokensOnly, themes, - } = minimist(commandArgs, { alias, default: defaultParams, boolean: 'source-tokens-only' }); + 'base-theme': baseTheme, + 'all-themes': allThemes, + } = minimist(commandArgs, { alias, default: defaultParams, boolean: ['source-tokens-only', 'all-themes'] }); + + let themesToProcess = null; + + if (allThemes) { + themesToProcess = fs + .readdirSync(`${tokensSource}/themes/`, { withFileTypes: true }) + .filter(entry => entry.isDirectory()) + .map(entry => entry.name); + } else { + themesToProcess = themes.split(' '); + } const coreConfig = { include: [path.resolve(__dirname, '../tokens/src/core/**/*.json')], @@ -65,9 +83,9 @@ async function buildTokensCommand(commandArgs) { }, }; - const getStyleDictionaryConfig = (themeVariant) => ({ + const getStyleDictionaryConfig = (themeVariant, baseThemeVariant) => ({ ...coreConfig, - include: [...coreConfig.include, path.resolve(__dirname, `../tokens/src/themes/${themeVariant}/**/*.json`)], + include: [...coreConfig.include, path.resolve(__dirname, `../tokens/src/themes/${baseThemeVariant}/**/*.json`)], source: tokensSource ? [`${tokensSource}/themes/${themeVariant}/**/*.json`] : [], transform: { 'color/sass-color-functions': { @@ -109,8 +127,8 @@ async function buildTokensCommand(commandArgs) { StyleDictionary.extend(coreConfig).buildAllPlatforms(); createIndexCssFile({ buildDir, isTheme: false }); - themes.forEach((themeVariant) => { - const config = getStyleDictionaryConfig(themeVariant); + themesToProcess.forEach((themeVariant) => { + const config = getStyleDictionaryConfig(themeVariant, baseTheme || themeVariant); StyleDictionary.extend(config).buildAllPlatforms(); createIndexCssFile({ buildDir, isTheme: true, themeVariant }); });