File: /var/www/vhosts/uyarreklam.com.tr/httpdocs/Visitor.tar
extendFinder.php 0000644 00000005261 15155241154 0007703 0 ustar 00 <?php
/**
* Extend Finder Visitor
*
* @package Less
* @subpackage visitor
*/
class Less_Visitor_extendFinder extends Less_Visitor{
public $contexts = array();
public $allExtendsStack;
public $foundExtends;
public function __construct(){
$this->contexts = array();
$this->allExtendsStack = array(array());
parent::__construct();
}
/**
* @param Less_Tree_Ruleset $root
*/
public function run($root){
$root = $this->visitObj($root);
$root->allExtends =& $this->allExtendsStack[0];
return $root;
}
public function visitRule($ruleNode, &$visitDeeper ){
$visitDeeper = false;
}
public function visitMixinDefinition( $mixinDefinitionNode, &$visitDeeper ){
$visitDeeper = false;
}
public function visitRuleset($rulesetNode){
if( $rulesetNode->root ){
return;
}
$allSelectorsExtendList = array();
// get &:extend(.a); rules which apply to all selectors in this ruleset
if( $rulesetNode->rules ){
foreach($rulesetNode->rules as $rule){
if( $rule instanceof Less_Tree_Extend ){
$allSelectorsExtendList[] = $rule;
$rulesetNode->extendOnEveryPath = true;
}
}
}
// now find every selector and apply the extends that apply to all extends
// and the ones which apply to an individual extend
foreach($rulesetNode->paths as $selectorPath){
$selector = end($selectorPath); //$selectorPath[ count($selectorPath)-1];
$j = 0;
foreach($selector->extendList as $extend){
$this->allExtendsStackPush($rulesetNode, $selectorPath, $extend, $j);
}
foreach($allSelectorsExtendList as $extend){
$this->allExtendsStackPush($rulesetNode, $selectorPath, $extend, $j);
}
}
$this->contexts[] = $rulesetNode->selectors;
}
public function allExtendsStackPush($rulesetNode, $selectorPath, $extend, &$j){
$this->foundExtends = true;
$extend = clone $extend;
$extend->findSelfSelectors( $selectorPath );
$extend->ruleset = $rulesetNode;
if( $j === 0 ){
$extend->firstExtendOnThisSelectorPath = true;
}
$end_key = count($this->allExtendsStack)-1;
$this->allExtendsStack[$end_key][] = $extend;
$j++;
}
public function visitRulesetOut( $rulesetNode ){
if( !is_object($rulesetNode) || !$rulesetNode->root ){
array_pop($this->contexts);
}
}
public function visitMedia( $mediaNode ){
$mediaNode->allExtends = array();
$this->allExtendsStack[] =& $mediaNode->allExtends;
}
public function visitMediaOut(){
array_pop($this->allExtendsStack);
}
public function visitDirective( $directiveNode ){
$directiveNode->allExtends = array();
$this->allExtendsStack[] =& $directiveNode->allExtends;
}
public function visitDirectiveOut(){
array_pop($this->allExtendsStack);
}
}
import.php 0000644 00000006422 15155241154 0006576 0 ustar 00 <?php
/*
class Less_Visitor_import extends Less_VisitorReplacing{
public $_visitor;
public $_importer;
public $importCount;
function __construct( $evalEnv ){
$this->env = $evalEnv;
$this->importCount = 0;
parent::__construct();
}
function run( $root ){
$root = $this->visitObj($root);
$this->isFinished = true;
//if( $this->importCount === 0) {
// $this->_finish();
//}
}
function visitImport($importNode, &$visitDeeper ){
$importVisitor = $this;
$inlineCSS = $importNode->options['inline'];
if( !$importNode->css || $inlineCSS ){
$evaldImportNode = $importNode->compileForImport($this->env);
if( $evaldImportNode && (!$evaldImportNode->css || $inlineCSS) ){
$importNode = $evaldImportNode;
$this->importCount++;
$env = clone $this->env;
if( (isset($importNode->options['multiple']) && $importNode->options['multiple']) ){
$env->importMultiple = true;
}
//get path & uri
$path_and_uri = null;
if( is_callable(Less_Parser::$options['import_callback']) ){
$path_and_uri = call_user_func(Less_Parser::$options['import_callback'],$importNode);
}
if( !$path_and_uri ){
$path_and_uri = $importNode->PathAndUri();
}
if( $path_and_uri ){
list($full_path, $uri) = $path_and_uri;
}else{
$full_path = $uri = $importNode->getPath();
}
//import once
if( $importNode->skip( $full_path, $env) ){
return array();
}
if( $importNode->options['inline'] ){
//todo needs to reference css file not import
//$contents = new Less_Tree_Anonymous($importNode->root, 0, array('filename'=>$importNode->importedFilename), true );
Less_Parser::AddParsedFile($full_path);
$contents = new Less_Tree_Anonymous( file_get_contents($full_path), 0, array(), true );
if( $importNode->features ){
return new Less_Tree_Media( array($contents), $importNode->features->value );
}
return array( $contents );
}
// css ?
if( $importNode->css ){
$features = ( $importNode->features ? $importNode->features->compile($env) : null );
return new Less_Tree_Import( $importNode->compilePath( $env), $features, $importNode->options, $this->index);
}
return $importNode->ParseImport( $full_path, $uri, $env );
}
}
$visitDeeper = false;
return $importNode;
}
function visitRule( $ruleNode, &$visitDeeper ){
$visitDeeper = false;
return $ruleNode;
}
function visitDirective($directiveNode, $visitArgs){
array_unshift($this->env->frames,$directiveNode);
return $directiveNode;
}
function visitDirectiveOut($directiveNode) {
array_shift($this->env->frames);
}
function visitMixinDefinition($mixinDefinitionNode, $visitArgs) {
array_unshift($this->env->frames,$mixinDefinitionNode);
return $mixinDefinitionNode;
}
function visitMixinDefinitionOut($mixinDefinitionNode) {
array_shift($this->env->frames);
}
function visitRuleset($rulesetNode, $visitArgs) {
array_unshift($this->env->frames,$rulesetNode);
return $rulesetNode;
}
function visitRulesetOut($rulesetNode) {
array_shift($this->env->frames);
}
function visitMedia($mediaNode, $visitArgs) {
array_unshift($this->env->frames, $mediaNode->ruleset);
return $mediaNode;
}
function visitMediaOut($mediaNode) {
array_shift($this->env->frames);
}
}
*/
joinSelector.php 0000644 00000003076 15155241154 0007726 0 ustar 00 <?php
/**
* Join Selector Visitor
*
* @package Less
* @subpackage visitor
*/
class Less_Visitor_joinSelector extends Less_Visitor{
public $contexts = array( array() );
/**
* @param Less_Tree_Ruleset $root
*/
public function run( $root ){
return $this->visitObj($root);
}
public function visitRule( $ruleNode, &$visitDeeper ){
$visitDeeper = false;
}
public function visitMixinDefinition( $mixinDefinitionNode, &$visitDeeper ){
$visitDeeper = false;
}
public function visitRuleset( $rulesetNode ){
$paths = array();
if( !$rulesetNode->root ){
$selectors = array();
if( $rulesetNode->selectors && $rulesetNode->selectors ){
foreach($rulesetNode->selectors as $selector){
if( $selector->getIsOutput() ){
$selectors[] = $selector;
}
}
}
if( !$selectors ){
$rulesetNode->selectors = null;
$rulesetNode->rules = null;
}else{
$context = end($this->contexts); //$context = $this->contexts[ count($this->contexts) - 1];
$paths = $rulesetNode->joinSelectors( $context, $selectors);
}
$rulesetNode->paths = $paths;
}
$this->contexts[] = $paths; //different from less.js. Placed after joinSelectors() so that $this->contexts will get correct $paths
}
public function visitRulesetOut(){
array_pop($this->contexts);
}
public function visitMedia($mediaNode) {
$context = end($this->contexts); //$context = $this->contexts[ count($this->contexts) - 1];
if( !count($context) || (is_object($context[0]) && $context[0]->multiMedia) ){
$mediaNode->rules[0]->root = true;
}
}
}
processExtends.php 0000644 00000037172 15155241154 0010303 0 ustar 00 <?php
/**
* Process Extends Visitor
*
* @package Less
* @subpackage visitor
*/
class Less_Visitor_processExtends extends Less_Visitor{
public $allExtendsStack;
/**
* @param Less_Tree_Ruleset $root
*/
public function run( $root ){
$extendFinder = new Less_Visitor_extendFinder();
$extendFinder->run( $root );
if( !$extendFinder->foundExtends){
return $root;
}
$root->allExtends = $this->doExtendChaining( $root->allExtends, $root->allExtends);
$this->allExtendsStack = array();
$this->allExtendsStack[] = &$root->allExtends;
return $this->visitObj( $root );
}
private function doExtendChaining( $extendsList, $extendsListTarget, $iterationCount = 0){
//
// chaining is different from normal extension.. if we extend an extend then we are not just copying, altering and pasting
// the selector we would do normally, but we are also adding an extend with the same target selector
// this means this new extend can then go and alter other extends
//
// this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors
// this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already processed if
// we look at each selector at a time, as is done in visitRuleset
$extendsToAdd = array();
//loop through comparing every extend with every target extend.
// a target extend is the one on the ruleset we are looking at copy/edit/pasting in place
// e.g. .a:extend(.b) {} and .b:extend(.c) {} then the first extend extends the second one
// and the second is the target.
// the separation into two lists allows us to process a subset of chains with a bigger set, as is the
// case when processing media queries
for( $extendIndex = 0, $extendsList_len = count($extendsList); $extendIndex < $extendsList_len; $extendIndex++ ){
for( $targetExtendIndex = 0; $targetExtendIndex < count($extendsListTarget); $targetExtendIndex++ ){
$extend = $extendsList[$extendIndex];
$targetExtend = $extendsListTarget[$targetExtendIndex];
// Optimisation: Explicit reference, <https://github.com/wikimedia/less.php/pull/14>
if( \array_key_exists($targetExtend->object_id, $extend->parent_ids) ){
// ignore circular references
continue;
}
// find a match in the target extends self selector (the bit before :extend)
$selectorPath = array( $targetExtend->selfSelectors[0] );
$matches = $this->findMatch( $extend, $selectorPath);
if( $matches ){
// we found a match, so for each self selector..
foreach($extend->selfSelectors as $selfSelector ){
// process the extend as usual
$newSelector = $this->extendSelector( $matches, $selectorPath, $selfSelector);
// but now we create a new extend from it
$newExtend = new Less_Tree_Extend( $targetExtend->selector, $targetExtend->option, 0);
$newExtend->selfSelectors = $newSelector;
// add the extend onto the list of extends for that selector
end($newSelector)->extendList = array($newExtend);
//$newSelector[ count($newSelector)-1]->extendList = array($newExtend);
// record that we need to add it.
$extendsToAdd[] = $newExtend;
$newExtend->ruleset = $targetExtend->ruleset;
//remember its parents for circular references
$newExtend->parent_ids = array_merge($newExtend->parent_ids,$targetExtend->parent_ids,$extend->parent_ids);
// only process the selector once.. if we have :extend(.a,.b) then multiple
// extends will look at the same selector path, so when extending
// we know that any others will be duplicates in terms of what is added to the css
if( $targetExtend->firstExtendOnThisSelectorPath ){
$newExtend->firstExtendOnThisSelectorPath = true;
$targetExtend->ruleset->paths[] = $newSelector;
}
}
}
}
}
if( $extendsToAdd ){
// try to detect circular references to stop a stack overflow.
// may no longer be needed. $this->extendChainCount++;
if( $iterationCount > 100) {
try{
$selectorOne = $extendsToAdd[0]->selfSelectors[0]->toCSS();
$selectorTwo = $extendsToAdd[0]->selector->toCSS();
}catch(Exception $e){
$selectorOne = "{unable to calculate}";
$selectorTwo = "{unable to calculate}";
}
throw new Less_Exception_Parser("extend circular reference detected. One of the circular extends is currently:" . $selectorOne . ":extend(" . $selectorTwo . ")");
}
// now process the new extends on the existing rules so that we can handle a extending b extending c ectending d extending e...
$extendsToAdd = $this->doExtendChaining( $extendsToAdd, $extendsListTarget, $iterationCount+1);
}
return array_merge($extendsList, $extendsToAdd);
}
protected function visitRule( $ruleNode, &$visitDeeper ){
$visitDeeper = false;
}
protected function visitMixinDefinition( $mixinDefinitionNode, &$visitDeeper ){
$visitDeeper = false;
}
protected function visitSelector( $selectorNode, &$visitDeeper ){
$visitDeeper = false;
}
protected function visitRuleset($rulesetNode){
if( $rulesetNode->root ){
return;
}
$allExtends = end($this->allExtendsStack);
$paths_len = count($rulesetNode->paths);
// look at each selector path in the ruleset, find any extend matches and then copy, find and replace
foreach($allExtends as $allExtend){
for($pathIndex = 0; $pathIndex < $paths_len; $pathIndex++ ){
// extending extends happens initially, before the main pass
if( isset($rulesetNode->extendOnEveryPath) && $rulesetNode->extendOnEveryPath ){
continue;
}
$selectorPath = $rulesetNode->paths[$pathIndex];
if( end($selectorPath)->extendList ){
continue;
}
$this->ExtendMatch( $rulesetNode, $allExtend, $selectorPath);
}
}
}
private function ExtendMatch( $rulesetNode, $extend, $selectorPath ){
$matches = $this->findMatch($extend, $selectorPath);
if( $matches ){
foreach($extend->selfSelectors as $selfSelector ){
$rulesetNode->paths[] = $this->extendSelector($matches, $selectorPath, $selfSelector);
}
}
}
private function findMatch($extend, $haystackSelectorPath ){
if( !$this->HasMatches($extend, $haystackSelectorPath) ){
return false;
}
//
// look through the haystack selector path to try and find the needle - extend.selector
// returns an array of selector matches that can then be replaced
//
$needleElements = $extend->selector->elements;
$potentialMatches = array();
$potentialMatches_len = 0;
$potentialMatch = null;
$matches = array();
// loop through the haystack elements
$haystack_path_len = count($haystackSelectorPath);
for($haystackSelectorIndex = 0; $haystackSelectorIndex < $haystack_path_len; $haystackSelectorIndex++ ){
$hackstackSelector = $haystackSelectorPath[$haystackSelectorIndex];
$haystack_elements_len = count($hackstackSelector->elements);
for($hackstackElementIndex = 0; $hackstackElementIndex < $haystack_elements_len; $hackstackElementIndex++ ){
$haystackElement = $hackstackSelector->elements[$hackstackElementIndex];
// if we allow elements before our match we can add a potential match every time. otherwise only at the first element.
if( $extend->allowBefore || ($haystackSelectorIndex === 0 && $hackstackElementIndex === 0) ){
$potentialMatches[] = array('pathIndex'=> $haystackSelectorIndex, 'index'=> $hackstackElementIndex, 'matched'=> 0, 'initialCombinator'=> $haystackElement->combinator);
$potentialMatches_len++;
}
for($i = 0; $i < $potentialMatches_len; $i++ ){
$potentialMatch = &$potentialMatches[$i];
$potentialMatch = $this->PotentialMatch( $potentialMatch, $needleElements, $haystackElement, $hackstackElementIndex );
// if we are still valid and have finished, test whether we have elements after and whether these are allowed
if( $potentialMatch && $potentialMatch['matched'] === $extend->selector->elements_len ){
$potentialMatch['finished'] = true;
if( !$extend->allowAfter && ($hackstackElementIndex+1 < $haystack_elements_len || $haystackSelectorIndex+1 < $haystack_path_len) ){
$potentialMatch = null;
}
}
// if null we remove, if not, we are still valid, so either push as a valid match or continue
if( $potentialMatch ){
if( $potentialMatch['finished'] ){
$potentialMatch['length'] = $extend->selector->elements_len;
$potentialMatch['endPathIndex'] = $haystackSelectorIndex;
$potentialMatch['endPathElementIndex'] = $hackstackElementIndex + 1; // index after end of match
$potentialMatches = array(); // we don't allow matches to overlap, so start matching again
$potentialMatches_len = 0;
$matches[] = $potentialMatch;
}
continue;
}
array_splice($potentialMatches, $i, 1);
$potentialMatches_len--;
$i--;
}
}
}
return $matches;
}
// Before going through all the nested loops, lets check to see if a match is possible
// Reduces Bootstrap 3.1 compile time from ~6.5s to ~5.6s
private function HasMatches($extend, $haystackSelectorPath){
if( !$extend->selector->cacheable ){
return true;
}
$first_el = $extend->selector->_oelements[0];
foreach($haystackSelectorPath as $hackstackSelector){
if( !$hackstackSelector->cacheable ){
return true;
}
// Optimisation: Explicit reference, <https://github.com/wikimedia/less.php/pull/14>
if( \array_key_exists($first_el, $hackstackSelector->_oelements_assoc) ){
return true;
}
}
return false;
}
/**
* @param integer $hackstackElementIndex
*/
private function PotentialMatch( $potentialMatch, $needleElements, $haystackElement, $hackstackElementIndex ){
if( $potentialMatch['matched'] > 0 ){
// selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't
// then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to work out
// what the resulting combinator will be
$targetCombinator = $haystackElement->combinator;
if( $targetCombinator === '' && $hackstackElementIndex === 0 ){
$targetCombinator = ' ';
}
if( $needleElements[ $potentialMatch['matched'] ]->combinator !== $targetCombinator ){
return null;
}
}
// if we don't match, null our match to indicate failure
if( !$this->isElementValuesEqual( $needleElements[$potentialMatch['matched'] ]->value, $haystackElement->value) ){
return null;
}
$potentialMatch['finished'] = false;
$potentialMatch['matched']++;
return $potentialMatch;
}
private function isElementValuesEqual( $elementValue1, $elementValue2 ){
if( $elementValue1 === $elementValue2 ){
return true;
}
if( is_string($elementValue1) || is_string($elementValue2) ) {
return false;
}
if( $elementValue1 instanceof Less_Tree_Attribute ){
return $this->isAttributeValuesEqual( $elementValue1, $elementValue2 );
}
$elementValue1 = $elementValue1->value;
if( $elementValue1 instanceof Less_Tree_Selector ){
return $this->isSelectorValuesEqual( $elementValue1, $elementValue2 );
}
return false;
}
/**
* @param Less_Tree_Selector $elementValue1
*/
private function isSelectorValuesEqual( $elementValue1, $elementValue2 ){
$elementValue2 = $elementValue2->value;
if( !($elementValue2 instanceof Less_Tree_Selector) || $elementValue1->elements_len !== $elementValue2->elements_len ){
return false;
}
for( $i = 0; $i < $elementValue1->elements_len; $i++ ){
if( $elementValue1->elements[$i]->combinator !== $elementValue2->elements[$i]->combinator ){
if( $i !== 0 || ($elementValue1->elements[$i]->combinator || ' ') !== ($elementValue2->elements[$i]->combinator || ' ') ){
return false;
}
}
if( !$this->isElementValuesEqual($elementValue1->elements[$i]->value, $elementValue2->elements[$i]->value) ){
return false;
}
}
return true;
}
/**
* @param Less_Tree_Attribute $elementValue1
*/
private function isAttributeValuesEqual( $elementValue1, $elementValue2 ){
if( $elementValue1->op !== $elementValue2->op || $elementValue1->key !== $elementValue2->key ){
return false;
}
if( !$elementValue1->value || !$elementValue2->value ){
if( $elementValue1->value || $elementValue2->value ) {
return false;
}
return true;
}
$elementValue1 = ($elementValue1->value->value ? $elementValue1->value->value : $elementValue1->value );
$elementValue2 = ($elementValue2->value->value ? $elementValue2->value->value : $elementValue2->value );
return $elementValue1 === $elementValue2;
}
private function extendSelector($matches, $selectorPath, $replacementSelector){
//for a set of matches, replace each match with the replacement selector
$currentSelectorPathIndex = 0;
$currentSelectorPathElementIndex = 0;
$path = array();
$selectorPath_len = count($selectorPath);
for($matchIndex = 0, $matches_len = count($matches); $matchIndex < $matches_len; $matchIndex++ ){
$match = $matches[$matchIndex];
$selector = $selectorPath[ $match['pathIndex'] ];
$firstElement = new Less_Tree_Element(
$match['initialCombinator'],
$replacementSelector->elements[0]->value,
$replacementSelector->elements[0]->index,
$replacementSelector->elements[0]->currentFileInfo
);
if( $match['pathIndex'] > $currentSelectorPathIndex && $currentSelectorPathElementIndex > 0 ){
$last_path = end($path);
$last_path->elements = array_merge( $last_path->elements, array_slice( $selectorPath[$currentSelectorPathIndex]->elements, $currentSelectorPathElementIndex));
$currentSelectorPathElementIndex = 0;
$currentSelectorPathIndex++;
}
$newElements = array_merge(
array_slice($selector->elements, $currentSelectorPathElementIndex, ($match['index'] - $currentSelectorPathElementIndex) ) // last parameter of array_slice is different than the last parameter of javascript's slice
, array($firstElement)
, array_slice($replacementSelector->elements,1)
);
if( $currentSelectorPathIndex === $match['pathIndex'] && $matchIndex > 0 ){
$last_key = count($path)-1;
$path[$last_key]->elements = array_merge($path[$last_key]->elements,$newElements);
}else{
$path = array_merge( $path, array_slice( $selectorPath, $currentSelectorPathIndex, $match['pathIndex'] ));
$path[] = new Less_Tree_Selector( $newElements );
}
$currentSelectorPathIndex = $match['endPathIndex'];
$currentSelectorPathElementIndex = $match['endPathElementIndex'];
if( $currentSelectorPathElementIndex >= count($selectorPath[$currentSelectorPathIndex]->elements) ){
$currentSelectorPathElementIndex = 0;
$currentSelectorPathIndex++;
}
}
if( $currentSelectorPathIndex < $selectorPath_len && $currentSelectorPathElementIndex > 0 ){
$last_path = end($path);
$last_path->elements = array_merge( $last_path->elements, array_slice($selectorPath[$currentSelectorPathIndex]->elements, $currentSelectorPathElementIndex));
$currentSelectorPathIndex++;
}
$slice_len = $selectorPath_len - $currentSelectorPathIndex;
$path = array_merge($path, array_slice($selectorPath, $currentSelectorPathIndex, $slice_len));
return $path;
}
protected function visitMedia( $mediaNode ){
$newAllExtends = array_merge( $mediaNode->allExtends, end($this->allExtendsStack) );
$this->allExtendsStack[] = $this->doExtendChaining($newAllExtends, $mediaNode->allExtends);
}
protected function visitMediaOut(){
array_pop( $this->allExtendsStack );
}
protected function visitDirective( $directiveNode ){
$newAllExtends = array_merge( $directiveNode->allExtends, end($this->allExtendsStack) );
$this->allExtendsStack[] = $this->doExtendChaining($newAllExtends, $directiveNode->allExtends);
}
protected function visitDirectiveOut(){
array_pop($this->allExtendsStack);
}
}
toCSS.php 0000644 00000015013 15155241154 0006253 0 ustar 00 <?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);
}
}