Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
91.05% |
966 / 1061 |
|
66.67% |
70 / 105 |
CRAP | |
0.00% |
0 / 1 |
Less_Parser | |
91.05% |
966 / 1061 |
|
66.67% |
70 / 105 |
710.61 | |
0.00% |
0 / 1 |
__construct | |
71.43% |
5 / 7 |
|
0.00% |
0 / 1 |
3.21 | |||
Reset | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
2 | |||
SetOptions | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
SetOption | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
4 | |||
registerFunction | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
unregisterFunction | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
getCss | |
92.31% |
24 / 26 |
|
0.00% |
0 / 1 |
6.02 | |||
findValueOf | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
30 | |||
getVariables | |
86.67% |
13 / 15 |
|
0.00% |
0 / 1 |
6.09 | |||
findVarByName | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
30 | |||
getVariableValue | |
42.86% |
9 / 21 |
|
0.00% |
0 / 1 |
94.64 | |||
rgb2html | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
3 | |||
PreVisitors | |
25.00% |
1 / 4 |
|
0.00% |
0 / 1 |
10.75 | |||
PostVisitors | |
57.14% |
8 / 14 |
|
0.00% |
0 / 1 |
15.38 | |||
parse | |
92.86% |
13 / 14 |
|
0.00% |
0 / 1 |
3.00 | |||
parseFile | |
88.89% |
16 / 18 |
|
0.00% |
0 / 1 |
8.09 | |||
ModifyVars | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
SetFileInfo | |
100.00% |
19 / 19 |
|
100.00% |
1 / 1 |
5 | |||
SetCacheDir | n/a |
0 / 0 |
n/a |
0 / 0 |
5 | |||||
SetImportDirs | |
90.00% |
9 / 10 |
|
0.00% |
0 / 1 |
5.03 | |||
_parse | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
GetRules | |
73.53% |
25 / 34 |
|
0.00% |
0 / 1 |
16.13 | |||
SetInput | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
4 | |||
UnsetInput | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
CacheFile | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
3 | |||
AddParsedFile | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
AllParsedFiles | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
FileParsed | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
save | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
restore | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
forget | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isWhitespace | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
matcher | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
7 | |||
MatchChar | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
3 | |||
MatchReg | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
PeekReg | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
PeekChar | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
skipWhitespace | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
expect | |
75.00% |
3 / 4 |
|
0.00% |
0 / 1 |
3.14 | |||
expectChar | |
60.00% |
3 / 5 |
|
0.00% |
0 / 1 |
3.58 | |||
parsePrimary | |
100.00% |
24 / 24 |
|
100.00% |
1 / 1 |
7 | |||
parseComment | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
4 | |||
parseComments | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
3 | |||
parseEntitiesQuoted | |
92.86% |
26 / 28 |
|
0.00% |
0 / 1 |
12.05 | |||
parseEntitiesKeyword | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
3 | |||
FromKeyword | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
parseEntitiesCall | |
100.00% |
18 / 18 |
|
100.00% |
1 / 1 |
7 | |||
parseEntitiesArguments | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
4 | |||
parseEntitiesLiteral | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
parseEntitiesAssignment | |
87.50% |
7 / 8 |
|
0.00% |
0 / 1 |
4.03 | |||
parseEntitiesUrl | |
90.00% |
9 / 10 |
|
0.00% |
0 / 1 |
6.04 | |||
parseEntitiesVariable | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
3 | |||
parseEntitiesVariableCurly | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
4 | |||
parseEntitiesColor | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
3 | |||
parseEntitiesDimension | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
7 | |||
parseUnicodeDescriptor | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
3 | |||
parseEntitiesJavascript | |
83.33% |
15 / 18 |
|
0.00% |
0 / 1 |
6.17 | |||
parseVariable | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
3 | |||
parseRulesetCall | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
3 | |||
parseExtend | |
100.00% |
22 / 22 |
|
100.00% |
1 / 1 |
8 | |||
parseMixinCall | |
100.00% |
17 / 17 |
|
100.00% |
1 / 1 |
6 | |||
parseMixinCallElements | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
3 | |||
parseMixinArgs | |
91.14% |
72 / 79 |
|
0.00% |
0 / 1 |
34.80 | |||
parseMixinDefinition | |
100.00% |
23 / 23 |
|
100.00% |
1 / 1 |
9 | |||
parseEntity | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
parseEnd | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
parseAlpha | |
90.00% |
9 / 10 |
|
0.00% |
0 / 1 |
4.02 | |||
parseElement | |
100.00% |
22 / 22 |
|
100.00% |
1 / 1 |
6 | |||
parseCombinator | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
10 | |||
parseLessSelector | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
parseSelector | |
95.83% |
23 / 24 |
|
0.00% |
0 / 1 |
17 | |||
parseTag | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
6 | |||
parseAttribute | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
5 | |||
parseBlock | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 | |||
parseBlockRuleset | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
parseDetachedRuleset | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
parseRuleset | |
90.48% |
19 / 21 |
|
0.00% |
0 / 1 |
9.07 | |||
parseNameValue | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
4 | |||
parseRule | |
100.00% |
34 / 34 |
|
100.00% |
1 / 1 |
20 | |||
parseAnonymousValue | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
parseImport | |
100.00% |
13 / 13 |
|
100.00% |
1 / 1 |
5 | |||
parseImportOptions | |
85.00% |
17 / 20 |
|
0.00% |
0 / 1 |
6.12 | |||
parseImportOption | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
parseMediaFeature | |
94.44% |
17 / 18 |
|
0.00% |
0 / 1 |
8.01 | |||
parseMediaFeatures | |
76.92% |
10 / 13 |
|
0.00% |
0 / 1 |
6.44 | |||
parseMedia | |
77.78% |
7 / 9 |
|
0.00% |
0 / 1 |
3.10 | |||
parseDirective | |
96.61% |
57 / 59 |
|
0.00% |
0 / 1 |
24 | |||
parseValue | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
4 | |||
parseImportant | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
3 | |||
parseSub | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
parseMultiplication | |
94.44% |
17 / 18 |
|
0.00% |
0 / 1 |
7.01 | |||
parseAddition | |
94.44% |
17 / 18 |
|
0.00% |
0 / 1 |
7.01 | |||
parseConditions | |
90.91% |
10 / 11 |
|
0.00% |
0 / 1 |
6.03 | |||
parseCondition | |
100.00% |
18 / 18 |
|
100.00% |
1 / 1 |
6 | |||
parseOperand | |
100.00% |
12 / 12 |
|
100.00% |
1 / 1 |
5 | |||
parseExpression | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
5 | |||
parseProperty | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
parseRuleProperty | |
100.00% |
21 / 21 |
|
100.00% |
1 / 1 |
9 | |||
rulePropertyMatch | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
2 | |||
serializeVars | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
20 | |||
is_method | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
round | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
2 | |||
Error | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
WinPath | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
AbsPath | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
5 | |||
CacheEnabled | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
3 |
1 | <?php |
2 | |
3 | /** |
4 | * Parse and compile Less files into CSS |
5 | */ |
6 | class Less_Parser { |
7 | |
8 | /** |
9 | * Default parser options |
10 | * @var array<string,mixed> |
11 | */ |
12 | public static $default_options = [ |
13 | 'compress' => false, // option - whether to compress |
14 | 'strictUnits' => false, // whether units need to evaluate correctly |
15 | 'strictMath' => false, // whether math has to be within parenthesis |
16 | 'relativeUrls' => true, // option - whether to adjust URL's to be relative |
17 | 'urlArgs' => '', // whether to add args into url tokens |
18 | 'numPrecision' => 8, |
19 | |
20 | 'import_dirs' => [], |
21 | 'import_callback' => null, |
22 | 'cache_dir' => null, |
23 | 'cache_method' => 'serialize', // false, 'serialize', 'callback'; |
24 | 'cache_callback_get' => null, |
25 | 'cache_callback_set' => null, |
26 | |
27 | 'sourceMap' => false, // whether to output a source map |
28 | 'sourceMapBasepath' => null, |
29 | 'sourceMapWriteTo' => null, |
30 | 'sourceMapURL' => null, |
31 | |
32 | 'indentation' => ' ', |
33 | |
34 | 'plugins' => [], |
35 | |
36 | ]; |
37 | |
38 | /** @var array{compress:bool,strictUnits:bool,strictMath:bool,numPrecision:int,import_dirs:array,import_callback:null|callable,indentation:string} */ |
39 | public static $options = []; |
40 | |
41 | private $input; // Less input string |
42 | private $input_len; // input string length |
43 | private $pos; // current index in `input` |
44 | private $saveStack = []; // holds state for backtracking |
45 | private $furthest; |
46 | private $mb_internal_encoding = ''; // for remember exists value of mbstring.internal_encoding |
47 | |
48 | /** |
49 | * @var Less_Environment |
50 | */ |
51 | private $env; |
52 | |
53 | protected $rules = []; |
54 | |
55 | private static $imports = []; |
56 | |
57 | public static $has_extends = false; |
58 | |
59 | public static $next_id = 0; |
60 | |
61 | /** |
62 | * Filename to contents of all parsed the files |
63 | * |
64 | * @var array |
65 | */ |
66 | public static $contentsMap = []; |
67 | |
68 | /** |
69 | * @param Less_Environment|array|null $env |
70 | */ |
71 | public function __construct( $env = null ) { |
72 | // Top parser on an import tree must be sure there is one "env" |
73 | // which will then be passed around by reference. |
74 | if ( $env instanceof Less_Environment ) { |
75 | $this->env = $env; |
76 | } else { |
77 | $this->SetOptions( self::$default_options ); |
78 | $this->Reset( $env ); |
79 | } |
80 | |
81 | // mbstring.func_overload > 1 bugfix |
82 | // The encoding value must be set for each source file, |
83 | // therefore, to conserve resources and improve the speed of this design is taken here |
84 | if ( ini_get( 'mbstring.func_overload' ) ) { |
85 | $this->mb_internal_encoding = ini_get( 'mbstring.internal_encoding' ); |
86 | @ini_set( 'mbstring.internal_encoding', 'ascii' ); |
87 | } |
88 | } |
89 | |
90 | /** |
91 | * Reset the parser state completely |
92 | */ |
93 | public function Reset( $options = null ) { |
94 | $this->rules = []; |
95 | self::$imports = []; |
96 | self::$has_extends = false; |
97 | self::$imports = []; |
98 | self::$contentsMap = []; |
99 | |
100 | $this->env = new Less_Environment(); |
101 | |
102 | // set new options |
103 | if ( is_array( $options ) ) { |
104 | $this->SetOptions( self::$default_options ); |
105 | $this->SetOptions( $options ); |
106 | } |
107 | |
108 | $this->env->Init(); |
109 | } |
110 | |
111 | /** |
112 | * Set one or more compiler options |
113 | * options: import_dirs, cache_dir, cache_method |
114 | */ |
115 | public function SetOptions( $options ) { |
116 | foreach ( $options as $option => $value ) { |
117 | $this->SetOption( $option, $value ); |
118 | } |
119 | } |
120 | |
121 | /** |
122 | * Set one compiler option |
123 | */ |
124 | public function SetOption( $option, $value ) { |
125 | switch ( $option ) { |
126 | |
127 | case 'import_dirs': |
128 | $this->SetImportDirs( $value ); |
129 | return; |
130 | |
131 | case 'cache_dir': |
132 | if ( is_string( $value ) ) { |
133 | Less_Cache::SetCacheDir( $value ); |
134 | Less_Cache::CheckCacheDir(); |
135 | } |
136 | return; |
137 | } |
138 | |
139 | self::$options[$option] = $value; |
140 | } |
141 | |
142 | /** |
143 | * Registers a new custom function |
144 | * |
145 | * @param string $name function name |
146 | * @param callable $callback callback |
147 | */ |
148 | public function registerFunction( $name, $callback ) { |
149 | $this->env->functions[$name] = $callback; |
150 | } |
151 | |
152 | /** |
153 | * Removed an already registered function |
154 | * |
155 | * @param string $name function name |
156 | */ |
157 | public function unregisterFunction( $name ) { |
158 | if ( isset( $this->env->functions[$name] ) ) { |
159 | unset( $this->env->functions[$name] ); |
160 | } |
161 | } |
162 | |
163 | /** |
164 | * Get the current css buffer |
165 | * |
166 | * @return string |
167 | */ |
168 | public function getCss() { |
169 | $precision = ini_get( 'precision' ); |
170 | @ini_set( 'precision', '16' ); |
171 | $locale = setlocale( LC_NUMERIC, 0 ); |
172 | setlocale( LC_NUMERIC, "C" ); |
173 | |
174 | try { |
175 | $root = new Less_Tree_Ruleset( null, $this->rules ); |
176 | $root->root = true; |
177 | $root->firstRoot = true; |
178 | |
179 | $this->PreVisitors( $root ); |
180 | |
181 | self::$has_extends = false; |
182 | $evaldRoot = $root->compile( $this->env ); |
183 | |
184 | $this->PostVisitors( $evaldRoot ); |
185 | |
186 | if ( self::$options['sourceMap'] ) { |
187 | $generator = new Less_SourceMap_Generator( $evaldRoot, self::$contentsMap, self::$options ); |
188 | // will also save file |
189 | // FIXME: should happen somewhere else? |
190 | $css = $generator->generateCSS(); |
191 | } else { |
192 | $css = $evaldRoot->toCSS(); |
193 | } |
194 | |
195 | if ( self::$options['compress'] ) { |
196 | $css = preg_replace( '/(^(\s)+)|((\s)+$)/', '', $css ); |
197 | } |
198 | |
199 | } catch ( Exception $exc ) { |
200 | // Intentional fall-through so we can reset environment |
201 | } |
202 | |
203 | // reset php settings |
204 | @ini_set( 'precision', $precision ); |
205 | setlocale( LC_NUMERIC, $locale ); |
206 | |
207 | // If you previously defined $this->mb_internal_encoding |
208 | // is required to return the encoding as it was before |
209 | if ( $this->mb_internal_encoding != '' ) { |
210 | @ini_set( "mbstring.internal_encoding", $this->mb_internal_encoding ); |
211 | $this->mb_internal_encoding = ''; |
212 | } |
213 | |
214 | // Rethrow exception after we handled resetting the environment |
215 | if ( !empty( $exc ) ) { |
216 | throw $exc; |
217 | } |
218 | |
219 | return $css; |
220 | } |
221 | |
222 | public function findValueOf( $varName ) { |
223 | foreach ( $this->rules as $rule ) { |
224 | if ( isset( $rule->variable ) && ( $rule->variable == true ) && ( str_replace( "@", "", $rule->name ) == $varName ) ) { |
225 | return $this->getVariableValue( $rule ); |
226 | } |
227 | } |
228 | return null; |
229 | } |
230 | |
231 | /** |
232 | * Gets the private rules variable and returns an array of the found variables |
233 | * it uses a helper method getVariableValue() that contains the logic ot fetch the value |
234 | * from the rule object |
235 | * |
236 | * @return array |
237 | */ |
238 | public function getVariables() { |
239 | $variables = []; |
240 | |
241 | $not_variable_type = [ |
242 | Less_Tree_Comment::class, // this include less comments ( // ) and css comments (/* */) |
243 | Less_Tree_Import::class, // do not search variables in included files @import |
244 | Less_Tree_Ruleset::class, // selectors (.someclass, #someid, …) |
245 | Less_Tree_Operation::class, |
246 | ]; |
247 | |
248 | // @TODO run compilation if not runned yet |
249 | foreach ( $this->rules as $key => $rule ) { |
250 | if ( in_array( get_class( $rule ), $not_variable_type ) ) { |
251 | continue; |
252 | } |
253 | |
254 | // Note: it seems $rule is always Less_Tree_Rule when variable = true |
255 | if ( $rule instanceof Less_Tree_Rule && $rule->variable ) { |
256 | $variables[$rule->name] = $this->getVariableValue( $rule ); |
257 | } else { |
258 | if ( $rule instanceof Less_Tree_Comment ) { |
259 | $variables[] = $this->getVariableValue( $rule ); |
260 | } |
261 | } |
262 | } |
263 | return $variables; |
264 | } |
265 | |
266 | public function findVarByName( $var_name ) { |
267 | foreach ( $this->rules as $rule ) { |
268 | if ( isset( $rule->variable ) && ( $rule->variable == true ) ) { |
269 | if ( $rule->name == $var_name ) { |
270 | return $this->getVariableValue( $rule ); |
271 | } |
272 | } |
273 | } |
274 | return null; |
275 | } |
276 | |
277 | /** |
278 | * This method gets the value of the less variable from the rules object. |
279 | * Since the objects vary here we add the logic for extracting the css/less value. |
280 | * |
281 | * @param Less_Tree $var |
282 | * @return string |
283 | */ |
284 | private function getVariableValue( Less_Tree $var ) { |
285 | switch ( get_class( $var ) ) { |
286 | case Less_Tree_Color::class: |
287 | return $this->rgb2html( $var->rgb ); |
288 | case Less_Tree_Variable::class: |
289 | return $this->findVarByName( $var->name ); |
290 | case Less_Tree_Keyword::class: |
291 | return $var->value; |
292 | case Less_Tree_Url::class: |
293 | // Based on Less_Tree_Url::genCSS() |
294 | // Recurse to serialize the Less_Tree_Quoted value |
295 | return 'url(' . $this->getVariableValue( $var->value ) . ')'; |
296 | case Less_Tree_Rule::class: |
297 | return $this->getVariableValue( $var->value ); |
298 | case Less_Tree_Value::class: |
299 | $value = ''; |
300 | foreach ( $var->value as $sub_value ) { |
301 | $value .= $this->getVariableValue( $sub_value ) . ' '; |
302 | } |
303 | return $value; |
304 | case Less_Tree_Quoted::class: |
305 | return $var->quote . $var->value . $var->quote; |
306 | case Less_Tree_Dimension::class: |
307 | $value = $var->value; |
308 | if ( $var->unit && $var->unit->numerator ) { |
309 | $value .= $var->unit->numerator[0]; |
310 | } |
311 | return $value; |
312 | case Less_Tree_Expression::class: |
313 | $value = ''; |
314 | foreach ( $var->value as $item ) { |
315 | $value .= $this->getVariableValue( $item ) . " "; |
316 | } |
317 | return $value; |
318 | case Less_Tree_Operation::class: |
319 | throw new Exception( 'getVariables() require Less to be compiled. please use $parser->getCss() before calling getVariables()' ); |
320 | case Less_Tree_Unit::class: |
321 | case Less_Tree_Comment::class: |
322 | case Less_Tree_Import::class: |
323 | case Less_Tree_Ruleset::class: |
324 | default: |
325 | throw new Exception( "type missing in switch/case getVariableValue for " . get_class( $var ) ); |
326 | } |
327 | } |
328 | |
329 | private function rgb2html( $r, $g = -1, $b = -1 ) { |
330 | if ( is_array( $r ) && count( $r ) == 3 ) { |
331 | list( $r, $g, $b ) = $r; |
332 | } |
333 | |
334 | return sprintf( '#%02x%02x%02x', $r, $g, $b ); |
335 | } |
336 | |
337 | /** |
338 | * Run pre-compile visitors |
339 | */ |
340 | private function PreVisitors( $root ) { |
341 | if ( self::$options['plugins'] ) { |
342 | foreach ( self::$options['plugins'] as $plugin ) { |
343 | if ( !empty( $plugin->isPreEvalVisitor ) ) { |
344 | $plugin->run( $root ); |
345 | } |
346 | } |
347 | } |
348 | } |
349 | |
350 | /** |
351 | * Run post-compile visitors |
352 | */ |
353 | private function PostVisitors( $evaldRoot ) { |
354 | $visitors = []; |
355 | $visitors[] = new Less_Visitor_joinSelector(); |
356 | if ( self::$has_extends ) { |
357 | $visitors[] = new Less_Visitor_processExtends(); |
358 | } |
359 | $visitors[] = new Less_Visitor_toCSS(); |
360 | |
361 | if ( self::$options['plugins'] ) { |
362 | foreach ( self::$options['plugins'] as $plugin ) { |
363 | if ( property_exists( $plugin, 'isPreEvalVisitor' ) && $plugin->isPreEvalVisitor ) { |
364 | continue; |
365 | } |
366 | |
367 | if ( property_exists( $plugin, 'isPreVisitor' ) && $plugin->isPreVisitor ) { |
368 | array_unshift( $visitors, $plugin ); |
369 | } else { |
370 | $visitors[] = $plugin; |
371 | } |
372 | } |
373 | } |
374 | |
375 | for ( $i = 0; $i < count( $visitors ); $i++ ) { |