Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
0.00% |
0 / 109 |
|
0.00% |
0 / 23 |
CRAP | |
0.00% |
0 / 1 |
| lessc | |
0.00% |
0 / 106 |
|
0.00% |
0 / 23 |
2862 | |
0.00% |
0 / 1 |
| __construct | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| setImportDir | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| addImportDir | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
| setFormatter | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| setPreserveComments | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| registerFunction | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| unregisterFunction | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| setVariables | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
| setVariable | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| unsetVariable | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| setOptions | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
| setOption | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| parse | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
12 | |||
| getOptions | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
12 | |||
| getImportDirs | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
| compile | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
20 | |||
| compileFile | |
0.00% |
0 / 22 |
|
0.00% |
0 / 1 |
42 | |||
| checkedCompile | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
12 | |||
| cachedCompile | |
0.00% |
0 / 20 |
|
0.00% |
0 / 1 |
156 | |||
| ccompile | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
| cexecute | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
| allParsedFiles | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| addParsedFile | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| 1 | <?php |
| 2 | /** |
| 3 | * This file provides the part of lessphp API (https://github.com/leafo/lessphp) |
| 4 | * to be a drop-in replacement for following products: |
| 5 | * - Drupal 7, by the less module v3.0+ (https://drupal.org/project/less) |
| 6 | * - Symfony 2 |
| 7 | */ |
| 8 | |
| 9 | // Register autoloader for non-composer installations |
| 10 | if ( !class_exists( 'Less_Parser' ) ) { |
| 11 | require_once __DIR__ . '/lib/Less/Autoloader.php'; |
| 12 | Less_Autoloader::register(); |
| 13 | } |
| 14 | |
| 15 | class lessc { |
| 16 | |
| 17 | /** @var string */ |
| 18 | public static $VERSION = Less_Version::less_version; |
| 19 | |
| 20 | /** @var string|string[] */ |
| 21 | public $importDir = ''; |
| 22 | /** @var array<string,int> */ |
| 23 | protected $allParsedFiles = []; |
| 24 | /** @var array<string,callable> */ |
| 25 | protected $libFunctions = []; |
| 26 | /** @var array */ |
| 27 | protected $registeredVars = []; |
| 28 | /** @var string */ |
| 29 | private $formatterName; |
| 30 | /** @var array<string,mixed> */ |
| 31 | private $options = []; |
| 32 | |
| 33 | public function __construct( $lessc = null, $sourceName = null ) { |
| 34 | } |
| 35 | |
| 36 | public function setImportDir( $dirs ) { |
| 37 | $this->importDir = (array)$dirs; |
| 38 | } |
| 39 | |
| 40 | public function addImportDir( $dir ) { |
| 41 | $this->importDir = (array)$this->importDir; |
| 42 | $this->importDir[] = $dir; |
| 43 | } |
| 44 | |
| 45 | public function setFormatter( $name ) { |
| 46 | $this->formatterName = $name; |
| 47 | } |
| 48 | |
| 49 | public function setPreserveComments( $preserve ) { |
| 50 | } |
| 51 | |
| 52 | public function registerFunction( $name, $func ) { |
| 53 | $this->libFunctions[$name] = $func; |
| 54 | } |
| 55 | |
| 56 | public function unregisterFunction( $name ) { |
| 57 | unset( $this->libFunctions[$name] ); |
| 58 | } |
| 59 | |
| 60 | public function setVariables( $variables ) { |
| 61 | foreach ( $variables as $name => $value ) { |
| 62 | $this->setVariable( $name, $value ); |
| 63 | } |
| 64 | } |
| 65 | |
| 66 | public function setVariable( $name, $value ) { |
| 67 | $this->registeredVars[$name] = $value; |
| 68 | } |
| 69 | |
| 70 | public function unsetVariable( $name ) { |
| 71 | unset( $this->registeredVars[$name] ); |
| 72 | } |
| 73 | |
| 74 | public function setOptions( $options ) { |
| 75 | foreach ( $options as $name => $value ) { |
| 76 | $this->setOption( $name, $value ); |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | public function setOption( $name, $value ) { |
| 81 | $this->options[$name] = $value; |
| 82 | } |
| 83 | |
| 84 | public function parse( $buffer, $presets = [] ) { |
| 85 | $this->setVariables( $presets ); |
| 86 | |
| 87 | $parser = new Less_Parser( $this->getOptions() ); |
| 88 | $parser->setImportDirs( $this->getImportDirs() ); |
| 89 | foreach ( $this->libFunctions as $name => $func ) { |
| 90 | $parser->registerFunction( $name, $func ); |
| 91 | } |
| 92 | $parser->parse( $buffer ); |
| 93 | if ( count( $this->registeredVars ) ) { |
| 94 | $parser->ModifyVars( $this->registeredVars ); |
| 95 | } |
| 96 | |
| 97 | return $parser->getCss(); |
| 98 | } |
| 99 | |
| 100 | protected function getOptions() { |
| 101 | $options = [ 'relativeUrls' => false ]; |
| 102 | switch ( $this->formatterName ) { |
| 103 | case 'compressed': |
| 104 | $options['compress'] = true; |
| 105 | break; |
| 106 | } |
| 107 | if ( is_array( $this->options ) ) { |
| 108 | $options = array_merge( $options, $this->options ); |
| 109 | } |
| 110 | return $options; |
| 111 | } |
| 112 | |
| 113 | protected function getImportDirs() { |
| 114 | $dirs_ = (array)$this->importDir; |
| 115 | $dirs = []; |
| 116 | foreach ( $dirs_ as $dir ) { |
| 117 | $dirs[$dir] = ''; |
| 118 | } |
| 119 | return $dirs; |
| 120 | } |
| 121 | |
| 122 | public function compile( $string, $name = null ) { |
| 123 | $oldImport = $this->importDir; |
| 124 | $this->importDir = (array)$this->importDir; |
| 125 | |
| 126 | $this->allParsedFiles = []; |
| 127 | |
| 128 | $parser = new Less_Parser( $this->getOptions() ); |
| 129 | $parser->SetImportDirs( $this->getImportDirs() ); |
| 130 | if ( count( $this->registeredVars ) ) { |
| 131 | $parser->ModifyVars( $this->registeredVars ); |
| 132 | } |
| 133 | foreach ( $this->libFunctions as $name => $func ) { |
| 134 | $parser->registerFunction( $name, $func ); |
| 135 | } |
| 136 | $parser->parse( $string ); |
| 137 | $out = $parser->getCss(); |
| 138 | |
| 139 | foreach ( $parser->getParsedFiles() as $file ) { |
| 140 | $this->addParsedFile( $file ); |
| 141 | } |
| 142 | |
| 143 | $this->importDir = $oldImport; |
| 144 | |
| 145 | return $out; |
| 146 | } |
| 147 | |
| 148 | public function compileFile( $fname, $outFname = null ) { |
| 149 | if ( !is_readable( $fname ) ) { |
| 150 | throw new Exception( 'load error: failed to find ' . $fname ); |
| 151 | } |
| 152 | |
| 153 | $pi = pathinfo( $fname ); |
| 154 | |
| 155 | $oldImport = $this->importDir; |
| 156 | |
| 157 | $this->importDir = (array)$this->importDir; |
| 158 | $this->importDir[] = Less_Parser::AbsPath( $pi['dirname'] ) . '/'; |
| 159 | |
| 160 | $this->allParsedFiles = []; |
| 161 | $this->addParsedFile( $fname ); |
| 162 | |
| 163 | $parser = new Less_Parser( $this->getOptions() ); |
| 164 | $parser->SetImportDirs( $this->getImportDirs() ); |
| 165 | if ( count( $this->registeredVars ) ) { |
| 166 | $parser->ModifyVars( $this->registeredVars ); |
| 167 | } |
| 168 | foreach ( $this->libFunctions as $name => $func ) { |
| 169 | $parser->registerFunction( $name, $func ); |
| 170 | } |
| 171 | $parser->parseFile( $fname ); |
| 172 | $out = $parser->getCss(); |
| 173 | |
| 174 | foreach ( $parser->getParsedFiles() as $file ) { |
| 175 | $this->addParsedFile( $file ); |
| 176 | } |
| 177 | |
| 178 | $this->importDir = $oldImport; |
| 179 | |
| 180 | if ( $outFname !== null ) { |
| 181 | return file_put_contents( $outFname, $out ); |
| 182 | } |
| 183 | |
| 184 | return $out; |
| 185 | } |
| 186 | |
| 187 | public function checkedCompile( $in, $out ) { |
| 188 | if ( !is_file( $out ) || filemtime( $in ) > filemtime( $out ) ) { |
| 189 | $this->compileFile( $in, $out ); |
| 190 | return true; |
| 191 | } |
| 192 | return false; |
| 193 | } |
| 194 | |
| 195 | /** |
| 196 | * Execute lessphp on a .less file or a lessphp cache structure |
| 197 | * |
| 198 | * The lessphp cache structure contains information about a specific |
| 199 | * less file having been parsed. It can be used as a hint for future |
| 200 | * calls to determine whether or not a rebuild is required. |
| 201 | * |
| 202 | * The cache structure contains two important keys that may be used |
| 203 | * externally: |
| 204 | * |
| 205 | * compiled: The final compiled CSS |
| 206 | * updated: The time (in seconds) the CSS was last compiled |
| 207 | * |
| 208 | * The cache structure is a plain-ol' PHP associative array and can |
| 209 | * be serialized and unserialized without a hitch. |
| 210 | * |
| 211 | * @param mixed $in Input |
| 212 | * @param bool $force Force rebuild? |
| 213 | * @return array lessphp cache structure |
| 214 | */ |
| 215 | public function cachedCompile( $in, $force = false ) { |
| 216 | // assume no root |
| 217 | $root = null; |
| 218 | |
| 219 | if ( is_string( $in ) ) { |
| 220 | $root = $in; |
| 221 | } elseif ( is_array( $in ) && isset( $in['root'] ) ) { |
| 222 | if ( $force || !isset( $in['files'] ) ) { |
| 223 | // If we are forcing a recompile or if for some reason the |
| 224 | // structure does not contain any file information we should |
| 225 | // specify the root to trigger a rebuild. |
| 226 | $root = $in['root']; |
| 227 | } elseif ( isset( $in['files'] ) && is_array( $in['files'] ) ) { |
| 228 | foreach ( $in['files'] as $fname => $ftime ) { |
| 229 | if ( !file_exists( $fname ) || filemtime( $fname ) > $ftime ) { |
| 230 | // One of the files we knew about previously has changed |
| 231 | // so we should look at our incoming root again. |
| 232 | $root = $in['root']; |
| 233 | break; |
| 234 | } |
| 235 | } |
| 236 | } |
| 237 | } else { |
| 238 | // TODO: Throw an exception? We got neither a string nor something |
| 239 | // that looks like a compatible lessphp cache structure. |
| 240 | return null; |
| 241 | } |
| 242 | |
| 243 | if ( $root !== null ) { |
| 244 | // If we have a root value which means we should rebuild. |
| 245 | $out = []; |
| 246 | $out['root'] = $root; |
| 247 | $out['compiled'] = $this->compileFile( $root ); |
| 248 | $out['files'] = $this->allParsedFiles; |
| 249 | $out['updated'] = time(); |
| 250 | return $out; |
| 251 | } else { |
| 252 | // No changes, pass back the structure |
| 253 | // we were given initially. |
| 254 | return $in; |
| 255 | } |
| 256 | } |
| 257 | |
| 258 | public function ccompile( $in, $out, $less = null ) { |
| 259 | if ( $less === null ) { |
| 260 | $less = new self; |
| 261 | } |
| 262 | return $less->checkedCompile( $in, $out ); |
| 263 | } |
| 264 | |
| 265 | public static function cexecute( $in, $force = false, $less = null ) { |
| 266 | if ( $less === null ) { |
| 267 | $less = new self; |
| 268 | } |
| 269 | return $less->cachedCompile( $in, $force ); |
| 270 | } |
| 271 | |
| 272 | public function allParsedFiles() { |
| 273 | return $this->allParsedFiles; |
| 274 | } |
| 275 | |
| 276 | protected function addParsedFile( $file ) { |
| 277 | $this->allParsedFiles[Less_Parser::AbsPath( $file )] = filemtime( $file ); |
| 278 | } |
| 279 | } |