2016-07-12 34 views
0

Hallo Ich habe mit PostCSS experimentiert und kämpfe ein wenig mit dem Schreiben eines Plugins, das eine neue Regel anfügt, wenn es bestimmte CSS-Eigenschaften findet.PostCSS: Wie kann eine neue Regel basierend auf der Deklaration in der aktuellen Regel bedingt hinzugefügt werden?

Was ich versuche zu erreichen ...

CSS Start:

.selector { 
    color: red; 
    not-yet-standard-property-a: 10px; 
    not-yet-standard-property-b: 20px; 
} 

Nach PostCSS Plugin:

.selector { 
    color: red; 
    not-yet-standard-property-a: 10px; 
    not-yet-standard-property-b: 20px; 
} 

.ie .selector { 
    standard-property-a: 10px; 
    standard-property-b: 20px; 
} 

Es ist einfach für mich eine neue Regel hinzuzufügen, wenn ich einen sehe von diesen not-yet-standard-property-* ...

return function (css) { 
    css.walkRules(function (rule) { 
     rule.walkDecls('not-yet-standard-property-a', function (decl) { 
      css.insertAfter(rule, '.ie ' + rule.selector + '{ standard-property-a: '+ decl.value +' }'); 
     }); 
     rule.walkDecls('not-yet-standard-property-b', function (decl) { 
      css.insertAfter(rule, '.ie ' + rule.selector + '{ standard-property-b: '+ decl.value +' }'); 
     }); 
     rule.walkDecls('not-yet-standard-property-c', function (decl) { 
      css.insertAfter(rule, '.ie ' + rule.selector + '{ standard-property-c: '+ decl.value +' }'); 
     }); 
    }); 
} 

Aber der Ausgang ist nicht ideal ...

.selector { 
    color: red; 
    not-yet-standard-property-a: 10px; 
    not-yet-standard-property-b: 20px; 
    not-yet-standard-property-c: 53px; 
} 
.ie .selector { 
    standard-property-c: 53px; 
} 
.ie .selector { 
    standard-property-b: 20px; 
} 
.ie .selector { 
    standard-property-a: 10px; 
} 

Im Idealfall würde die neue Regel nur einmal hinzugefügt werden, nachdem es über die gesamte Regel ging ist aber PostCSS scheint nicht conditionals innerhalb der walkRules Funktion zu ermöglichen, also bin ich Ich bin mir nicht sicher, wie ich verhindern kann, dass es für jede Regel, die es sieht, eine neue Regel erstellt.

Ich habe zu einer Demo des obigen Codes verlinkt. Irgendwelche Vorschläge für bessere Architektur würden sehr geschätzt werden, wie ich schon sagte, ich bin ziemlich neu dazu. Vielen Dank!

Demo

bearbeiten: Gelöst. Vielen Dank an Andrey Sitnik! Ich habe seine Antwort als richtig markiert, da die Konzepte darin das waren, was ich brauchte. Für diejenigen, für eine vollständige Lösung dieses Problems suchen sehen Sie den folgenden Code (und Demo!):

function isNotYetStandardProp (propName) { 
    if (propName.indexOf('not-yet-standard-property-') > -1) { 
     return true; 
    } 
    else { 
     return false; 
    } 
} 

function transformPropName (propName) { 
    return propName.replace("not-yet-", ""); 
} 

var skipNext = false; 
var convertedProps = []; 
var newRule; 
var newNode; 

return function (css) { 

    css.walkRules(function(rule) { 
     // The skipNext flag is used to prevent walkRules from walking onto any 
     // newly created rules and recursively creating new rules based on the 
     // newly added rule. 
     if (!skipNext) { 
      // Reset to remove values from last loop 
      convertedProps = []; 
      newRule = null; 
      newNode = null; 

      // Search through nodes of current rule and build up array 
      // containing each property that needs to change. 
      rule.nodes.filter(function (node) { 
       if ((node.type === 'decl') && isNotYetStandardProp(node.prop)) { 
        newNode = node.clone(); 
        newNode.prop = transformPropName(node.prop); 
        convertedProps.push(newNode); 
       } 
      }); 

      // If there were properties to convert in this rule create a new 
      // rule to put them in. 
      if (convertedProps.length > 0) { 
       newRule = rule.cloneAfter({ selector: '.ie ' + rule.selector }); 
       newRule.removeAll().append(convertedProps); 
       skipNext = true; 
      } 
     } 
     else { 
      // We only want to skipNext once. 
      skipNext = false; 
     } 
    }) 

} 

Demo of solution

+0

Sie sollten immer 'node.source' einstellen, wenn Sie einen Knoten manuell erstellen (ohne die' clone() 'Methode zu benutzen). Ohne 'node.source' wird die Quellenzuordnung abgebrochen. –

Antwort

1

Sie brauchen kein walkDecls innerhalb walkRules, arbeiten nur mit rule.nodes:

css.walkRules(rule => { 
    const nonStandard = rule.nodes.filter(node => { 
     return if node.type === 'decl' && checkPropName(node.prop); 
    }); 
    if (nonStandard.length > 0) { 
     const clone = rule.cloneAfter({ selector: '.ie ' + rule.selector }); 
     clone.append(nonStandard); 
    } 
})