All files / packages/design-system-2/scripts/plugins postcss-add-scope.js

100% Statements 29/29
95.23% Branches 20/21
100% Functions 8/8
100% Lines 28/28

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 671x     1x 16x 16x     1x 14x       1x 14x           15x   1x 14x       14x 14x 1x     13x   14x 2x     12x 16x 2x     14x 14x 1x     1x       13x 1x     12x             1x      
const conditionalGroupRules = new Set(['media', 'supports', 'document', 'html']);
 
// check if the node is already scoped
const alreadyScoped = (selector, scope) => {
  let outermostScope = selector.split(' ', 1)[0];
  return outermostScope === scope;
};
 
const isValidScope = (scope) => {
  return !scope?.includes(',');
};
 
// check if a rule should be scoped or skipped.
const isRuleScopable = (rule) => {
  return rule.parent.type === 'root'
    ? true
    : rule.parent.type === 'atrule' && conditionalGroupRules.has(rule.parent.name);
};
 
// root level pseudo-class selectors must not be scoped.
const isRootLevelPseudoClass = (selector) => /^:(\w|-)+$/.test(selector.trim());
 
const plugin = (opts = {}) => {
  return {
    postcssPlugin: 'postcss-add-scope',
    Once(root, { result }) {
      // default scope set to .slds-scope
      let scope = opts.scope || '.slds-scope';
      if (!isValidScope(scope)) {
        throw root.error('invalid scope', { plugin: 'postcss-add-scope' });
      }
 
      root.walkRules((rule) => {
        // skip scoping of special rules (certain At-rules, nested, etc')
        if (!isRuleScopable(rule)) {
          return rule;
        }
 
        rule.selectors = rule.selectors.map((selector) => {
          if (alreadyScoped(selector, scope) || isRootLevelPseudoClass(selector)) {
            return selector;
          }
 
          const dirRegex = /^\[dir=["']\w+["']\]/;
          if (dirRegex.test(selector)) {
            const [dirPart, restOfSelector] = selector.match(dirRegex)
              ? [selector.match(dirRegex)[0], selector.replace(dirRegex, '').trim()]
              : [null, selector];
            return `${dirPart} ${scope} ${restOfSelector}`;
          }
 
          // special case for a top level '&' selector, resolves to scope
          if (selector.includes('&')) {
            return selector.replaceAll('&', scope);
          }
 
          return `${scope} ${selector}`;
        });
      });
    },
  };
};
 
plugin.postcss = true;
 
export default plugin;