Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.67% covered (success)
97.67%
42 / 43
90.91% covered (success)
90.91%
10 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
Less_Environment
97.67% covered (success)
97.67%
42 / 43
90.91% covered (success)
90.91%
10 / 11
19
0.00% covered (danger)
0.00%
0 / 1
 Init
100.00% covered (success)
100.00%
9 / 9
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%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 isMathOn
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 isPathRelative
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 callImportCallback
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 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
24    /** @var Less_Tree_Media[] */
25    public $mediaBlocks = [];
26    /** @var Less_Tree_Media[] */
27    public $mediaPath = [];
28
29    /** @var string[] */
30    public $imports = [];
31
32    /**
33     * This is the equivalent of `importVisitor.onceFileDetectionMap`
34     * as used by the dynamic `importNode.skip` function.
35     *
36     * @see less-2.5.3.js#ImportVisitor.prototype.onImported
37     * @var array<string,true>
38     */
39    public $importVisitorOnceMap = [];
40
41    public static $parensStack = 0;
42
43    public static $tabLevel = 0;
44
45    public static $lastRule = false;
46
47    public static $_noSpaceCombinators;
48
49    public static $mixin_stack = 0;
50
51    public $strictMath = false;
52
53    public $importCallback = null;
54
55    /**
56     * @var array
57     */
58    public $functions = [];
59
60    public function Init() {
61        self::$parensStack = 0;
62        self::$tabLevel = 0;
63        self::$lastRule = false;
64        self::$mixin_stack = 0;
65
66        self::$_noSpaceCombinators = [
67            '' => true,
68            ' ' => true,
69            '|' => true
70        ];
71    }
72
73    /**
74     * @param string $file
75     * @return void
76     */
77    public function addParsedFile( $file ) {
78        $this->imports[] = $file;
79    }
80
81    public function clone() {
82        $new_env = clone $this;
83        // NOTE: Match JavaScript by-ref behaviour for arrays
84        $new_env->imports =& $this->imports;
85        $new_env->importVisitorOnceMap =& $this->importVisitorOnceMap;
86        return $new_env;
87    }
88
89    /**
90     * @param string $file
91     * @return bool
92     */
93    public function isFileParsed( $file ) {
94        return in_array( $file, $this->imports );
95    }
96
97    public function copyEvalEnv( $frames = [] ) {
98        $new_env = new self();
99        $new_env->frames = $frames;
100        return $new_env;
101    }
102
103    /**
104     * @return bool
105     * @see Eval.prototype.isMathOn in less.js 3.0.0 https://github.com/less/less.js/blob/v3.0.0/dist/less.js#L1007
106     */
107    public function isMathOn() {
108        return $this->strictMath ? (bool)self::$parensStack : true;
109    }
110
111    /**
112     * @param string $path
113     * @return bool
114     * @see less-2.5.3.js#Eval.isPathRelative
115     */
116    public static function isPathRelative( $path ) {
117        return !preg_match( '/^(?:[a-z-]+:|\/|#)/', $path );
118    }
119
120    /**
121     * Apply legacy 'import_callback' option.
122     *
123     * See Less_Parser::$default_options to learn more about the 'import_callback' option.
124     * This option is deprecated in favour of Less_Parser::SetImportDirs.
125     *
126     * @param Less_Tree_Import $importNode
127     * @return array{0:string,1:string|null}|null Array containing path and (optional) uri or null
128     */
129    public function callImportCallback( Less_Tree_Import $importNode ) {
130        if ( is_callable( $this->importCallback ) ) {
131            return ( $this->importCallback )( $importNode );
132        }
133    }
134
135    /**
136     * Canonicalize a path by resolving references to '/./', '/../'
137     * Does not remove leading "../"
138     * @param string $path or url
139     * @return string Canonicalized path
140     */
141    public static function normalizePath( $path ) {
142        $segments = explode( '/', $path );
143        $segments = array_reverse( $segments );
144
145        $path = [];
146        $path_len = 0;
147
148        while ( $segments ) {
149            $segment = array_pop( $segments );
150            switch ( $segment ) {
151
152                case '.':
153                    break;
154
155                case '..':
156                    // @phan-suppress-next-line PhanTypeInvalidDimOffset False positive
157                    if ( !$path_len || ( $path[$path_len - 1] === '..' ) ) {
158                        $path[] = $segment;
159                        $path_len++;
160                    } else {
161                        array_pop( $path );
162                        $path_len--;
163                    }
164                    break;
165
166                default:
167                    $path[] = $segment;
168                    $path_len++;
169                    break;
170            }
171        }
172
173        return implode( '/', $path );
174    }
175
176    public function unshiftFrame( $frame ) {
177        array_unshift( $this->frames, $frame );
178    }
179
180    public function shiftFrame() {
181        return array_shift( $this->frames );
182    }
183
184}