diff options
author | derchris | 2019-02-02 15:35:30 +0100 |
---|---|---|
committer | derchris | 2019-02-02 15:35:30 +0100 |
commit | 7ad9f272a482802da2d43fe83841adbe9bcd8cb4 (patch) | |
tree | 75b43a2a8c3ab3dbdcb0694d135f4729c90b8af7 /lib/less.php/Visitor/toCSS.php | |
parent | eb6601b2520d48a0be91634fada0389faadde31d (diff) |
update less.php to PHP 7.x compatible fork
Diffstat (limited to 'lib/less.php/Visitor/toCSS.php')
-rw-r--r-- | lib/less.php/Visitor/toCSS.php | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/lib/less.php/Visitor/toCSS.php b/lib/less.php/Visitor/toCSS.php new file mode 100644 index 0000000..8aaca96 --- /dev/null +++ b/lib/less.php/Visitor/toCSS.php @@ -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); + } +} + |