]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blobdiff - vendor/oyejorge/less.php/lib/Less/Visitor/toCSS.php
MediaWiki 1.30.2
[autoinstallsdev/mediawiki.git] / vendor / oyejorge / less.php / lib / Less / Visitor / toCSS.php
diff --git a/vendor/oyejorge/less.php/lib/Less/Visitor/toCSS.php b/vendor/oyejorge/less.php/lib/Less/Visitor/toCSS.php
new file mode 100644 (file)
index 0000000..8aaca96
--- /dev/null
@@ -0,0 +1,292 @@
+<?php
+
+/**
+ * toCSS Visitor
+ *
+ * @package Less
+ * @subpackage visitor
+ */
+class Less_Visitor_toCSS extends Less_VisitorReplacing{
+
+       private $charset;
+
+       public function __construct(){
+               parent::__construct();
+       }
+
+       /**
+        * @param Less_Tree_Ruleset $root
+        */
+       public function run( $root ){
+               return $this->visitObj($root);
+       }
+
+       public function visitRule( $ruleNode ){
+               if( $ruleNode->variable ){
+                       return array();
+               }
+               return $ruleNode;
+       }
+
+       public function visitMixinDefinition($mixinNode){
+               // mixin definitions do not get eval'd - this means they keep state
+               // so we have to clear that state here so it isn't used if toCSS is called twice
+               $mixinNode->frames = array();
+               return array();
+       }
+
+       public function visitExtend(){
+               return array();
+       }
+
+       public function visitComment( $commentNode ){
+               if( $commentNode->isSilent() ){
+                       return array();
+               }
+               return $commentNode;
+       }
+
+       public function visitMedia( $mediaNode, &$visitDeeper ){
+               $mediaNode->accept($this);
+               $visitDeeper = false;
+
+               if( !$mediaNode->rules ){
+                       return array();
+               }
+               return $mediaNode;
+       }
+
+       public function visitDirective( $directiveNode ){
+               if( isset($directiveNode->currentFileInfo['reference']) && (!property_exists($directiveNode,'isReferenced') || !$directiveNode->isReferenced) ){
+                       return array();
+               }
+               if( $directiveNode->name === '@charset' ){
+                       // Only output the debug info together with subsequent @charset definitions
+                       // a comment (or @media statement) before the actual @charset directive would
+                       // be considered illegal css as it has to be on the first line
+                       if( isset($this->charset) && $this->charset ){
+
+                               //if( $directiveNode->debugInfo ){
+                               //      $comment = new Less_Tree_Comment('/* ' . str_replace("\n",'',$directiveNode->toCSS())." */\n");
+                               //      $comment->debugInfo = $directiveNode->debugInfo;
+                               //      return $this->visit($comment);
+                               //}
+
+
+                               return array();
+                       }
+                       $this->charset = true;
+               }
+               return $directiveNode;
+       }
+
+       public function checkPropertiesInRoot( $rulesetNode ){
+
+               if( !$rulesetNode->firstRoot ){
+                       return;
+               }
+
+               foreach($rulesetNode->rules as $ruleNode){
+                       if( $ruleNode instanceof Less_Tree_Rule && !$ruleNode->variable ){
+                               $msg = "properties must be inside selector blocks, they cannot be in the root. Index ".$ruleNode->index.($ruleNode->currentFileInfo ? (' Filename: '.$ruleNode->currentFileInfo['filename']) : null);
+                               throw new Less_Exception_Compiler($msg);
+                       }
+               }
+       }
+
+
+       public function visitRuleset( $rulesetNode, &$visitDeeper ){
+
+               $visitDeeper = false;
+
+               $this->checkPropertiesInRoot( $rulesetNode );
+
+               if( $rulesetNode->root ){
+                       return $this->visitRulesetRoot( $rulesetNode );
+               }
+
+               $rulesets = array();
+               $rulesetNode->paths = $this->visitRulesetPaths($rulesetNode);
+
+
+               // Compile rules and rulesets
+               $nodeRuleCnt = $rulesetNode->rules?count($rulesetNode->rules):0;
+               for( $i = 0; $i < $nodeRuleCnt; ){
+                       $rule = $rulesetNode->rules[$i];
+
+                       if( property_exists($rule,'rules') ){
+                               // visit because we are moving them out from being a child
+                               $rulesets[] = $this->visitObj($rule);
+                               array_splice($rulesetNode->rules,$i,1);
+                               $nodeRuleCnt--;
+                               continue;
+                       }
+                       $i++;
+               }
+
+
+               // accept the visitor to remove rules and refactor itself
+               // then we can decide now whether we want it or not
+               if( $nodeRuleCnt > 0 ){
+                       $rulesetNode->accept($this);
+
+                       if( $rulesetNode->rules ){
+
+                               if( count($rulesetNode->rules) >  1 ){
+                                       $this->_mergeRules( $rulesetNode->rules );
+                                       $this->_removeDuplicateRules( $rulesetNode->rules );
+                               }
+
+                               // now decide whether we keep the ruleset
+                               if( $rulesetNode->paths ){
+                                       //array_unshift($rulesets, $rulesetNode);
+                                       array_splice($rulesets,0,0,array($rulesetNode));
+                               }
+                       }
+
+               }
+
+
+               if( count($rulesets) === 1 ){
+                       return $rulesets[0];
+               }
+               return $rulesets;
+       }
+
+
+       /**
+        * Helper function for visitiRuleset
+        *
+        * return array|Less_Tree_Ruleset
+        */
+       private function visitRulesetRoot( $rulesetNode ){
+               $rulesetNode->accept( $this );
+               if( $rulesetNode->firstRoot || $rulesetNode->rules ){
+                       return $rulesetNode;
+               }
+               return array();
+       }
+
+
+       /**
+        * Helper function for visitRuleset()
+        *
+        * @return array
+        */
+       private function visitRulesetPaths($rulesetNode){
+
+               $paths = array();
+               foreach($rulesetNode->paths as $p){
+                       if( $p[0]->elements[0]->combinator === ' ' ){
+                               $p[0]->elements[0]->combinator = '';
+                       }
+
+                       foreach($p as $pi){
+                               if( $pi->getIsReferenced() && $pi->getIsOutput() ){
+                                       $paths[] = $p;
+                                       break;
+                               }
+                       }
+               }
+
+               return $paths;
+       }
+
+       protected function _removeDuplicateRules( &$rules ){
+               // remove duplicates
+               $ruleCache = array();
+               for( $i = count($rules)-1; $i >= 0 ; $i-- ){
+                       $rule = $rules[$i];
+                       if( $rule instanceof Less_Tree_Rule || $rule instanceof Less_Tree_NameValue ){
+
+                               if( !isset($ruleCache[$rule->name]) ){
+                                       $ruleCache[$rule->name] = $rule;
+                               }else{
+                                       $ruleList =& $ruleCache[$rule->name];
+
+                                       if( $ruleList instanceof Less_Tree_Rule || $ruleList instanceof Less_Tree_NameValue ){
+                                               $ruleList = $ruleCache[$rule->name] = array( $ruleCache[$rule->name]->toCSS() );
+                                       }
+
+                                       $ruleCSS = $rule->toCSS();
+                                       if( array_search($ruleCSS,$ruleList) !== false ){
+                                               array_splice($rules,$i,1);
+                                       }else{
+                                               $ruleList[] = $ruleCSS;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       protected function _mergeRules( &$rules ){
+               $groups = array();
+
+               //obj($rules);
+
+               $rules_len = count($rules);
+               for( $i = 0; $i < $rules_len; $i++ ){
+                       $rule = $rules[$i];
+
+                       if( ($rule instanceof Less_Tree_Rule) && $rule->merge ){
+
+                               $key = $rule->name;
+                               if( $rule->important ){
+                                       $key .= ',!';
+                               }
+
+                               if( !isset($groups[$key]) ){
+                                       $groups[$key] = array();
+                               }else{
+                                       array_splice($rules, $i--, 1);
+                                       $rules_len--;
+                               }
+
+                               $groups[$key][] = $rule;
+                       }
+               }
+
+
+               foreach($groups as $parts){
+
+                       if( count($parts) > 1 ){
+                               $rule = $parts[0];
+                               $spacedGroups = array();
+                               $lastSpacedGroup = array();
+                               $parts_mapped = array();
+                               foreach($parts as $p){
+                                       if( $p->merge === '+' ){
+                                               if( $lastSpacedGroup ){
+                                                       $spacedGroups[] = self::toExpression($lastSpacedGroup);
+                                               }
+                                               $lastSpacedGroup = array();
+                                       }
+                                       $lastSpacedGroup[] = $p;
+                               }
+
+                               $spacedGroups[] = self::toExpression($lastSpacedGroup);
+                               $rule->value = self::toValue($spacedGroups);
+                       }
+               }
+
+       }
+
+       public static function toExpression($values){
+               $mapped = array();
+               foreach($values as $p){
+                       $mapped[] = $p->value;
+               }
+               return new Less_Tree_Expression( $mapped );
+       }
+
+       public static function toValue($values){
+               //return new Less_Tree_Value($values); ??
+
+               $mapped = array();
+               foreach($values as $p){
+                       $mapped[] = $p;
+               }
+               return new Less_Tree_Value($mapped);
+       }
+}
+