Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.24% covered (success)
97.24%
141 / 145
89.47% covered (warning)
89.47%
17 / 19
CRAP
0.00% covered (danger)
0.00%
0 / 1
Less_Visitor_toCSS
97.24% covered (success)
97.24%
141 / 145
89.47% covered (warning)
89.47%
17 / 19
80
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 run
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 visitDeclaration
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 visitMixinDefinition
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 visitExtend
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 visitComment
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 visitMedia
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 visitAtRule
95.24% covered (success)
95.24%
20 / 21
0.00% covered (danger)
0.00%
0 / 1
10
 checkPropertiesInRoot
57.14% covered (warning)
57.14%
4 / 7
0.00% covered (danger)
0.00%
0 / 1
8.83
 visitRuleset
100.00% covered (success)
100.00%
26 / 26
100.00% covered (success)
100.00%
1 / 1
10
 visitAnonymous
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 visitImport
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 visitRulesetRoot
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 visitRulesetPaths
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
6
 _removeDuplicateRules
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
8
 _mergeRules
100.00% covered (success)
100.00%
27 / 27
100.00% covered (success)
100.00%
1 / 1
11
 toExpression
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 toValue
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 hasVisibleChild
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
7
1<?php
2/**
3 * @private
4 */
5class Less_Visitor_toCSS extends Less_VisitorReplacing {
6
7    private $charset;
8
9    public function __construct() {
10        parent::__construct();
11    }
12
13    /**
14     * @param Less_Tree_Ruleset $root
15     */
16    public function run( $root ) {
17        return $this->visitObj( $root );
18    }
19
20    public function visitDeclaration( $declNode ) {
21        if ( $declNode->variable ) {
22            return [];
23        }
24        return $declNode;
25    }
26
27    public function visitMixinDefinition( $mixinNode ) {
28        // mixin definitions do not get eval'd - this means they keep state
29        // so we have to clear that state here so it isn't used if toCSS is called twice
30        $mixinNode->frames = [];
31        return [];
32    }
33
34    public function visitExtend() {
35        return [];
36    }
37
38    public function visitComment( $commentNode ) {
39        if ( $commentNode->isSilent() ) {
40            return [];
41        }
42        return $commentNode;
43    }
44
45    public function visitMedia( $mediaNode, &$visitDeeper ) {
46        $mediaNode->accept( $this );
47        $visitDeeper = false;
48
49        if ( !$mediaNode->rules ) {
50            return [];
51        }
52        return $mediaNode;
53    }
54
55    public function visitAtRule( $atRuleNode, &$visitDeeper ) {
56        if ( $atRuleNode->name === '@charset' ) {
57            if ( !$atRuleNode->getIsReferenced() ) {
58                return;
59            }
60            if ( isset( $this->charset ) && $this->charset ) {
61                // NOTE: Skip debugInfo handling (not implemented)
62                return;
63            }
64            $this->charset = true;
65        }
66
67        if ( $atRuleNode->rules ) {
68            $this->_mergeRules( $atRuleNode->rules[0]->rules );
69            // process childs
70            $atRuleNode->accept( $this );
71            $visitDeeper = false;
72
73            // the directive was directly referenced and therefore needs to be shown in the output
74            if ( $atRuleNode->getIsReferenced() ) {
75                return $atRuleNode;
76            }
77
78            if ( !$atRuleNode->rules ) {
79                return;
80            }
81            if ( $this->hasVisibleChild( $atRuleNode ) ) {
82                // marking as referenced in case the directive is stored inside another directive
83                $atRuleNode->markReferenced();
84                return $atRuleNode;
85            }
86                // The directive was not directly referenced and does not contain anything that
87                //was referenced. Therefore it must not be shown in output.
88                return;
89        } else {
90            if ( !$atRuleNode->getIsReferenced() ) {
91                return;
92            }
93        }
94
95        return $atRuleNode;
96    }
97
98    public function checkPropertiesInRoot( $rulesetNode ) {
99        if ( !$rulesetNode->firstRoot ) {
100            return;
101        }
102
103        foreach ( $rulesetNode->rules as $ruleNode ) {
104            if ( $ruleNode instanceof Less_Tree_Declaration && !$ruleNode->variable ) {
105                $msg = "properties must be inside selector blocks, they cannot be in the root. Index " . $ruleNode->index .
106                    ( $ruleNode->currentFileInfo ? ' Filename: ' . $ruleNode->currentFileInfo['filename'] : null );
107                throw new Less_Exception_Compiler( $msg );
108            }
109        }
110    }
111
112    public function visitRuleset( $rulesetNode, &$visitDeeper ) {
113        $visitDeeper = false;
114
115        $this->checkPropertiesInRoot( $rulesetNode );
116
117        if ( $rulesetNode->root ) {
118            return $this->visitRulesetRoot( $rulesetNode );
119        }
120
121        $rulesets = [];
122        $rulesetNode->paths = $this->visitRulesetPaths( $rulesetNode );
123
124        // Compile rules and rulesets
125        $nodeRuleCnt = $rulesetNode->rules ? count( $rulesetNode->rules ) : 0;
126        for ( $i = 0; $i < $nodeRuleCnt; ) {
127            $rule = $rulesetNode->rules[$i];
128
129            if ( property_exists( $rule, 'rules' ) ) {
130                // visit because we are moving them out from being a child
131                $rulesets[] = $this->visitObj( $rule );
132                array_splice( $rulesetNode->rules, $i, 1 );
133                $nodeRuleCnt--;
134                continue;
135            }
136            $i++;
137        }
138
139        // accept the visitor to remove rules and refactor itself
140        // then we can decide now whether we want it or not
141        if ( $nodeRuleCnt > 0 ) {
142            $rulesetNode->accept( $this );
143
144            if ( $rulesetNode->rules ) {
145
146                if ( count( $rulesetNode->rules ) > 1 ) {
147                    $this->_mergeRules( $rulesetNode->rules );
148                    $this->_removeDuplicateRules( $rulesetNode->rules );
149                }
150
151                // now decide whether we keep the ruleset
152                if ( $rulesetNode->paths ) {
153                    // array_unshift($rulesets, $rulesetNode);
154                    array_splice( $rulesets, 0, 0, [ $rulesetNode ] );
155                }
156            }
157
158        }
159
160        if ( count( $rulesets ) === 1 ) {
161            return $rulesets[0];
162        }
163        return $rulesets;
164    }
165
166    public function visitAnonymous( $anonymousNode ) {
167        if ( !$anonymousNode->getIsReferenced() ) {
168            return;
169        }
170
171        $anonymousNode->accept( $this );
172        return $anonymousNode;
173    }
174
175    public function visitImport( $importNode ) {
176        if ( isset( $importNode->path->currentFileInfo["reference"] ) && $importNode->css ) {
177            return;
178        }
179        return $importNode;
180    }
181
182    /**
183     * Helper function for visitiRuleset
184     *
185     * return array|Less_Tree_Ruleset
186     */
187    private function visitRulesetRoot( $rulesetNode ) {
188        $rulesetNode->accept( $this );
189        if ( $rulesetNode->firstRoot || $rulesetNode->rules ) {