packages/heml-styles/src/plugins/postcss-element-expander/expanders.js
function expandElementRule (element, selectors = [], originalRule) {
  /** early return if we don't have any selectors */
  if (selectors.length === 0) return []

  let usedProps = []
  let expandedRules = []
  let defaultRules = []

  /** create the base rule */
  const baseRule = originalRule.clone()
  baseRule.selectors = selectors
  baseRule.selector = replaceElementTagMentions(element, baseRule.selector)

  /** create postcss rules for each element rule */
  for (const [ ruleSelector, ruleDecls ] of Object.entries(element.rules)) {
    const isRoot = element.pseudos.root === ruleSelector
    const isDefault = element.defaults.includes(ruleSelector)
    const expandedRule = baseRule.clone()

    /** gather all rules that get decls be default */
    if (isDefault) { defaultRules.push(expandedRule) }

    /** map all the selectors to target this rule selector */
    if (!isRoot) { expandedRule.selectors = expandedRule.selectors.map((selector) => `${selector} ${ruleSelector}`) }

    /** strip any non whitelisted props, run tranforms, gather used props */
    expandedRule.walkDecls((decl) => {
      const matchedRuleDecls = ruleDecls.filter(({ prop }) => prop.test(decl.prop))

      if (matchedRuleDecls.length === 0) { return decl.remove() }

      usedProps.push(decl.prop)
      matchedRuleDecls.forEach(({ transform }) => transform(decl, originalRule))
    })

    expandedRules.push(expandedRule)
  }

  baseRule.walkDecls((decl) => {
    if (!usedProps.includes(decl.prop)) {
      defaultRules.forEach((defaultRule) => defaultRule.prepend(decl.clone()))
    }
  })

  return expandedRules
}
function expandElementRule (element, selectors = [], originalRule) {
  /** early return if we don't have any selectors */
  if (selectors.length === 0) return []

  let usedProps = []
  let expandedRules = []
  let defaultRules = []

  /** create the base rule */
  const baseRule = originalRule.clone()
  baseRule.selectors = selectors
  baseRule.selector = replaceElementTagMentions(element, baseRule.selector)

  /** create postcss rules for each element rule */
  for (const [ ruleSelector, ruleDecls ] of Object.entries(element.rules)) {
    const isRoot = element.pseudos.root === ruleSelector
    const isDefault = element.defaults.includes(ruleSelector)
    const expandedRule = baseRule.clone()

    /** gather all rules that get decls be default */
    if (isDefault) { defaultRules.push(expandedRule) }

    /** map all the selectors to target this rule selector */
    if (!isRoot) { expandedRule.selectors = expandedRule.selectors.map((selector) => `${selector} ${ruleSelector}`) }

    /** strip any non whitelisted props, run tranforms, gather used props */
    expandedRule.walkDecls((decl) => {
      const matchedRuleDecls = ruleDecls.filter(({ prop }) => prop.test(decl.prop))

      if (matchedRuleDecls.length === 0) { return decl.remove() }

      usedProps.push(decl.prop)
      matchedRuleDecls.forEach(({ transform }) => transform(decl, originalRule))
    })

    expandedRules.push(expandedRule)
  }

  baseRule.walkDecls((decl) => {
    if (!usedProps.includes(decl.prop)) {
      defaultRules.forEach((defaultRule) => defaultRule.prepend(decl.clone()))
    }
  })

  return expandedRules
}
function expandElementRule ( element , selectors = [ ] , originalRule ) { /** early return if we don't have any selectors */ if ( selectors . length === 0 ) return [ ] let usedProps = [ ] let expandedRules = [ ] let defaultRules = [ ] /** create the base rule */ const baseRule = originalRule . clone ( ) baseRule . selectors = selectors baseRule . selector = replaceElementTagMentions ( element , baseRule . selector ) /** create postcss rules for each element rule */ for ( const [ ruleSelector , ruleDecls ] of Object . entries ( element . rules ) ) { const isRoot = element . pseudos . root === ruleSelector const isDefault = element . defaults . includes ( ruleSelector ) const expandedRule = baseRule . clone ( ) /** gather all rules that get decls be default */ if ( isDefault ) { defaultRules . push ( expandedRule ) } /** map all the selectors to target this rule selector */ if ( ! isRoot ) { expandedRule . selectors = expandedRule . selectors . map ( ( selector ) => ` ${ selector } ${ ruleSelector } ` ) } /** strip any non whitelisted props, run tranforms, gather used props */ expandedRule . walkDecls ( ( decl ) => { const matchedRuleDecls = ruleDecls . filter ( ( { prop } ) => prop . test ( decl . prop ) ) if ( matchedRuleDecls . length === 0 ) { return decl . remove ( ) } usedProps . push ( decl . prop ) matchedRuleDecls . forEach ( ( { transform } ) => transform ( decl , originalRule ) ) } ) expandedRules . push ( expandedRule ) } baseRule . walkDecls ( ( decl ) => { if ( ! usedProps . includes ( decl . prop ) ) { defaultRules . forEach ( ( defaultRule ) => defaultRule . prepend ( decl . clone ( ) ) ) } } ) return expandedRules }
expand the given rule to correctly the style the element
@param {Object}       element      element The element definition
@param {Array}        selectors    the matched selectors to for
@return {Array[Rule]}              an array of the expanded rules
expand the given rule to correctly the style the element