/** * Script to get information on which selectors use the brand color. * This is needed to provide the accent color feature - the feature will create CSS rules * to overwrite the color of these selectors. */ const css = require('css'); const fs = require('fs-extra'); const path = require('path'); const theme = require('@meetfranz/theme'); // Colors that should be replaced with the accent color const accentColors = [ theme.DEFAULT_ACCENT_COLOR.toLowerCase(), '#7367f0', '#5e50ee', ]; const cssFile = path.join(__dirname, '..', '..', 'build', 'styles', 'main.css'); const outputFile = path.join(__dirname, '..', 'assets', 'themeInfo.json'); // Parse and extract the rules from a CSS stylesheet file async function getRulesFromCssFile(file) { const cssSrc = (await fs.readFile(file)).toString(); const cssTree = css.parse(cssSrc); return cssTree.stylesheet?.rules; } /** * Get all selectors from a list of parsed CSS rules that set any property to one of the specified * values. * * This function will output an object in this format: * { * 'property-name': [ array of selectors ] * } * * e.g. * { * 'background-color': [ * '.background', * '.input-dark' * ] * } * * @param {Array} rules Rules as outputted by the `css` module * @param {Array} values Array of values that should be searched for */ function getSelectorsDeclaringValues(rules, values) { const output = {}; for (const rule of rules) { if (rule.declarations) { for (const declaration of rule.declarations) { if ( declaration.type === 'declaration' && values.includes(declaration.value.toLowerCase()) ) { if (!output[declaration.property]) { output[declaration.property] = []; } // eslint-disable-next-line unicorn/prefer-spread output[declaration.property] = output[declaration.property].concat( rule.selectors, ); } } } } return output; } async function generateThemeInfo() { if (!(await fs.pathExists(cssFile))) { console.log('Please make sure to build the project first.'); return; } // Read and parse css bundle const rules = await getRulesFromCssFile(cssFile); console.log(`Found ${rules?.length} rules`); // Get rules specifying the brand colors const brandRules = getSelectorsDeclaringValues(rules, accentColors); console.log( `Found ${Object.keys(brandRules).join( ', ', )} properties that set color to brand color`, ); // Join array of declarations into a single string for (const rule of Object.keys(brandRules)) { brandRules[rule] = brandRules[rule].join(', '); } // Write object with theme info to file fs.writeFile(outputFile, JSON.stringify(brandRules)); } generateThemeInfo();