Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
90.91% covered (success)
90.91%
70 / 77
75.00% covered (warning)
75.00%
9 / 12
CRAP
0.00% covered (danger)
0.00%
0 / 1
Less_Tree
90.91% covered (success)
90.91%
70 / 77
75.00% covered (warning)
75.00%
9 / 12
48.66
0.00% covered (danger)
0.00%
0 / 1
 toCSS
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 genCSS
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 compile
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 _operate
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
5
 fround
83.33% covered (warning)
83.33%
5 / 6
0.00% covered (danger)
0.00%
0 / 1
3.04
 outputRuleset
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
4
 accept
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 nodeCompare
95.83% covered (success)
95.83%
23 / 24
0.00% covered (danger)
0.00%
0 / 1
21
 numericCompare
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
4
 ReferencedArray
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 __set_state
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 isVisible
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2declare( strict_types = 1 );
3
4/**
5 * Tree
6 */
7class Less_Tree {
8
9    /** @var bool */
10    public $parensInOp = false;
11    /** @var true|null */
12    public $extendOnEveryPath;
13    /** @var Less_Tree_Extend[] */
14    public $allExtends;
15    /**
16     * This is set to true to ensure visibility
17     * for all except Less_Tree_Anonymous where we decide
18     * if the the node should be visible or not
19     *
20     * @var bool
21     */
22    public $nodeVisible = true;
23
24    /**
25     * @var Less_Parser
26     * @see less-3.13.1.js#Node.prototype.parse
27     */
28    public static $parse;
29
30    /**
31     * @see less-2.5.3.js#Node.prototype.toCSS
32     */
33    public function toCSS() {
34        $output = new Less_Output();
35        $this->genCSS( $output );
36        return $output->toString();
37    }
38
39    /**
40     * Generate CSS by adding it to the output object
41     *
42     * @param Less_Output $output The output
43     * @return void
44     */
45    public function genCSS( $output ) {
46    }
47
48    public function compile( $env ) {
49        return $this;
50    }
51
52    /**
53     * @param string $op
54     * @param float $a
55     * @param float $b
56     * @see less-2.5.3.js#Node.prototype._operate
57     */
58    protected function _operate( $op, $a, $b ) {
59        switch ( $op ) {
60            case '+':
61                return $a + $b;
62            case '-':
63                return $a - $b;
64            case '*':
65                return $a * $b;
66            case '/':
67                return $a / $b;
68        }
69    }
70
71    /**
72     * @see less-2.5.3.js#Node.prototype.fround
73     */
74    protected function fround( $value ) {
75        if ( $value === 0 ) {
76            return $value;
77        }
78
79        // TODO: Migrate to passing $env.
80        if ( Less_Parser::$options['numPrecision'] ) {
81            $p = pow( 10, Less_Parser::$options['numPrecision'] );
82            return round( $value * $p ) / $p;
83        }
84        return $value;
85    }
86
87    /**
88     * @param Less_Output $output
89     * @param Less_Tree_Ruleset[] $rules
90     */
91    public static function outputRuleset( $output, $rules ) {
92        $ruleCnt = count( $rules );
93        Less_Environment::$tabLevel++;
94
95        // Compressed
96        if ( Less_Parser::$options['compress'] ) {
97            $output->add( '{' );
98            for ( $i = 0; $i < $ruleCnt; $i++ ) {
99                $rules[$i]->genCSS( $output );
100            }
101
102            $output->add( '}' );
103            Less_Environment::$tabLevel--;
104            return;
105        }
106
107        // Non-compressed
108        $tabSetStr = "\n" . str_repeat( Less_Parser::$options['indentation'], Less_Environment::$tabLevel - 1 );
109        $tabRuleStr = $tabSetStr . Less_Parser::$options['indentation'];
110
111        $output->add( " {" );
112        for ( $i = 0; $i < $ruleCnt; $i++ ) {
113            $output->add( $tabRuleStr );
114            $rules[$i]->genCSS( $output );
115        }
116        Less_Environment::$tabLevel--;
117        $output->add( $tabSetStr . '}' );
118    }
119
120    public function accept( $visitor ) {
121    }
122
123    /**
124     * @param Less_Tree $a
125     * @param Less_Tree $b
126     * @return int|null
127     * @see less-2.5.3.js#Node.compare
128     */
129    public static function nodeCompare( $a, $b ) {
130        // Less_Tree subclasses that implement compare() are:
131        // Anonymous, Color, Dimension, Quoted, Unit
132        $aHasCompare = ( $a instanceof Less_Tree_Anonymous || $a instanceof Less_Tree_Color
133            || $a instanceof Less_Tree_Dimension || $a instanceof Less_Tree_Quoted || $a instanceof Less_Tree_Unit
134        );
135        $bHasCompare = ( $b instanceof Less_Tree_Anonymous || $b instanceof Less_Tree_Color
136            || $b instanceof Less_Tree_Dimension || $b instanceof Less_Tree_Quoted || $b instanceof Less_Tree_Unit
137        );
138
139        if ( $aHasCompare &&
140            !( $b instanceof Less_Tree_Quoted || $b instanceof Less_Tree_Anonymous )
141        ) {
142            // for "symmetric results" force toCSS-based comparison via b.compare()
143            // of Quoted or Anonymous if either value is one of those
144            return $a->compare( $b );
145        } elseif ( $bHasCompare ) {
146            $res = $b->compare( $a );
147            // In JS, `-undefined` produces NAN, which, just like undefined
148            // will enter the the default/false branch of Less_Tree_Condition#compile.
149            // In PHP, `-null` is 0. To ensure parity, preserve the null.
150            return $res !== null ? -$res : null;
151        } elseif ( get_class( $a ) !== get_class( $b ) ) {
152            return null;
153        }
154
155        // Less_Tree subclasses that have an array value: Less_Tree_Expression, Less_Tree_Value
156        $aval = $a->value ?? [];
157        $bval = $b->value ?? [];
158        if ( !( $a instanceof Less_Tree_Expression || $a instanceof Less_Tree_Value ) ) {
159            return $aval === $bval ? 0 : null;
160        }
161        '@phan-var Less_Tree[] $aval';
162        '@phan-var Less_Tree[] $bval';
163        if ( count( $aval ) !== count( $bval ) ) {
164            return null;
165        }
166        foreach ( $aval as $i => $item ) {
167            if ( self::nodeCompare( $item, $bval[$i] ) !== 0 ) {
168                return null;
169            }
170        }
171        return 0;
172    }
173
174    /**
175     * @param string|float|int $a
176     * @param string|float|int $b
177     * @return int|null
178     * @see less-2.5.3.js#Node.numericCompare
179     */
180    public static function numericCompare( $a, $b ) {
181        return $a < $b ? -1
182            : ( $a === $b ? 0
183                : ( $a > $b ? 1
184                    // NAN is not greater, less, or equal
185                    : null
186                )
187            );
188    }
189
190    public static function ReferencedArray( $rules ) {
191        foreach ( $rules as $rule ) {
192            if ( method_exists( $rule, 'markReferenced' ) ) {
193                // @phan-suppress-next-line PhanUndeclaredMethod False positive
194                $rule->markReferenced();
195            }
196        }
197    }
198
199    /**
200     * Requires php 5.3+
201     */
202    public static function __set_state( $args ) {
203        $class = get_called_class();
204        $obj = new $class( null, null, null, null );
205        foreach ( $args as $key => $val ) {
206            $obj->$key = $val;
207        }
208        return $obj;
209    }
210
211    /**
212     * @see less-3.13.1.js#Node.prototype.isVisible
213     */
214    public function isVisible() {
215        return $this->nodeVisible;
216    }
217
218}