Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
90.41% covered (success)
90.41%
66 / 73
62.50% covered (warning)
62.50%
5 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
Less_Tree_Declaration
90.41% covered (success)
90.41%
66 / 73
62.50% covered (warning)
62.50%
5 / 8
36.08
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
5
 accept
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 genCSS
63.64% covered (warning)
63.64%
7 / 11
0.00% covered (danger)
0.00%
0 / 1
7.73
 compile
97.44% covered (success)
97.44%
38 / 39
0.00% covered (danger)
0.00%
0 / 1
14
 CompileName
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 makeImportant
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 mark
60.00% covered (warning)
60.00%
3 / 5
0.00% covered (danger)
0.00%
0 / 1
5.02
 markReferenced
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2declare( strict_types = 1 );
3
4/**
5 * @private
6 * @see less-3.13.1.js#Declaration.prototype
7 * @todo check for feature parity with 3.13.1
8 */
9class Less_Tree_Declaration extends Less_Tree implements Less_Tree_HasValueProperty {
10
11    /** @var string|array<Less_Tree_Keyword|Less_Tree_Variable> */
12    public $name;
13    /** @var Less_Tree */
14    public $value;
15    /** @var string */
16    public $important;
17    /** @var null|false|string */
18    public $merge;
19    /** @var int|null */
20    public $index;
21    /** @var bool */
22    public $inline;
23    /** @var bool */
24    public $variable;
25    /** @var array|null */
26    public $currentFileInfo;
27
28    /**
29     * In the upstream `parsed` is stored in `Node`, but Less_Tree_Declaration is the only place
30     * that make use of it.
31     * @see less-3.13.1.js#Node.parsed
32     * @var bool
33     */
34    public $parsed = false;
35
36    /**
37     * @param string|array<Less_Tree_Keyword|Less_Tree_Variable> $name
38     * @param Less_Tree|string|null $value
39     * @param null|false|string $important
40     * @param null|false|string $merge
41     * @param int|null $index
42     * @param array|null $currentFileInfo
43     * @param bool $inline
44     * @param bool|null $variable
45     */
46    public function __construct(
47        $name,
48        $value = null,
49        $important = null,
50        $merge = null,
51        $index = null,
52        $currentFileInfo = null,
53        $inline = false,
54        $variable = null
55    ) {
56        $this->name = $name;
57        $this->value = ( $value instanceof Less_Tree )
58            ? $value
59            : new Less_Tree_Value( [ $value ? new Less_Tree_Anonymous( $value ) : null ] );
60        $this->important = $important ? ' ' . trim( $important ) : '';
61        $this->merge = $merge;
62        $this->index = $index;
63        $this->currentFileInfo = $currentFileInfo;
64        $this->inline = $inline;
65        $this->variable = $variable ?? ( is_string( $name ) && $name[0] === '@' );
66    }
67
68    public function accept( $visitor ) {
69        $this->value = $visitor->visitObj( $this->value );
70    }
71
72    /**
73     * @see less-2.5.3.js#Rule.prototype.genCSS
74     */
75    public function genCSS( $output ) {
76        $output->add( $this->name . ( Less_Parser::$options['compress'] ? ':' : ': ' ), $this->currentFileInfo, $this->index );
77        try {
78            $this->value->genCSS( $output );
79
80        } catch ( Less_Exception_Parser $e ) {
81            $e->index = $this->index;
82            $e->currentFile = $this->currentFileInfo;
83            throw $e;
84        }
85        $output->add(
86            $this->important . ( ( $this->inline || ( Less_Environment::$lastRule && Less_Parser::$options['compress'] ) ) ? "" : ";" ),
87            $this->currentFileInfo,
88            $this->index
89        );
90    }
91
92    /**
93     * @see less-2.5.3.js#Rule.prototype.eval
94     * @param Less_Environment $env
95     * @return self
96     */
97    public function compile( $env ) {
98        $variable = $this->variable;
99        $name = $this->name;
100        if ( is_array( $name ) ) {
101            // expand 'primitive' name directly to get
102            // things faster (~10% for benchmark.less):
103            if ( count( $name ) === 1 && $name[0] instanceof Less_Tree_Keyword ) {
104                $name = $name[0]->value;
105            } else {
106                $name = $this->CompileName( $env, $name );
107            }
108            $variable = false; // never treat expanded interpolation as new variable name
109        }
110
111        $mathBypass = false;
112        $prevMath = $env->math;
113        if ( $name === "font" && $env->math === Less_Environment::MATH_ALWAYS ) {
114            $mathBypass = true;
115            $env->math = Less_Environment::MATH_PARENS_DIVISION;
116        }
117
118        try {
119            $env->importantScope[] = [];
120            $evaldValue = $this->value->compile( $env );
121
122            if ( !$this->variable && $evaldValue instanceof Less_Tree_DetachedRuleset ) {
123                throw new Less_Exception_Compiler( "Rulesets cannot be evaluated on a property.", null, $this->index, $this->currentFileInfo );
124            }
125
126            $important = $this->important;
127            $importantResult = array_pop( $env->importantScope );
128
129            if ( !$important && isset( $importantResult['important'] ) && $importantResult['important'] ) {
130                $important = $importantResult['important'];
131            }
132
133            $return = new Less_Tree_Declaration(
134                $name,
135                $evaldValue,
136                $important,
137                $this->merge,
138                $this->index,
139                $this->currentFileInfo,
140                $this->inline,
141                $variable,
142            );
143
144        } catch ( Less_Exception_Parser $e ) {
145            if ( !is_numeric( $e->index ) ) {
146                $e->index = $this->index;
147                $e->currentFile = $this->currentFileInfo;
148                $e->genMessage();
149            }
150            throw $e;
151        }
152
153        if ( $mathBypass ) {
154            $env->math = $prevMath;
155        }
156
157        return $return;
158    }
159
160    public function CompileName( $env, $name ) {
161        $output = new Less_Output();
162        foreach ( $name as $n ) {
163            $n->compile( $env )->genCSS( $output );
164        }
165        return $output->toString();
166    }
167
168    public function makeImportant() {
169        return new self( $this->name, $this->value, '!important', $this->merge, $this->index, $this->currentFileInfo, $this->inline );
170    }
171
172    public function mark( $value ) {
173        if ( !is_array( $this->value ) ) {
174
175            if ( method_exists( $value, 'markReferenced' ) ) {
176                // @phan-suppress-next-line PhanUndeclaredMethod
177                $value->markReferenced();
178            }
179        } else {
180            foreach ( $this->value as $v ) {
181                $this->mark( $v );
182            }
183        }
184    }
185
186    public function markReferenced() {
187        if ( $this->value ) {
188            $this->mark( $this->value );
189        }
190    }
191
192}