function insertAreas (css, isDisabled) {
  // parse grid-template declarations
  let gridTemplatesData = parseGridTemplatesData(css)

  // return undefined if no declarations found
  if (gridTemplatesData.length === 0) {
    return undefined
  }

  // we need to store the rules that we will insert later
  let rulesToInsert = {}

  css.walkDecls('grid-area', gridArea => {
    let gridAreaRule = gridArea.parent
    let hasPrefixedRow = gridAreaRule.first.prop === '-ms-grid-row'
    let gridAreaMedia = getParentMedia(gridAreaRule)

    if (isDisabled(gridArea)) {
      return undefined
    }

    let gridAreaRuleIndex =
      gridAreaMedia ? css.index(gridAreaMedia) : css.index(gridAreaRule)

    let value = gridArea.value
    // found the data that matches grid-area identifier
    let data = gridTemplatesData.filter(d => d.allAreas.includes(value))[0]

    if (!data) {
      return true
    }

    let lastArea = data.allAreas[data.allAreas.length - 1]
    let selectorBySpace = list.space(gridAreaRule.selector)
    let selectorByComma = list.comma(gridAreaRule.selector)
    let selectorIsComplex = (
      (selectorBySpace.length > 1) &&
      (selectorBySpace.length > selectorByComma.length)
    )

    // prevent doubling of prefixes
    if (hasPrefixedRow) {
      return false
    }

    // create the empty object with the key as the last area name
    // e.g if we have templates with "a b c" values, "c" will be the last area
    if (!rulesToInsert[lastArea]) {
      rulesToInsert[lastArea] = {}
    }

    let lastRuleIsSet = false

    // walk through every grid-template rule data
    for (let rule of data.rules) {
      let area = rule.areas[value]
      let hasDuplicateName = rule.duplicateAreaNames.includes(value)

      // if we can't find the area name, update lastRule and continue
      if (!area) {
        let lastRuleIndex = css.index(rulesToInsert[lastArea].lastRule)
        if (gridAreaRuleIndex > lastRuleIndex) {
          rulesToInsert[lastArea].lastRule = gridAreaMedia || gridAreaRule
        }
        continue
      }

      // for grid-templates inside media rule we need to create empty
      // array to push prefixed grid-area rules later
      if (rule.params && !rulesToInsert[lastArea][rule.params]) {
        rulesToInsert[lastArea][rule.params] = []
      }

      if ((!rule.hasDuplicates || !hasDuplicateName) && !rule.params) {
        // grid-template has no duplicates and not inside media rule

        getMSDecls(area, false, false).reverse()
          .forEach(i => gridAreaRule.prepend(
            Object.assign(i, {
              raws: {
                between: gridArea.raws.between
              }
            })
          ))

        rulesToInsert[lastArea].lastRule = gridAreaRule
        lastRuleIsSet = true
      } else if (rule.hasDuplicates && !rule.params && !selectorIsComplex) {
        // grid-template has duplicates and not inside media rule
        let cloned = gridAreaRule.clone()
        cloned.removeAll()

        getMSDecls(area, area.row.updateSpan, area.column.updateSpan).reverse()
          .forEach(i => cloned.prepend(
            Object.assign(i, {
              raws: {
                between: gridArea.raws.between
              }
            })
          ))

        cloned.selectors = (
          changeDuplicateAreaSelectors(cloned.selectors, rule.selectors)
        )

        if (rulesToInsert[lastArea].lastRule) {
          rulesToInsert[lastArea].lastRule.after(cloned)
        }
        rulesToInsert[lastArea].lastRule = cloned
        lastRuleIsSet = true
      } else if (
        rule.hasDuplicates &&
        !rule.params &&
        selectorIsComplex &&
        gridAreaRule.selector.includes(rule.selectors[0])
      ) {
        // grid-template has duplicates and not inside media rule
        // and the selector is complex
        gridAreaRule.walkDecls(/-ms-grid-(row|column)/, d => d.remove())
        getMSDecls(area, area.row.updateSpan, area.column.updateSpan).reverse()
          .forEach(i => gridAreaRule.prepend(
            Object.assign(i, {
              raws: {
                between: gridArea.raws.between
              }
            })
          ))
      } else if (rule.params) {
        // grid-template is inside media rule
        // if we're inside media rule, we need to store prefixed rules
        // inside rulesToInsert object to be able to preserve the order of media
        // rules and merge them easily
        let cloned = gridAreaRule.clone()
        cloned.removeAll()

        getMSDecls(area, area.row.updateSpan, area.column.updateSpan).reverse()
          .forEach(i => cloned.prepend(
            Object.assign(i, {
              raws: {
                between: gridArea.raws.between
              }
            })
          ))

        if (rule.hasDuplicates && hasDuplicateName) {
          cloned.selectors = (
            changeDuplicateAreaSelectors(cloned.selectors, rule.selectors)
          )
        }

        cloned.raws = rule.node.raws

        if (css.index(rule.node.parent) > gridAreaRuleIndex) {
          // append the prefixed rules right inside media rule
          // with grid-template
          rule.node.parent.append(cloned)
        } else {
          // store the rule to insert later
          rulesToInsert[lastArea][rule.params].push(cloned)
        }

        // set new rule as last rule ONLY if we didn't set lastRule for
        // this grid-area before
        if (!lastRuleIsSet) {
          rulesToInsert[lastArea].lastRule = gridAreaMedia || gridAreaRule
        }
      }
    }

    return undefined
  })

  // append stored rules inside the media rules
  Object.keys(rulesToInsert).forEach(area => {
    let data = rulesToInsert[area]
    let lastRule = data.lastRule
    Object.keys(data)
      .reverse()
      .filter(p => p !== 'lastRule')
      .forEach(params => {
        if (data[params].length > 0 && lastRule) {
          lastRule.after({ name: 'media', params })
          lastRule.next().append(data[params])
        }
      })
  })

  return undefined
}
function insertAreas (css, isDisabled) {
  // parse grid-template declarations
  let gridTemplatesData = parseGridTemplatesData(css)

  // return undefined if no declarations found
  if (gridTemplatesData.length === 0) {
    return undefined
  }

  // we need to store the rules that we will insert later
  let rulesToInsert = {}

  css.walkDecls('grid-area', gridArea => {
    let gridAreaRule = gridArea.parent
    let hasPrefixedRow = gridAreaRule.first.prop === '-ms-grid-row'
    let gridAreaMedia = getParentMedia(gridAreaRule)

    if (isDisabled(gridArea)) {
      return undefined
    }

    let gridAreaRuleIndex =
      gridAreaMedia ? css.index(gridAreaMedia) : css.index(gridAreaRule)

    let value = gridArea.value
    // found the data that matches grid-area identifier
    let data = gridTemplatesData.filter(d => d.allAreas.includes(value))[0]

    if (!data) {
      return true
    }

    let lastArea = data.allAreas[data.allAreas.length - 1]
    let selectorBySpace = list.space(gridAreaRule.selector)
    let selectorByComma = list.comma(gridAreaRule.selector)
    let selectorIsComplex = (
      (selectorBySpace.length > 1) &&
      (selectorBySpace.length > selectorByComma.length)
    )

    // prevent doubling of prefixes
    if (hasPrefixedRow) {
      return false
    }

    // create the empty object with the key as the last area name
    // e.g if we have templates with "a b c" values, "c" will be the last area
    if (!rulesToInsert[lastArea]) {
      rulesToInsert[lastArea] = {}
    }

    let lastRuleIsSet = false

    // walk through every grid-template rule data
    for (let rule of data.rules) {
      let area = rule.areas[value]
      let hasDuplicateName = rule.duplicateAreaNames.includes(value)

      // if we can't find the area name, update lastRule and continue
      if (!area) {
        let lastRuleIndex = css.index(rulesToInsert[lastArea].lastRule)
        if (gridAreaRuleIndex > lastRuleIndex) {
          rulesToInsert[lastArea].lastRule = gridAreaMedia || gridAreaRule
        }
        continue
      }

      // for grid-templates inside media rule we need to create empty
      // array to push prefixed grid-area rules later
      if (rule.params && !rulesToInsert[lastArea][rule.params]) {
        rulesToInsert[lastArea][rule.params] = []
      }

      if ((!rule.hasDuplicates || !hasDuplicateName) && !rule.params) {
        // grid-template has no duplicates and not inside media rule

        getMSDecls(area, false, false).reverse()
          .forEach(i => gridAreaRule.prepend(
            Object.assign(i, {
              raws: {
                between: gridArea.raws.between
              }
            })
          ))

        rulesToInsert[lastArea].lastRule = gridAreaRule
        lastRuleIsSet = true
      } else if (rule.hasDuplicates && !rule.params && !selectorIsComplex) {
        // grid-template has duplicates and not inside media rule
        let cloned = gridAreaRule.clone()
        cloned.removeAll()

        getMSDecls(area, area.row.updateSpan, area.column.updateSpan).reverse()
          .forEach(i => cloned.prepend(
            Object.assign(i, {
              raws: {
                between: gridArea.raws.between
              }
            })
          ))

        cloned.selectors = (
          changeDuplicateAreaSelectors(cloned.selectors, rule.selectors)
        )

        if (rulesToInsert[lastArea].lastRule) {
          rulesToInsert[lastArea].lastRule.after(cloned)
        }
        rulesToInsert[lastArea].lastRule = cloned
        lastRuleIsSet = true
      } else if (
        rule.hasDuplicates &&
        !rule.params &&
        selectorIsComplex &&
        gridAreaRule.selector.includes(rule.selectors[0])
      ) {
        // grid-template has duplicates and not inside media rule
        // and the selector is complex
        gridAreaRule.walkDecls(/-ms-grid-(row|column)/, d => d.remove())
        getMSDecls(area, area.row.updateSpan, area.column.updateSpan).reverse()
          .forEach(i => gridAreaRule.prepend(
            Object.assign(i, {
              raws: {
                between: gridArea.raws.between
              }
            })
          ))
      } else if (rule.params) {
        // grid-template is inside media rule
        // if we're inside media rule, we need to store prefixed rules
        // inside rulesToInsert object to be able to preserve the order of media
        // rules and merge them easily
        let cloned = gridAreaRule.clone()
        cloned.removeAll()

        getMSDecls(area, area.row.updateSpan, area.column.updateSpan).reverse()
          .forEach(i => cloned.prepend(
            Object.assign(i, {
              raws: {
                between: gridArea.raws.between
              }
            })
          ))

        if (rule.hasDuplicates && hasDuplicateName) {
          cloned.selectors = (
            changeDuplicateAreaSelectors(cloned.selectors, rule.selectors)
          )
        }

        cloned.raws = rule.node.raws

        if (css.index(rule.node.parent) > gridAreaRuleIndex) {
          // append the prefixed rules right inside media rule
          // with grid-template
          rule.node.parent.append(cloned)
        } else {
          // store the rule to insert later
          rulesToInsert[lastArea][rule.params].push(cloned)
        }

        // set new rule as last rule ONLY if we didn't set lastRule for
        // this grid-area before
        if (!lastRuleIsSet) {
          rulesToInsert[lastArea].lastRule = gridAreaMedia || gridAreaRule
        }
      }
    }

    return undefined
  })

  // append stored rules inside the media rules
  Object.keys(rulesToInsert).forEach(area => {
    let data = rulesToInsert[area]
    let lastRule = data.lastRule
    Object.keys(data)
      .reverse()
      .filter(p => p !== 'lastRule')
      .forEach(params => {
        if (data[params].length > 0 && lastRule) {
          lastRule.after({ name: 'media', params })
          lastRule.next().append(data[params])
        }
      })
  })

  return undefined
}
function insertAreas ( css , isDisabled ) { // parse grid-template declarations let gridTemplatesData = parseGridTemplatesData ( css ) // return undefined if no declarations found if ( gridTemplatesData . length === 0 ) { return undefined } // we need to store the rules that we will insert later let rulesToInsert = { } css . walkDecls ( 'grid-area' , gridArea => { let gridAreaRule = gridArea . parent let hasPrefixedRow = gridAreaRule . first . prop === '-ms-grid-row' let gridAreaMedia = getParentMedia ( gridAreaRule ) if ( isDisabled ( gridArea ) ) { return undefined } let gridAreaRuleIndex = gridAreaMedia ? css . index ( gridAreaMedia ) : css . index ( gridAreaRule ) let value = gridArea . value // found the data that matches grid-area identifier let data = gridTemplatesData . filter ( d => d . allAreas . includes ( value ) ) [ 0 ] if ( ! data ) { return true } let lastArea = data . allAreas [ data . allAreas . length - 1 ] let selectorBySpace = list . space ( gridAreaRule . selector ) let selectorByComma = list . comma ( gridAreaRule . selector ) let selectorIsComplex = ( ( selectorBySpace . length > 1 ) && ( selectorBySpace . length > selectorByComma . length ) ) // prevent doubling of prefixes if ( hasPrefixedRow ) { return false } // create the empty object with the key as the last area name // e.g if we have templates with "a b c" values, "c" will be the last area if ( ! rulesToInsert [ lastArea ] ) { rulesToInsert [ lastArea ] = { } } let lastRuleIsSet = false // walk through every grid-template rule data for ( let rule of data . rules ) { let area = rule . areas [ value ] let hasDuplicateName = rule . duplicateAreaNames . includes ( value ) // if we can't find the area name, update lastRule and continue if ( ! area ) { let lastRuleIndex = css . index ( rulesToInsert [ lastArea ] . lastRule ) if ( gridAreaRuleIndex > lastRuleIndex ) { rulesToInsert [ lastArea ] . lastRule = gridAreaMedia || gridAreaRule } continue } // for grid-templates inside media rule we need to create empty // array to push prefixed grid-area rules later if ( rule . params && ! rulesToInsert [ lastArea ] [ rule . params ] ) { rulesToInsert [ lastArea ] [ rule . params ] = [ ] } if ( ( ! rule . hasDuplicates || ! hasDuplicateName ) && ! rule . params ) { // grid-template has no duplicates and not inside media rule getMSDecls ( area , false , false ) . reverse ( ) . forEach ( i => gridAreaRule . prepend ( Object . assign ( i , { raws : { between : gridArea . raws . between } } ) ) ) rulesToInsert [ lastArea ] . lastRule = gridAreaRule lastRuleIsSet = true } else if ( rule . hasDuplicates && ! rule . params && ! selectorIsComplex ) { // grid-template has duplicates and not inside media rule let cloned = gridAreaRule . clone ( ) cloned . removeAll ( ) getMSDecls ( area , area . row . updateSpan , area . column . updateSpan ) . reverse ( ) . forEach ( i => cloned . prepend ( Object . assign ( i , { raws : { between : gridArea . raws . between } } ) ) ) cloned . selectors = ( changeDuplicateAreaSelectors ( cloned . selectors , rule . selectors ) ) if ( rulesToInsert [ lastArea ] . lastRule ) { rulesToInsert [ lastArea ] . lastRule . after ( cloned ) } rulesToInsert [ lastArea ] . lastRule = cloned lastRuleIsSet = true } else if ( rule . hasDuplicates && ! rule . params && selectorIsComplex && gridAreaRule . selector . includes ( rule . selectors [ 0 ] ) ) { // grid-template has duplicates and not inside media rule // and the selector is complex gridAreaRule . walkDecls ( / -ms-grid-(row|column) / , d => d . remove ( ) ) getMSDecls ( area , area . row . updateSpan , area . column . updateSpan ) . reverse ( ) . forEach ( i => gridAreaRule . prepend ( Object . assign ( i , { raws : { between : gridArea . raws . between } } ) ) ) } else if ( rule . params ) { // grid-template is inside media rule // if we're inside media rule, we need to store prefixed rules // inside rulesToInsert object to be able to preserve the order of media // rules and merge them easily let cloned = gridAreaRule . clone ( ) cloned . removeAll ( ) getMSDecls ( area , area . row . updateSpan , area . column . updateSpan ) . reverse ( ) . forEach ( i => cloned . prepend ( Object . assign ( i , { raws : { between : gridArea . raws . between } } ) ) ) if ( rule . hasDuplicates && hasDuplicateName ) { cloned . selectors = ( changeDuplicateAreaSelectors ( cloned . selectors , rule . selectors ) ) } cloned . raws = rule . node . raws if ( css . index ( rule . node . parent ) > gridAreaRuleIndex ) { // append the prefixed rules right inside media rule // with grid-template rule . node . parent . append ( cloned ) } else { // store the rule to insert later rulesToInsert [ lastArea ] [ rule . params ] . push ( cloned ) } // set new rule as last rule ONLY if we didn't set lastRule for // this grid-area before if ( ! lastRuleIsSet ) { rulesToInsert [ lastArea ] . lastRule = gridAreaMedia || gridAreaRule } } } return undefined } ) // append stored rules inside the media rules Object . keys ( rulesToInsert ) . forEach ( area => { let data = rulesToInsert [ area ] let lastRule = data . lastRule Object . keys ( data ) . reverse ( ) . filter ( p => p !== 'lastRule' ) . forEach ( params => { if ( data [ params ] . length > 0 && lastRule ) { lastRule . after ( { name : 'media' , params } ) lastRule . next ( ) . append ( data [ params ] ) } } ) } ) return undefined }
insert prefixed grid-area declarations
@param  {Root}  css css root
@param  {Function} isDisabled check if the rule is disabled
@return {void}
insert prefixed grid - area declarations
inserts areas in the grid - template