edit anywhere | load ckeditor | Cell 9 | Search

This code modifies CSS stylesheets by adding a prefix to selectors, effectively renaming elements within the stylesheet for purposes like theming or component isolation.

Run example

npm run import -- "scope css"

scope css

var css = require('css');

function prefixRule(r, str, prefix, bodyId) {
    if(typeof r.rules !== 'undefined') {
        r.rules.forEach(r2 => prefixRule(r2, str, prefix, bodyId))
    }
    if(typeof r.selectors === 'undefined') {
        return;
    }
    r.selectors.forEach((s, i) => {
        if(s.includes(bodyId)) {
            r.selectors[i] = s.replace('#' + bodyId, prefix);
        } else if(s.includes('body') && !s.includes('#body')) {
            r.selectors[i] = s.replace(/\s*body\s*/ig, prefix);
        } else {
            r.selectors[i] = prefix + ' ' + s;
        }
    });
}

function prefixCssRules(str, prefix, bodyId) {
    try {
        const ast = css.parse(str);
        // TODO: add a check for media queries
        ast.stylesheet.rules.forEach(r => prefixRule(r, str, prefix, bodyId))
        return css.stringify(ast);
    } catch (e) {
        console.log(e)
        return str
    }
    
}


// TODO: convert media queries to togglable javascript classes for good emulation in a golden layout tab

module.exports = prefixCssRules;

What the code could have been:

const css = require('css');

/**
 * Recursively prefixes CSS selectors with the given prefix.
 * 
 * @param {Object} rule - The CSS rule to prefix.
 * @param {string} str - The original CSS string.
 * @param {string} prefix - The prefix to apply.
 * @param {string} bodyId - The ID of the body element.
 */
function prefixRule(rule, str, prefix, bodyId) {
    if (rule.rules) {
        rule.rules.forEach(r => prefixRule(r, str, prefix, bodyId));
    }
    
    if (!rule.selectors) return;

    rule.selectors.forEach((selector, index) => {
        if (selector.includes(`#${bodyId}`)) {
            rule.selectors[index] = selector.replace(`#${bodyId}`, prefix);
        } else if (selector.includes('body') &&!selector.includes('#body')) {
            rule.selectors[index] = selector.replace(/\s*body\s*/gi, prefix);
        } else {
            rule.selectors[index] = `${prefix} ${selector}`;
        }
    });
}

/**
 * Prefixes CSS rules in the given string with the specified prefix.
 * 
 * @param {string} str - The CSS string to prefix.
 * @param {string} prefix - The prefix to apply.
 * @param {string} bodyId - The ID of the body element.
 * @returns {string} The prefixed CSS string.
 */
function prefixCssRules(str, prefix, bodyId) {
    try {
        const ast = css.parse(str);
        
        // Prefix rules in media queries
        ast.stylesheet.rules.forEach(rule => prefixRule(rule, str, prefix, bodyId));
        
        return css.stringify(ast);
    } catch (error) {
        console.error(error);
        return str;
    }
}

module.exports = prefixCssRules;

This code defines a function prefixCssRules that modifies CSS rules by adding a prefix to selectors, effectively renaming elements within the stylesheet.

Here's a breakdown:

  1. Dependencies:

  2. prefixRule Function:

  3. prefixCssRules Function:

  4. Module Export:

Overall Purpose:

This code provides a way to dynamically modify CSS stylesheets by adding a prefix to selectors, likely for purposes like theming, component isolation, or code generation. It allows for selective renaming of elements based on specific IDs or the presence of "body" in selectors.