Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
98.00% covered (success)
98.00%
49 / 50
91.67% covered (success)
91.67%
11 / 12
CRAP
0.00% covered (danger)
0.00%
0 / 1
Less_Environment
98.00% covered (success)
98.00%
49 / 50
91.67% covered (success)
91.67%
11 / 12
23
0.00% covered (danger)
0.00%
0 / 1
 Init
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 addParsedFile
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 clone
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 isFileParsed
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 copyEvalEnv
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 isMathOn
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
6
 inParenthesis
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 outOfParenthesis
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isPathRelative
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 normalizePath
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
7
 unshiftFrame
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 shiftFrame
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * @private
4 */
5class Less_Environment {
6
7    /**
8     * Information about the current file - for error reporting and importing and making urls relative etc.
9     *
10     * - rootpath: rootpath to append to URLs
11     *
12     * @var array|null
13     */
14    public $currentFileInfo;
15
16    /** @var bool Whether we are currently importing multiple copies */
17    public $importMultiple = false;
18
19    /**
20     * @var array
21     */
22    public $frames = [];
23    /** @var array */
24    public $importantScope = [];
25    public $inCalc = false;
26    public $mathOn = true;
27
28    /** @var Less_Tree_Media[] */
29    public $mediaBlocks = [];
30    /** @var Less_Tree_Media[] */
31    public $mediaPath = [];
32
33    /** @var string[] */
34    public $imports = [];
35
36    /**
37     * This is the equivalent of `importVisitor.onceFileDetectionMap`
38     * as used by the dynamic `importNode.skip` function.
39     *
40     * @see less-2.5.3.js#ImportVisitor.prototype.onImported
41     * @var array<string,true>
42     */
43    public $importVisitorOnceMap = [];
44
45    public static $tabLevel = 0;
46
47    public static $lastRule = false;
48
49    public static $_noSpaceCombinators;
50
51    public static $mixin_stack = 0;
52
53    public $math = self::MATH_PARENS_DIVISION;
54
55    public $importCallback = null;
56
57    public $parensStack = [];
58
59    public const MATH_ALWAYS = 0;
60    public const MATH_PARENS_DIVISION = 1;
61    public const MATH_PARENS = 2;
62
63    /**
64     * @var array
65     */
66    public $functions = [];
67
68    public function Init() {
69        self::$tabLevel = 0;
70        self::$lastRule = false;
71        self::$mixin_stack = 0;
72
73        self::$_noSpaceCombinators = [
74            '' => true,
75            ' ' => true,
76            '|' => true
77        ];
78    }
79
80    /**
81     * @param string $file
82     * @return void
83     */
84    public function addParsedFile( $file ) {
85        $this->imports[] = $file;
86    }
87
88    public function clone() {
89        $new_env = clone $this;
90        // NOTE: Match JavaScript by-ref behaviour for arrays
91        $new_env->imports =& $this->imports;
92        $new_env->importVisitorOnceMap =& $this->importVisitorOnceMap;
93        return $new_env;
94    }
95
96    /**
97     * @param string $file
98     * @return bool
99     */
100    public function isFileParsed( $file ) {
101        return in_array( $file, $this->imports );
102    }
103
104    public function copyEvalEnv( $frames = [] ) {
105        $new_env = new self();
106        $new_env->frames = $frames;
107        $new_env->importantScope = $this->importantScope;
108        $new_env->math = $this->math;
109        return $new_env;
110    }
111
112    /**
113     * @return bool
114     * @see less-3.13.1.js#Eval.prototype.isMathOn
115     */
116    public function isMathOn( $op = "" ) {
117        if ( !$this->mathOn ) {
118            return false;
119        }
120        if ( $op === '/' && $this->math !== $this::MATH_ALWAYS && !$this->parensStack ) {
121            return false;
122        }
123
124        if ( $this->math > $this::MATH_PARENS_DIVISION ) {
125            return (bool)$this->parensStack;
126        }
127        return true;
128    }
129
130    /**
131     * @see less-3.13.1.js#Eval.prototype.inParenthesis
132     */
133    public function inParenthesis() {
134        // Optimization: We don't need undefined/null, always have an array
135        $this->parensStack[] = true;
136    }
137
138    /**
139     * @see less-3.13.1.js#Eval.prototype.inParenthesis
140     */
141    public function outOfParenthesis() {
142        array_pop( $this->parensStack );
143    }
144
145    /**
146     * @param string $path
147     * @return bool
148     * @see less-2.5.3.js#Eval.isPathRelative
149     */
150    public static function isPathRelative( $path ) {
151        return !preg_match( '/^(?:[a-z-]+:|\/|#)/', $path );
152    }
153
154    /**
155     * Canonicalize a path by resolving references to '/./', '/../'
156     * Does not remove leading "../"
157     * @param string $path or url
158     * @return string Canonicalized path
159     */
160    public static function normalizePath( $path ) {
161        $segments = explode( '/', $path );
162        $segments = array_reverse( $segments );
163
164        $path = [];
165        $path_len = 0;
166
167        while ( $segments ) {
168            $segment = array_pop( $segments );
169            switch ( $segment ) {
170
171                case '.':
172                    break;
173
174                case '..':
175                    // @phan-suppress-next-line PhanTypeInvalidDimOffset False positive
176                    if ( !$path_len || ( $path[$path_len - 1] === '..' ) ) {
177                        $path[] = $segment;
178                        $path_len++;
179                    } else {
180                        array_pop( $path );
181                        $path_len--;
182                    }
183                    break;
184
185                default:
186                    $path[] = $segment;
187                    $path_len++;
188                    break;
189            }
190        }
191
192        return implode( '/', $path );
193    }
194
195    public function unshiftFrame( $frame ) {
196        array_unshift( $this->frames, $frame );
197    }
198
199    public function shiftFrame() {
200        return array_shift( $this->frames );
201    }
202
203}