@ -0,0 +1,70 @@ | |||
# 3.1.0 | |||
- [All Changes](https://github.com/wikimedia/less.php/compare/v3.0.0...v3.1.0) | |||
* PHP 8.0 support: Drop use of curly braces for sub-string eval (James D. Forrester) | |||
* Make `Directive::__construct` $rules arg optional (fix PHP 7.4 warning) (Sam Reed) | |||
* ProcessExtends: Improve performance by using a map for selectors and parents (Andrey Legayev) | |||
* build: Run CI tests on PHP 8.0 too (James D. Forrester) | |||
* code: Fix PSR12.Properties.ConstantVisibility.NotFound (Sam Reed) | |||
# 3.0.0 | |||
- [All Changes](https://github.com/wikimedia/less.php/compare/v2.0.0...v3.0.0) | |||
- Raise PHP requirement from 7.1 to 7.2.9 (James Forrester) | |||
- build: Upgrade phpunit to ^8.5 and make pass (James Forrester) | |||
- build: Install php-parallel-lint (James Forrester) | |||
- build: Install minus-x and make pass (James Forrester) | |||
# 2.0.0 | |||
- [All Changes](https://github.com/wikimedia/less.php/compare/1.8.2...v2.0.0) | |||
- Relax PHP requirement down to 7.1, from 7.2.9 (Franz Liedke) | |||
- Reflect recent breaking changes properly with the semantic versioning (James Forrester) | |||
# 1.8.2 | |||
- [All Changes](https://github.com/wikimedia/less.php/compare/1.8.1...1.8.2) | |||
- Require PHP 7.2.9+, up from 5.3+ (James Forrester) | |||
- Release: Update Version.php with the current release ID (COBadger) | |||
- Fix access array offset on value of type null (Michele Locati) | |||
- Fixed test suite on PHP 7.4 (Sergei Morozov) | |||
- docs: Fix 1.8.1 "All changes" link (Timo Tijhof) | |||
# 1.8.1 | |||
- [All Changes](https://github.com/wikimedia/less.php/compare/v1.8.0...1.8.1) | |||
- Another PHP 7.3 compatibility tweak | |||
# 1.8.0 | |||
- [All Changes](https://github.com/Asenar/less.php/compare/v1.7.0.13...v1.8.0) | |||
- Wikimedia fork | |||
- Supports up to PHP 7.3 | |||
- No longer tested against PHP 5, though it's still remains allowed in `composer.json` for HHVM compatibility | |||
- Switched to [semantic versioning](https://semver.org/), hence version numbers now use 3 digits | |||
# 1.7.0.13 | |||
- [All Changes](https://github.com/Asenar/less.php/compare/v1.7.0.12...v1.7.0.13) | |||
- Fix composer.json (PSR-4 was invalid) | |||
# 1.7.0.12 | |||
- [All Changes](https://github.com/Asenar/less.php/compare/v1.7.0.11...v1.7.0.12) | |||
- set bin/lessc bit executable | |||
- Add 'gettingVariables' method in Less_Parser | |||
# 1.7.0.11 | |||
- [All Changes](https://github.com/Asenar/less.php/compare/v1.7.0.10...v1.7.0.11) | |||
- Fix realpath issue (windows) | |||
- Set Less_Tree_Call property back to public ( Fix 258 266 267 issues from oyejorge/less.php) | |||
# 1.7.0.10 | |||
- [All Changes](https://github.com/oyejorge/less.php/compare/v1.7.0.9...v1.7.10) | |||
- Add indentation option | |||
- Add 'optional' modifier for @import | |||
- fix $color in Exception messages | |||
- don't use set_time_limit when running cli | |||
- take relative-url into account when building the cache filename | |||
- urlArgs should be string no array() | |||
- add bug-report fixtures [#6dc898f](https://github.com/oyejorge/less.php/commit/6dc898f5d75b447464906bdf19d79c2e19d95e33) | |||
- fix #269, missing on NameValue type [#a8dac63](https://github.com/oyejorge/less.php/commit/a8dac63d93fb941c54fb78b12588abf635747c1b) | |||
# 1.7.0.9 | |||
- [All Changes](https://github.com/oyejorge/less.php/compare/v1.7.0.8...v1.7.0.9) | |||
- Remove space at beginning of Version.php | |||
- Revert require() paths in test interface |
@ -0,0 +1,178 @@ | |||
Apache License | |||
Version 2.0, January 2004 | |||
http://www.apache.org/licenses/ | |||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | |||
1. Definitions. | |||
"License" shall mean the terms and conditions for use, reproduction, | |||
and distribution as defined by Sections 1 through 9 of this document. | |||
"Licensor" shall mean the copyright owner or entity authorized by | |||
the copyright owner that is granting the License. | |||
"Legal Entity" shall mean the union of the acting entity and all | |||
other entities that control, are controlled by, or are under common | |||
control with that entity. For the purposes of this definition, | |||
"control" means (i) the power, direct or indirect, to cause the | |||
direction or management of such entity, whether by contract or | |||
otherwise, or (ii) ownership of fifty percent (50%) or more of the | |||
outstanding shares, or (iii) beneficial ownership of such entity. | |||
"You" (or "Your") shall mean an individual or Legal Entity | |||
exercising permissions granted by this License. | |||
"Source" form shall mean the preferred form for making modifications, | |||
including but not limited to software source code, documentation | |||
source, and configuration files. | |||
"Object" form shall mean any form resulting from mechanical | |||
transformation or translation of a Source form, including but | |||
not limited to compiled object code, generated documentation, | |||
and conversions to other media types. | |||
"Work" shall mean the work of authorship, whether in Source or | |||
Object form, made available under the License, as indicated by a | |||
copyright notice that is included in or attached to the work | |||
(an example is provided in the Appendix below). | |||
"Derivative Works" shall mean any work, whether in Source or Object | |||
form, that is based on (or derived from) the Work and for which the | |||
editorial revisions, annotations, elaborations, or other modifications | |||
represent, as a whole, an original work of authorship. For the purposes | |||
of this License, Derivative Works shall not include works that remain | |||
separable from, or merely link (or bind by name) to the interfaces of, | |||
the Work and Derivative Works thereof. | |||
"Contribution" shall mean any work of authorship, including | |||
the original version of the Work and any modifications or additions | |||
to that Work or Derivative Works thereof, that is intentionally | |||
submitted to Licensor for inclusion in the Work by the copyright owner | |||
or by an individual or Legal Entity authorized to submit on behalf of | |||
the copyright owner. For the purposes of this definition, "submitted" | |||
means any form of electronic, verbal, or written communication sent | |||
to the Licensor or its representatives, including but not limited to | |||
communication on electronic mailing lists, source code control systems, | |||
and issue tracking systems that are managed by, or on behalf of, the | |||
Licensor for the purpose of discussing and improving the Work, but | |||
excluding communication that is conspicuously marked or otherwise | |||
designated in writing by the copyright owner as "Not a Contribution." | |||
"Contributor" shall mean Licensor and any individual or Legal Entity | |||
on behalf of whom a Contribution has been received by Licensor and | |||
subsequently incorporated within the Work. | |||
2. Grant of Copyright License. Subject to the terms and conditions of | |||
this License, each Contributor hereby grants to You a perpetual, | |||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |||
copyright license to reproduce, prepare Derivative Works of, | |||
publicly display, publicly perform, sublicense, and distribute the | |||
Work and such Derivative Works in Source or Object form. | |||
3. Grant of Patent License. Subject to the terms and conditions of | |||
this License, each Contributor hereby grants to You a perpetual, | |||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |||
(except as stated in this section) patent license to make, have made, | |||
use, offer to sell, sell, import, and otherwise transfer the Work, | |||
where such license applies only to those patent claims licensable | |||
by such Contributor that are necessarily infringed by their | |||
Contribution(s) alone or by combination of their Contribution(s) | |||
with the Work to which such Contribution(s) was submitted. If You | |||
institute patent litigation against any entity (including a | |||
cross-claim or counterclaim in a lawsuit) alleging that the Work | |||
or a Contribution incorporated within the Work constitutes direct | |||
or contributory patent infringement, then any patent licenses | |||
granted to You under this License for that Work shall terminate | |||
as of the date such litigation is filed. | |||
4. Redistribution. You may reproduce and distribute copies of the | |||
Work or Derivative Works thereof in any medium, with or without | |||
modifications, and in Source or Object form, provided that You | |||
meet the following conditions: | |||
(a) You must give any other recipients of the Work or | |||
Derivative Works a copy of this License; and | |||
(b) You must cause any modified files to carry prominent notices | |||
stating that You changed the files; and | |||
(c) You must retain, in the Source form of any Derivative Works | |||
that You distribute, all copyright, patent, trademark, and | |||
attribution notices from the Source form of the Work, | |||
excluding those notices that do not pertain to any part of | |||
the Derivative Works; and | |||
(d) If the Work includes a "NOTICE" text file as part of its | |||
distribution, then any Derivative Works that You distribute must | |||
include a readable copy of the attribution notices contained | |||
within such NOTICE file, excluding those notices that do not | |||
pertain to any part of the Derivative Works, in at least one | |||
of the following places: within a NOTICE text file distributed | |||
as part of the Derivative Works; within the Source form or | |||
documentation, if provided along with the Derivative Works; or, | |||
within a display generated by the Derivative Works, if and | |||
wherever such third-party notices normally appear. The contents | |||
of the NOTICE file are for informational purposes only and | |||
do not modify the License. You may add Your own attribution | |||
notices within Derivative Works that You distribute, alongside | |||
or as an addendum to the NOTICE text from the Work, provided | |||
that such additional attribution notices cannot be construed | |||
as modifying the License. | |||
You may add Your own copyright statement to Your modifications and | |||
may provide additional or different license terms and conditions | |||
for use, reproduction, or distribution of Your modifications, or | |||
for any such Derivative Works as a whole, provided Your use, | |||
reproduction, and distribution of the Work otherwise complies with | |||
the conditions stated in this License. | |||
5. Submission of Contributions. Unless You explicitly state otherwise, | |||
any Contribution intentionally submitted for inclusion in the Work | |||
by You to the Licensor shall be under the terms and conditions of | |||
this License, without any additional terms or conditions. | |||
Notwithstanding the above, nothing herein shall supersede or modify | |||
the terms of any separate license agreement you may have executed | |||
with Licensor regarding such Contributions. | |||
6. Trademarks. This License does not grant permission to use the trade | |||
names, trademarks, service marks, or product names of the Licensor, | |||
except as required for reasonable and customary use in describing the | |||
origin of the Work and reproducing the content of the NOTICE file. | |||
7. Disclaimer of Warranty. Unless required by applicable law or | |||
agreed to in writing, Licensor provides the Work (and each | |||
Contributor provides its Contributions) on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | |||
implied, including, without limitation, any warranties or conditions | |||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | |||
PARTICULAR PURPOSE. You are solely responsible for determining the | |||
appropriateness of using or redistributing the Work and assume any | |||
risks associated with Your exercise of permissions under this License. | |||
8. Limitation of Liability. In no event and under no legal theory, | |||
whether in tort (including negligence), contract, or otherwise, | |||
unless required by applicable law (such as deliberate and grossly | |||
negligent acts) or agreed to in writing, shall any Contributor be | |||
liable to You for damages, including any direct, indirect, special, | |||
incidental, or consequential damages of any character arising as a | |||
result of this License or out of the use or inability to use the | |||
Work (including but not limited to damages for loss of goodwill, | |||
work stoppage, computer failure or malfunction, or any and all | |||
other commercial damages or losses), even if such Contributor | |||
has been advised of the possibility of such damages. | |||
9. Accepting Warranty or Additional Liability. While redistributing | |||
the Work or Derivative Works thereof, You may choose to offer, | |||
and charge a fee for, acceptance of support, warranty, indemnity, | |||
or other liability obligations and/or rights consistent with this | |||
License. However, in accepting such obligations, You may act only | |||
on Your own behalf and on Your sole responsibility, not on behalf | |||
of any other Contributor, and only if You agree to indemnify, | |||
defend, and hold each Contributor harmless for any liability | |||
incurred by, or claims asserted against, such Contributor by reason | |||
of your accepting any such warranty or additional liability. | |||
END OF TERMS AND CONDITIONS | |||
@ -0,0 +1,315 @@ | |||
[](https://github.com/wikimedia/less.php/actions) | |||
[Less.php](http://lessphp.typesettercms.com) | |||
======== | |||
This is the Wikimedia fork of a PHP port of the official LESS processor <http://lesscss.org>. | |||
* [About](#about) | |||
* [Installation](#installation) | |||
* [Basic Use](#basic-use) | |||
* [Caching](#caching) | |||
* [Source Maps](#source-maps) | |||
* [Command Line](#command-line) | |||
* [Integration with other projects](#integration-with-other-projects) | |||
* [Transitioning from Leafo/lessphp](#transitioning-from-leafolessphp) | |||
* [Credits](#credits) | |||
About | |||
--- | |||
The code structure of less.php mirrors that of the official processor which helps us ensure compatibility and allows for easy maintenance. | |||
Please note, there are a few unsupported LESS features: | |||
- Evaluation of JavaScript expressions within back-ticks (for obvious reasons). | |||
- Definition of custom functions. | |||
Installation | |||
--- | |||
You can install the library with Composer or manually. | |||
#### Composer | |||
1. [Install Composer](https://getcomposer.org/download/) | |||
2. Run `composer require wikimedia/less.php` | |||
#### Manually From Release | |||
Step 1. [Download a release](https://github.com/wikimedia/less.php/releases) and upload the PHP files to your server. | |||
Step 2. Include the library: | |||
```php | |||
require_once '[path to less.php]/lib/Less/Autoloader.php'; | |||
Less_Autoloader::register(); | |||
``` | |||
Basic Use | |||
--- | |||
#### Parsing Strings | |||
```php | |||
$parser = new Less_Parser(); | |||
$parser->parse( '@color: #4D926F; #header { color: @color; } h2 { color: @color; }' ); | |||
$css = $parser->getCss(); | |||
``` | |||
#### Parsing LESS Files | |||
The parseFile() function takes two arguments: | |||
1. The absolute path of the .less file to be parsed | |||
2. The url root to prepend to any relative image or @import urls in the .less file. | |||
```php | |||
$parser = new Less_Parser(); | |||
$parser->parseFile( '/var/www/mysite/bootstrap.less', 'http://example.com/mysite/' ); | |||
$css = $parser->getCss(); | |||
``` | |||
#### Handling Invalid LESS | |||
An exception will be thrown if the compiler encounters invalid LESS. | |||
```php | |||
try{ | |||
$parser = new Less_Parser(); | |||
$parser->parseFile( '/var/www/mysite/bootstrap.less', 'http://example.com/mysite/' ); | |||
$css = $parser->getCss(); | |||
}catch(Exception $e){ | |||
$error_message = $e->getMessage(); | |||
} | |||
``` | |||
#### Parsing Multiple Sources | |||
less.php can parse multiple sources to generate a single CSS file. | |||
```php | |||
$parser = new Less_Parser(); | |||
$parser->parseFile( '/var/www/mysite/bootstrap.less', '/mysite/' ); | |||
$parser->parse( '@color: #4D926F; #header { color: @color; } h2 { color: @color; }' ); | |||
$css = $parser->getCss(); | |||
``` | |||
#### Getting Info About The Parsed Files | |||
less.php can tell you which .less files were imported and parsed. | |||
```php | |||
$parser = new Less_Parser(); | |||
$parser->parseFile( '/var/www/mysite/bootstrap.less', '/mysite/' ); | |||
$css = $parser->getCss(); | |||
$imported_files = $parser->allParsedFiles(); | |||
``` | |||
#### Compressing Output | |||
You can tell less.php to remove comments and whitespace to generate minimized CSS files. | |||
```php | |||
$options = array( 'compress'=>true ); | |||
$parser = new Less_Parser( $options ); | |||
$parser->parseFile( '/var/www/mysite/bootstrap.less', '/mysite/' ); | |||
$css = $parser->getCss(); | |||
``` | |||
#### Getting Variables | |||
You can use the getVariables() method to get an all variables defined and | |||
their value in a php associative array. Note that LESS has to be previously | |||
compiled. | |||
```php | |||
$parser = new Less_Parser; | |||
$parser->parseFile( '/var/www/mysite/bootstrap.less'); | |||
$css = $parser->getCss(); | |||
$variables = $parser->getVariables(); | |||
``` | |||
#### Setting Variables | |||
You can use the ModifyVars() method to customize your CSS if you have variables stored in PHP associative arrays. | |||
```php | |||
$parser = new Less_Parser(); | |||
$parser->parseFile( '/var/www/mysite/bootstrap.less', '/mysite/' ); | |||
$parser->ModifyVars( array('font-size-base'=>'16px') ); | |||
$css = $parser->getCss(); | |||
``` | |||
#### Import Directories | |||
By default, less.php will look for @imports in the directory of the file passed to parseFile(). | |||
If you're using parse() or if @imports reside in different directories, you can tell less.php where to look. | |||
```php | |||
$directories = array( '/var/www/mysite/bootstrap/' => '/mysite/bootstrap/' ); | |||
$parser = new Less_Parser(); | |||
$parser->SetImportDirs( $directories ); | |||
$parser->parseFile( '/var/www/mysite/theme.less', '/mysite/' ); | |||
$css = $parser->getCss(); | |||
``` | |||
Caching | |||
--- | |||
Compiling LESS code into CSS is a time consuming process, caching your results is highly recommended. | |||
#### Caching CSS | |||
Use the Less_Cache class to save and reuse the results of compiled LESS files. | |||
This method will check the modified time and size of each LESS file (including imported files) and regenerate a new CSS file when changes are found. | |||
Note: When changes are found, this method will return a different file name for the new cached content. | |||
```php | |||
$less_files = array( '/var/www/mysite/bootstrap.less' => '/mysite/' ); | |||
$options = array( 'cache_dir' => '/var/www/writable_folder' ); | |||
$css_file_name = Less_Cache::Get( $less_files, $options ); | |||
$compiled = file_get_contents( '/var/www/writable_folder/'.$css_file_name ); | |||
``` | |||
#### Caching CSS With Variables | |||
Passing options to Less_Cache::Get() | |||
```php | |||
$less_files = array( '/var/www/mysite/bootstrap.less' => '/mysite/' ); | |||
$options = array( 'cache_dir' => '/var/www/writable_folder' ); | |||
$variables = array( 'width' => '100px' ); | |||
$css_file_name = Less_Cache::Get( $less_files, $options, $variables ); | |||
$compiled = file_get_contents( '/var/www/writable_folder/'.$css_file_name ); | |||
``` | |||
#### Parser Caching | |||
less.php will save serialized parser data for each .less file if a writable folder is passed to the SetCacheDir() method. | |||
Note: This feature only caches intermediate parsing results to improve the performance of repeated CSS generation. | |||
Your application should cache any CSS generated by less.php. | |||
```php | |||
$options = array('cache_dir'=>'/var/www/writable_folder'); | |||
$parser = new Less_Parser( $options ); | |||
$parser->parseFile( '/var/www/mysite/bootstrap.less', '/mysite/' ); | |||
$css = $parser->getCss(); | |||
``` | |||
You can specify the caching technique used by changing the ```cache_method``` option. Supported methods are: | |||
* ```php```: Creates valid PHP files which can be included without any changes (default method). | |||
* ```var_export```: Like "php", but using PHP's ```var_export()``` function without any optimizations. | |||
It's recommended to use "php" instead. | |||
* ```serialize```: Faster, but pretty memory-intense. | |||
* ```callback```: Use custom callback functions to implement your own caching method. Give the "cache_callback_get" and | |||
"cache_callback_set" options with callables (see PHP's ```call_user_func()``` and ```is_callable()``` functions). less.php | |||
will pass the parser object (class ```Less_Parser```), the path to the parsed .less file ("/some/path/to/file.less") and | |||
an identifier that will change every time the .less file is modified. The ```get``` callback must return the ruleset | |||
(an array with ```Less_Tree``` objects) provided as fourth parameter of the ```set``` callback. If something goes wrong, | |||
return ```NULL``` (cache doesn't exist) or ```FALSE```. | |||
Source Maps | |||
--- | |||
Less.php supports v3 sourcemaps | |||
#### Inline | |||
The sourcemap will be appended to the generated CSS file. | |||
```php | |||
$options = array( 'sourceMap' => true ); | |||
$parser = new Less_Parser($options); | |||
$parser->parseFile( '/var/www/mysite/bootstrap.less', '/mysite/' ); | |||
$css = $parser->getCss(); | |||
``` | |||
#### Saving to Map File | |||
```php | |||
$options = array( | |||
'sourceMap' => true, | |||
'sourceMapWriteTo' => '/var/www/mysite/writable_folder/filename.map', | |||
'sourceMapURL' => '/mysite/writable_folder/filename.map', | |||
); | |||
$parser = new Less_Parser($options); | |||
$parser->parseFile( '/var/www/mysite/bootstrap.less', '/mysite/' ); | |||
$css = $parser->getCss(); | |||
``` | |||
Command line | |||
--- | |||
An additional script has been included to use the compiler from the command line. | |||
In the simplest invocation, you specify an input file and the compiled CSS is written to standard out: | |||
``` | |||
$ lessc input.less > output.css | |||
``` | |||
By using the -w flag you can watch a specified input file and have it compile as needed to the output file: | |||
``` | |||
$ lessc -w input.less output.css | |||
``` | |||
Errors from watch mode are written to standard out. | |||
For more help, run `lessc --help` | |||
Integration with other projects | |||
--- | |||
#### Drupal 7 | |||
This library can be used as drop-in replacement of lessphp to work with [Drupal 7 less module](https://drupal.org/project/less). | |||
How to install: | |||
1. [Download the less.php source code](https://github.com/wikimedia/less.php/archive/master.zip) and unzip it so that 'lessc.inc.php' is located at 'sites/all/libraries/lessphp/lessc.inc.php'. | |||
2. Download and install [Drupal 7 less module](https://drupal.org/project/less) as usual. | |||
3. That's it :) | |||
#### JBST WordPress theme | |||
JBST has a built-in LESS compiler based on lessphp. Customize your WordPress theme with LESS. | |||
How to use / install: | |||
1. [Download the latest release](https://github.com/bassjobsen/jamedo-bootstrap-start-theme) copy the files to your {wordpress/}wp-content/themes folder and activate it. | |||
2. Find the compiler under Appearance > LESS Compiler in your WordPress dashboard | |||
3. Enter your LESS code in the text area and press (re)compile | |||
Use the built-in compiler to: | |||
- set any [Bootstrap](http://getbootstrap.com/customize/) variable or use Bootstrap's mixins: | |||
-`@navbar-default-color: blue;` | |||
- create a custom button: `.btn-custom { | |||
.button-variant(white; red; blue); | |||
}` | |||
- set any built-in LESS variable: for example `@footer_bg_color: black;` sets the background color of the footer to black | |||
- use built-in mixins: - add a custom font: `.include-custom-font(@family: arial,@font-path, @path: @custom-font-dir, @weight: normal, @style: normal);` | |||
The compiler can also be downloaded as [plugin](http://wordpress.org/plugins/wp-less-to-css/) | |||
#### WordPress | |||
This simple plugin will simply make the library available to other plugins and themes and can be used as a dependency using the [TGM Library](http://tgmpluginactivation.com/) | |||
How to install: | |||
1. Install the plugin from your WordPress Dashboard: http://wordpress.org/plugins/lessphp/ | |||
2. That's it :) | |||
Transitioning from Leafo/lessphp | |||
--- | |||
Projects looking for an easy transition from leafo/lessphp can use the lessc.inc.php adapter. To use, [Download the less.php source code](https://github.com/wikimedia/less.php/archive/master.zip) and unzip the files into your project so that the new 'lessc.inc.php' replaces the existing 'lessc.inc.php'. | |||
Note, the 'setPreserveComments' will no longer have any effect on the compiled LESS. | |||
Credits | |||
--- | |||
less.php was originally ported to PHP by [Matt Agar](https://github.com/agar) and then updated by [Martin Jantoลกoviฤ](https://github.com/Mordred). This Wikimedia-maintained fork was split off from [Josh Schmidt's version](https://github.com/oyejorge/less.php). | |||
@ -0,0 +1,191 @@ | |||
#!/usr/bin/env php | |||
<?php | |||
require_once dirname(__FILE__) . '/../lib/Less/Autoloader.php'; | |||
Less_Autoloader::register(); | |||
// Create our environment | |||
$env = array('compress' => false, 'relativeUrls' => false); | |||
$silent = false; | |||
$watch = false; | |||
$rootpath = ''; | |||
// Check for arguments | |||
array_shift($argv); | |||
if (!count($argv)) { | |||
$argv[] = '-h'; | |||
} | |||
// parse arguments | |||
foreach ($argv as $key => $arg) { | |||
if (preg_match('/^--?([a-z][0-9a-z-]*)(?:=([^\s]+))?$/i', $arg, $matches)) { | |||
$option = $matches[1]; | |||
$value = isset($matches[2]) ? $matches[2] : false; | |||
unset($argv[$key]); | |||
switch ($option) { | |||
case 'h': | |||
case 'help': | |||
echo <<<EOD | |||
Usage: lessc [options] sources [destination] | |||
-h, --help Print help (this message) and exit. | |||
-s, --silent Suppress output of error messages. | |||
-v, --version Print version number and exit. | |||
-x, --compress Compress output by removing some whitespaces. | |||
--include-path=PATHS Set include paths. Separated by `:'. Use `;' on Windows. | |||
--strict-imports Force evaluation of imports. | |||
-sm=on|off Turn on or off strict math, where in strict mode, math | |||
--strict-math=on|off requires brackets. This option may default to on and then | |||
be removed in the future. | |||
-su=on|off Allow mixed units, e.g. 1px+1em or 1px*1px which have units | |||
--strict-units=on|off that cannot be represented. | |||
-ru, --relative-urls re-write relative urls to the base less file. | |||
-rp, --rootpath=URL Set rootpath for url rewriting in relative imports and urls. | |||
Works with or without the relative-urls option. | |||
-w, --watch Watch input files for changes. | |||
EOD; | |||
exit; | |||
case 's': | |||
case 'silent': | |||
$silent = true; | |||
break; | |||
case 'w': | |||
case 'watch': | |||
$watch = true; | |||
break; | |||
case 'v': | |||
case 'version': | |||
echo "lessc " . Less_Version::version . " (less.php)\n\n"; | |||
exit; | |||
case 'rp': | |||
case 'rootpath': | |||
$rootpath = $value; | |||
break; | |||
//parser options | |||
case 'compress': | |||
$env['compress'] = true; | |||
break; | |||
case 'ru': | |||
case 'relative-urls': | |||
$env['relativeUrls'] = true; | |||
break; | |||
case 'su': | |||
case 'strict-units': | |||
$env['strictUnits'] = ($value === 'on'); | |||
break; | |||
case 'sm': | |||
case 'strict-math': | |||
$env['strictMath'] = ($value === 'on'); | |||
break; | |||
case 'x': | |||
case 'include-path': | |||
$env['import_dirs'] = preg_split('#;|\:#', $value); | |||
break; | |||
} | |||
} | |||
} | |||
if (count($argv) > 1) { | |||
$output = array_pop($argv); | |||
$inputs = $argv; | |||
} | |||
else { | |||
$inputs = $argv; | |||
$output = false; | |||
} | |||
if (!count($inputs)) { | |||
echo("lessc: no input files\n"); | |||
exit; | |||
} | |||
if ($watch) { | |||
if (!$output) { | |||
echo("lessc: you must specify the output file if --watch is given\n"); | |||
exit; | |||
} | |||
$lastAction = 0; | |||
echo("lessc: watching input files\n"); | |||
while (1) { | |||
clearstatcache(); | |||
$updated = false; | |||
foreach ($inputs as $input) { | |||
if ($input == '-') { | |||
if (count($inputs) == 1) { | |||
echo("lessc: during watching files is not possible to watch stdin\n"); | |||
exit; | |||
} | |||
else { | |||
continue; | |||
} | |||
} | |||
if (filemtime($input) > $lastAction) { | |||
$updated = true; | |||
break; | |||
} | |||
} | |||
if ($updated) { | |||
$lastAction = time(); | |||
$parser = new Less_Parser($env); | |||
foreach ($inputs as $input) { | |||
try { | |||
$parser->parseFile($input, $rootpath); | |||
} | |||
catch (Exception $e) { | |||
echo("lessc: " . $e->getMessage() . " \n"); | |||
continue; // Invalid processing | |||
} | |||
} | |||
file_put_contents($output, $parser->getCss()); | |||
echo("lessc: output file recompiled\n"); | |||
} | |||
sleep(1); | |||
} | |||
} | |||
else { | |||
$parser = new Less_Parser($env); | |||
foreach ($inputs as $input) { | |||
if ($input == '-') { | |||
$content = file_get_contents('php://stdin'); | |||
$parser->parse($content); | |||
} | |||
else { | |||
try { | |||
$parser->parseFile($input); | |||
} | |||
catch (Exception $e) { | |||
if (!$silent) { | |||
echo("lessc: " . ((string)$e) . " \n"); | |||
} | |||
} | |||
} | |||
} | |||
if ($output) { | |||
file_put_contents($output, $parser->getCss()); | |||
} | |||
else { | |||
echo $parser->getCss(); | |||
} | |||
} |
@ -0,0 +1,49 @@ | |||
{ | |||
"name": "wikimedia/less.php", | |||
"description": "PHP port of the Javascript version of LESS http://lesscss.org (Originally maintained by Josh Schmidt)", | |||
"keywords": [ "less", "css", "php", "stylesheet", "less.js", "lesscss" ], | |||
"license": "Apache-2.0", | |||
"authors": [ | |||
{ | |||
"name": "Josh Schmidt", | |||
"homepage": "https://github.com/oyejorge" | |||
}, | |||
{ | |||
"name": "Matt Agar", | |||
"homepage": "https://github.com/agar" | |||
}, | |||
{ | |||
"name": "Martin Jantoลกoviฤ", | |||
"homepage": "https://github.com/Mordred" | |||
} | |||
], | |||
"require": { | |||
"php": ">=7.2.9" | |||
}, | |||
"require-dev": { | |||
"mediawiki/mediawiki-codesniffer": "34.0.0", | |||
"mediawiki/minus-x": "1.0.0", | |||
"php-parallel-lint/php-console-highlighter": "0.5.0", | |||
"php-parallel-lint/php-parallel-lint": "1.2.0", | |||
"phpunit/phpunit": "^8.5" | |||
}, | |||
"scripts": { | |||
"test": [ | |||
"parallel-lint . --exclude vendor", | |||
"phpcs -sp", | |||
"phpunit", | |||
"minus-x check ." | |||
], | |||
"fix": [ | |||
"minus-x fix .", | |||
"phpcbf" | |||
] | |||
}, | |||
"autoload": { | |||
"psr-0": { "Less": "lib/" }, | |||
"classmap": ["lessc.inc.php"] | |||
}, | |||
"bin": [ | |||
"bin/lessc" | |||
] | |||
} |
@ -0,0 +1,274 @@ | |||
<?php | |||
/** | |||
* This file provides the part of lessphp API (https://github.com/leafo/lessphp) | |||
* to be a drop-in replacement for following products: | |||
* - Drupal 7, by the less module v3.0+ (https://drupal.org/project/less) | |||
* - Symfony 2 | |||
*/ | |||
// Register autoloader for non-composer installations | |||
if ( !class_exists( 'Less_Parser' ) ) { | |||
require_once __DIR__ . '/lib/Less/Autoloader.php'; | |||
Less_Autoloader::register(); | |||
} | |||
class lessc { | |||
static public $VERSION = Less_Version::less_version; | |||
public $importDir = ''; | |||
protected $allParsedFiles = array(); | |||
protected $libFunctions = array(); | |||
protected $registeredVars = array(); | |||
private $formatterName; | |||
private $options = array(); | |||
public function __construct( $lessc = null, $sourceName = null ) { | |||
} | |||
public function setImportDir( $dirs ) { | |||
$this->importDir = (array)$dirs; | |||
} | |||
public function addImportDir( $dir ) { | |||
$this->importDir = (array)$this->importDir; | |||
$this->importDir[] = $dir; | |||
} | |||
public function setFormatter( $name ) { | |||
$this->formatterName = $name; | |||
} | |||
public function setPreserveComments( $preserve ) { | |||
} | |||
public function registerFunction( $name, $func ) { | |||
$this->libFunctions[$name] = $func; | |||
} | |||
public function unregisterFunction( $name ) { | |||
unset( $this->libFunctions[$name] ); | |||
} | |||
public function setVariables( $variables ) { | |||
foreach ( $variables as $name => $value ) { | |||
$this->setVariable( $name, $value ); | |||
} | |||
} | |||
public function setVariable( $name, $value ) { | |||
$this->registeredVars[$name] = $value; | |||
} | |||
public function unsetVariable( $name ) { | |||
unset( $this->registeredVars[$name] ); | |||
} | |||
public function setOptions( $options ) { | |||
foreach ( $options as $name => $value ) { | |||
$this->setOption( $name, $value ); | |||
} | |||
} | |||
public function setOption( $name, $value ) { | |||
$this->options[$name] = $value; | |||
} | |||
public function parse( $buffer, $presets = array() ) { | |||
$this->setVariables( $presets ); | |||
$parser = new Less_Parser( $this->getOptions() ); | |||
$parser->setImportDirs( $this->getImportDirs() ); | |||
foreach ( $this->libFunctions as $name => $func ) { | |||
$parser->registerFunction( $name, $func ); | |||
} | |||
$parser->parse( $buffer ); | |||
if ( count( $this->registeredVars ) ) { | |||
$parser->ModifyVars( $this->registeredVars ); | |||
} | |||
return $parser->getCss(); | |||
} | |||
protected function getOptions() { | |||
$options = array( 'relativeUrls' => false ); | |||
switch ( $this->formatterName ) { | |||
case 'compressed': | |||
$options['compress'] = true; | |||
break; | |||
} | |||
if ( is_array( $this->options ) ) { | |||
$options = array_merge( $options, $this->options ); | |||
} | |||
return $options; | |||
} | |||
protected function getImportDirs() { | |||
$dirs_ = (array)$this->importDir; | |||
$dirs = array(); | |||
foreach ( $dirs_ as $dir ) { | |||
$dirs[$dir] = ''; | |||
} | |||
return $dirs; | |||
} | |||
public function compile( $string, $name = null ) { | |||
$oldImport = $this->importDir; | |||
$this->importDir = (array)$this->importDir; | |||
$this->allParsedFiles = array(); | |||
$parser = new Less_Parser( $this->getOptions() ); | |||
$parser->SetImportDirs( $this->getImportDirs() ); | |||
if ( count( $this->registeredVars ) ) { | |||
$parser->ModifyVars( $this->registeredVars ); | |||
} | |||
foreach ( $this->libFunctions as $name => $func ) { | |||
$parser->registerFunction( $name, $func ); | |||
} | |||
$parser->parse( $string ); | |||
$out = $parser->getCss(); | |||
$parsed = Less_Parser::AllParsedFiles(); | |||
foreach ( $parsed as $file ) { | |||
$this->addParsedFile( $file ); | |||
} | |||
$this->importDir = $oldImport; | |||
return $out; | |||
} | |||
public function compileFile( $fname, $outFname = null ) { | |||
if ( !is_readable( $fname ) ) { | |||
throw new Exception( 'load error: failed to find '.$fname ); | |||
} | |||
$pi = pathinfo( $fname ); | |||
$oldImport = $this->importDir; | |||
$this->importDir = (array)$this->importDir; | |||
$this->importDir[] = Less_Parser::AbsPath( $pi['dirname'] ).'/'; | |||
$this->allParsedFiles = array(); | |||
$this->addParsedFile( $fname ); | |||
$parser = new Less_Parser( $this->getOptions() ); | |||
$parser->SetImportDirs( $this->getImportDirs() ); | |||
if ( count( $this->registeredVars ) ) { | |||
$parser->ModifyVars( $this->registeredVars ); | |||
} | |||
foreach ( $this->libFunctions as $name => $func ) { | |||
$parser->registerFunction( $name, $func ); | |||
} | |||
$parser->parseFile( $fname ); | |||
$out = $parser->getCss(); | |||
$parsed = Less_Parser::AllParsedFiles(); | |||
foreach ( $parsed as $file ) { | |||
$this->addParsedFile( $file ); | |||
} | |||
$this->importDir = $oldImport; | |||
if ( $outFname !== null ) { | |||
return file_put_contents( $outFname, $out ); | |||
} | |||
return $out; | |||
} | |||
public function checkedCompile( $in, $out ) { | |||
if ( !is_file( $out ) || filemtime( $in ) > filemtime( $out ) ) { | |||
$this->compileFile( $in, $out ); | |||
return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* Execute lessphp on a .less file or a lessphp cache structure | |||
* | |||
* The lessphp cache structure contains information about a specific | |||
* less file having been parsed. It can be used as a hint for future | |||
* calls to determine whether or not a rebuild is required. | |||
* | |||
* The cache structure contains two important keys that may be used | |||
* externally: | |||
* | |||
* compiled: The final compiled CSS | |||
* updated: The time (in seconds) the CSS was last compiled | |||
* | |||
* The cache structure is a plain-ol' PHP associative array and can | |||
* be serialized and unserialized without a hitch. | |||
* | |||
* @param mixed $in Input | |||
* @param bool $force Force rebuild? | |||
* @return array lessphp cache structure | |||
*/ | |||
public function cachedCompile( $in, $force = false ) { | |||
// assume no root | |||
$root = null; | |||
if ( is_string( $in ) ) { | |||
$root = $in; | |||
} elseif ( is_array( $in ) and isset( $in['root'] ) ) { | |||
if ( $force or !isset( $in['files'] ) ) { | |||
// If we are forcing a recompile or if for some reason the | |||
// structure does not contain any file information we should | |||
// specify the root to trigger a rebuild. | |||
$root = $in['root']; | |||
} elseif ( isset( $in['files'] ) and is_array( $in['files'] ) ) { | |||
foreach ( $in['files'] as $fname => $ftime ) { | |||
if ( !file_exists( $fname ) or filemtime( $fname ) > $ftime ) { | |||
// One of the files we knew about previously has changed | |||
// so we should look at our incoming root again. | |||
$root = $in['root']; | |||
break; | |||
} | |||
} | |||
} | |||
} else { | |||
// TODO: Throw an exception? We got neither a string nor something | |||
// that looks like a compatible lessphp cache structure. | |||
return null; | |||
} | |||
if ( $root !== null ) { | |||
// If we have a root value which means we should rebuild. | |||
$out = array(); | |||
$out['root'] = $root; | |||
$out['compiled'] = $this->compileFile( $root ); | |||
$out['files'] = $this->allParsedFiles(); | |||
$out['updated'] = time(); | |||
return $out; | |||
} else { | |||
// No changes, pass back the structure | |||
// we were given initially. | |||
return $in; | |||
} | |||
} | |||
public function ccompile( $in, $out, $less = null ) { | |||
if ( $less === null ) { | |||
$less = new self; | |||
} | |||
return $less->checkedCompile( $in, $out ); | |||
} | |||
public static function cexecute( $in, $force = false, $less = null ) { | |||
if ( $less === null ) { | |||
$less = new self; | |||
} | |||
return $less->cachedCompile( $in, $force ); | |||
} | |||
public function allParsedFiles() { | |||
return $this->allParsedFiles; | |||
} | |||
protected function addParsedFile( $file ) { | |||
$this->allParsedFiles[Less_Parser::AbsPath( $file )] = filemtime( $file ); | |||
} | |||
} |
@ -0,0 +1,2 @@ | |||
.easymin | |||
Autoloader.php |
@ -0,0 +1,77 @@ | |||
<?php | |||
/** | |||
* Autoloader | |||
* | |||
* @package Less | |||
* @subpackage autoload | |||
*/ | |||
class Less_Autoloader { | |||
/** | |||
* Registered flag | |||
* | |||
* @var boolean | |||
*/ | |||
protected static $registered = false; | |||
/** | |||
* Library directory | |||
* | |||
* @var string | |||
*/ | |||
protected static $libDir; | |||
/** | |||
* Register the autoloader in the spl autoloader | |||
* | |||
* @return void | |||
* @throws Exception If there was an error in registration | |||
*/ | |||
public static function register() { | |||
if ( self::$registered ) { | |||
return; | |||
} | |||
self::$libDir = dirname( __FILE__ ); | |||
if ( false === spl_autoload_register( array( 'Less_Autoloader', 'loadClass' ) ) ) { | |||
throw new Exception( 'Unable to register Less_Autoloader::loadClass as an autoloading method.' ); | |||
} | |||
self::$registered = true; | |||
} | |||
/** | |||
* Unregisters the autoloader | |||
* | |||
* @return void | |||
*/ | |||
public static function unregister() { | |||
spl_autoload_unregister( array( 'Less_Autoloader', 'loadClass' ) ); | |||
self::$registered = false; | |||
} | |||
/** | |||
* Loads the class | |||
* | |||
* @param string $className The class to load | |||
*/ | |||
public static function loadClass( $className ) { | |||
// handle only package classes | |||
if ( strpos( $className, 'Less_' ) !== 0 ) { | |||
return; | |||
} | |||
$className = substr( $className, 5 ); | |||
$fileName = self::$libDir . DIRECTORY_SEPARATOR . str_replace( '_', DIRECTORY_SEPARATOR, $className ) . '.php'; | |||
if ( file_exists( $fileName ) ) { | |||
require $fileName; | |||
return true; | |||
} else { | |||
throw new Exception( 'file not loadable '.$fileName ); | |||
} | |||
} | |||
} |
@ -0,0 +1,293 @@ | |||
<?php | |||
require_once dirname( __FILE__ ).'/Version.php'; | |||
/** | |||
* Utility for handling the generation and caching of css files | |||
* | |||
* @package Less | |||
* @subpackage cache | |||
* | |||
*/ | |||
class Less_Cache { | |||
// directory less.php can use for storing data | |||
public static $cache_dir = false; | |||
// prefix for the storing data | |||
public static $prefix = 'lessphp_'; | |||
// prefix for the storing vars | |||
public static $prefix_vars = 'lessphpvars_'; | |||
// specifies the number of seconds after which data created by less.php will be seen as 'garbage' and potentially cleaned up | |||
public static $gc_lifetime = 604800; | |||
/** | |||
* Save and reuse the results of compiled less files. | |||
* The first call to Get() will generate css and save it. | |||
* Subsequent calls to Get() with the same arguments will return the same css filename | |||
* | |||
* @param array $less_files Array of .less files to compile | |||
* @param array $parser_options Array of compiler options | |||
* @param array $modify_vars Array of variables | |||
* @return string Name of the css file | |||
*/ | |||
public static function Get( $less_files, $parser_options = array(), $modify_vars = array() ) { | |||
// check $cache_dir | |||
if ( isset( $parser_options['cache_dir'] ) ) { | |||
Less_Cache::$cache_dir = $parser_options['cache_dir']; | |||
} | |||
if ( empty( Less_Cache::$cache_dir ) ) { | |||
throw new Exception( 'cache_dir not set' ); | |||
} | |||
if ( isset( $parser_options['prefix'] ) ) { | |||
Less_Cache::$prefix = $parser_options['prefix']; | |||
} | |||
if ( empty( Less_Cache::$prefix ) ) { | |||
throw new Exception( 'prefix not set' ); | |||
} | |||
if ( isset( $parser_options['prefix_vars'] ) ) { | |||
Less_Cache::$prefix_vars = $parser_options['prefix_vars']; | |||
} | |||
if ( empty( Less_Cache::$prefix_vars ) ) { | |||
throw new Exception( 'prefix_vars not set' ); | |||
} | |||
self::CheckCacheDir(); | |||
$less_files = (array)$less_files; | |||
// create a file for variables | |||
if ( !empty( $modify_vars ) ) { | |||
$lessvars = Less_Parser::serializeVars( $modify_vars ); | |||
$vars_file = Less_Cache::$cache_dir . Less_Cache::$prefix_vars . sha1( $lessvars ) . '.less'; | |||
if ( !file_exists( $vars_file ) ) { | |||
file_put_contents( $vars_file, $lessvars ); | |||
} | |||
$less_files += array( $vars_file => '/' ); | |||
} | |||
// generate name for compiled css file | |||
$hash = md5( json_encode( $less_files ) ); | |||
$list_file = Less_Cache::$cache_dir . Less_Cache::$prefix . $hash . '.list'; | |||
// check cached content | |||
if ( !isset( $parser_options['use_cache'] ) || $parser_options['use_cache'] === true ) { | |||
if ( file_exists( $list_file ) ) { | |||
self::ListFiles( $list_file, $list, $cached_name ); | |||
$compiled_name = self::CompiledName( $list, $hash ); | |||
// if $cached_name is the same as the $compiled name, don't regenerate | |||
if ( !$cached_name || $cached_name === $compiled_name ) { | |||
$output_file = self::OutputFile( $compiled_name, $parser_options ); | |||
if ( $output_file && file_exists( $output_file ) ) { | |||
@touch( $list_file ); | |||
return basename( $output_file ); // for backwards compatibility, we just return the name of the file | |||
} | |||
} | |||
} | |||
} | |||
$compiled = self::Cache( $less_files, $parser_options ); | |||
if ( !$compiled ) { | |||
return false; | |||
} | |||
$compiled_name = self::CompiledName( $less_files, $hash ); | |||
$output_file = self::OutputFile( $compiled_name, $parser_options ); | |||
// save the file list | |||
$list = $less_files; | |||
$list[] = $compiled_name; | |||
$cache = implode( "\n", $list ); | |||
file_put_contents( $list_file, $cache ); | |||
// save the css | |||
file_put_contents( $output_file, $compiled ); | |||
// clean up | |||
self::CleanCache(); | |||
return basename( $output_file ); | |||
} | |||
/** | |||
* Force the compiler to regenerate the cached css file | |||
* | |||
* @param array $less_files Array of .less files to compile | |||
* @param array $parser_options Array of compiler options | |||
* @param array $modify_vars Array of variables | |||
* @return string Name of the css file | |||
*/ | |||
public static function Regen( $less_files, $parser_options = array(), $modify_vars = array() ) { | |||
$parser_options['use_cache'] = false; | |||
return self::Get( $less_files, $parser_options, $modify_vars ); | |||
} | |||
public static function Cache( &$less_files, $parser_options = array() ) { | |||
// get less.php if it exists | |||
$file = dirname( __FILE__ ) . '/Less.php'; | |||
if ( file_exists( $file ) && !class_exists( 'Less_Parser' ) ) { | |||
require_once $file; | |||
} | |||
$parser_options['cache_dir'] = Less_Cache::$cache_dir; | |||
$parser = new Less_Parser( $parser_options ); | |||
// combine files | |||
foreach ( $less_files as $file_path => $uri_or_less ) { | |||
// treat as less markup if there are newline characters | |||
if ( strpos( $uri_or_less, "\n" ) !== false ) { | |||
$parser->Parse( $uri_or_less ); | |||
continue; | |||
} | |||
$parser->ParseFile( $file_path, $uri_or_less ); | |||
} | |||
$compiled = $parser->getCss(); | |||
$less_files = $parser->allParsedFiles(); | |||
return $compiled; | |||
} | |||
private static function OutputFile( $compiled_name, $parser_options ) { | |||
// custom output file | |||
if ( !empty( $parser_options['output'] ) ) { | |||
// relative to cache directory? | |||
if ( preg_match( '#[\\\\/]#', $parser_options['output'] ) ) { | |||
return $parser_options['output']; | |||
} | |||
return Less_Cache::$cache_dir.$parser_options['output']; | |||
} | |||
return Less_Cache::$cache_dir.$compiled_name; | |||
} | |||
private static function CompiledName( $files, $extrahash ) { | |||
// save the file list | |||
$temp = array( Less_Version::cache_version ); | |||
foreach ( $files as $file ) { | |||
$temp[] = filemtime( $file )."\t".filesize( $file )."\t".$file; | |||
} | |||
return Less_Cache::$prefix.sha1( json_encode( $temp ).$extrahash ).'.css'; | |||
} | |||
public static function SetCacheDir( $dir ) { | |||
Less_Cache::$cache_dir = $dir; | |||
self::CheckCacheDir(); | |||
} | |||
public static function CheckCacheDir() { | |||
Less_Cache::$cache_dir = str_replace( '\\', '/', Less_Cache::$cache_dir ); | |||
Less_Cache::$cache_dir = rtrim( Less_Cache::$cache_dir, '/' ).'/'; | |||
if ( !file_exists( Less_Cache::$cache_dir ) ) { | |||
if ( !mkdir( Less_Cache::$cache_dir ) ) { | |||
throw new Less_Exception_Parser( 'Less.php cache directory couldn\'t be created: '.Less_Cache::$cache_dir ); | |||
} | |||
} elseif ( !is_dir( Less_Cache::$cache_dir ) ) { | |||
throw new Less_Exception_Parser( 'Less.php cache directory doesn\'t exist: '.Less_Cache::$cache_dir ); | |||
} elseif ( !is_writable( Less_Cache::$cache_dir ) ) { | |||
throw new Less_Exception_Parser( 'Less.php cache directory isn\'t writable: '.Less_Cache::$cache_dir ); | |||
} | |||
} | |||
/** | |||
* Delete unused less.php files | |||
* | |||
*/ | |||
public static function CleanCache() { | |||
static $clean = false; | |||
if ( $clean || empty( Less_Cache::$cache_dir ) ) { | |||
return; | |||
} | |||
$clean = true; | |||
// only remove files with extensions created by less.php | |||
// css files removed based on the list files | |||
$remove_types = array( 'lesscache' => 1,'list' => 1,'less' => 1,'map' => 1 ); | |||
$files = scandir( Less_Cache::$cache_dir ); | |||
if ( !$files ) { | |||
return; | |||
} | |||
$check_time = time() - self::$gc_lifetime; | |||
foreach ( $files as $file ) { | |||
// don't delete if the file wasn't created with less.php | |||
if ( strpos( $file, Less_Cache::$prefix ) !== 0 ) { | |||
continue; | |||
} | |||
$parts = explode( '.', $file ); | |||
$type = array_pop( $parts ); | |||
if ( !isset( $remove_types[$type] ) ) { | |||
continue; | |||
} | |||
$full_path = Less_Cache::$cache_dir . $file; | |||
$mtime = filemtime( $full_path ); | |||
// don't delete if it's a relatively new file | |||
if ( $mtime > $check_time ) { | |||
continue; | |||
} | |||
// delete the list file and associated css file | |||
if ( $type === 'list' ) { | |||
self::ListFiles( $full_path, $list, $css_file_name ); | |||
if ( $css_file_name ) { | |||
$css_file = Less_Cache::$cache_dir . $css_file_name; | |||
if ( file_exists( $css_file ) ) { | |||
unlink( $css_file ); | |||
} | |||
} | |||
} | |||
unlink( $full_path ); | |||
} | |||
} | |||
/** | |||
* Get the list of less files and generated css file from a list file | |||
* | |||
*/ | |||
static function ListFiles( $list_file, &$list, &$css_file_name ) { | |||
$list = explode( "\n", file_get_contents( $list_file ) ); | |||
// pop the cached name that should match $compiled_name | |||
$css_file_name = array_pop( $list ); | |||
if ( !preg_match( '/^' . Less_Cache::$prefix . '[a-f0-9]+\.css$/', $css_file_name ) ) { | |||
$list[] = $css_file_name; | |||
$css_file_name = false; | |||
} | |||
} | |||
} |
@ -0,0 +1,169 @@ | |||
<?php | |||
/** | |||
* Utility for css colors | |||
* | |||
* @package Less | |||
* @subpackage color | |||
*/ | |||
class Less_Colors { | |||
public static $colors = array( | |||
'aliceblue' => '#f0f8ff', | |||
'antiquewhite' => '#faebd7', | |||
'aqua' => '#00ffff', | |||
'aquamarine' => '#7fffd4', | |||
'azure' => '#f0ffff', | |||
'beige' => '#f5f5dc', | |||
'bisque' => '#ffe4c4', | |||
'black' => '#000000', | |||
'blanchedalmond' => '#ffebcd', | |||
'blue' => '#0000ff', | |||
'blueviolet' => '#8a2be2', | |||
'brown' => '#a52a2a', | |||
'burlywood' => '#deb887', | |||
'cadetblue' => '#5f9ea0', | |||
'chartreuse' => '#7fff00', | |||
'chocolate' => '#d2691e', | |||
'coral' => '#ff7f50', | |||
'cornflowerblue' => '#6495ed', | |||
'cornsilk' => '#fff8dc', | |||
'crimson' => '#dc143c', | |||
'cyan' => '#00ffff', | |||
'darkblue' => '#00008b', | |||
'darkcyan' => '#008b8b', | |||
'darkgoldenrod' => '#b8860b', | |||
'darkgray' => '#a9a9a9', | |||
'darkgrey' => '#a9a9a9', | |||
'darkgreen' => '#006400', | |||
'darkkhaki' => '#bdb76b', | |||
'darkmagenta' => '#8b008b', | |||
'darkolivegreen' => '#556b2f', | |||
'darkorange' => '#ff8c00', | |||
'darkorchid' => '#9932cc', | |||
'darkred' => '#8b0000', | |||
'darksalmon' => '#e9967a', | |||
'darkseagreen' => '#8fbc8f', | |||
'darkslateblue' => '#483d8b', | |||
'darkslategray' => '#2f4f4f', | |||
'darkslategrey' => '#2f4f4f', | |||
'darkturquoise' => '#00ced1', | |||
'darkviolet' => '#9400d3', | |||
'deeppink' => '#ff1493', | |||
'deepskyblue' => '#00bfff', | |||
'dimgray' => '#696969', | |||
'dimgrey' => '#696969', | |||
'dodgerblue' => '#1e90ff', | |||
'firebrick' => '#b22222', | |||
'floralwhite' => '#fffaf0', | |||
'forestgreen' => '#228b22', | |||
'fuchsia' => '#ff00ff', | |||
'gainsboro' => '#dcdcdc', | |||
'ghostwhite' => '#f8f8ff', | |||
'gold' => '#ffd700', | |||
'goldenrod' => '#daa520', | |||
'gray' => '#808080', | |||
'grey' => '#808080', | |||
'green' => '#008000', | |||
'greenyellow' => '#adff2f', | |||
'honeydew' => '#f0fff0', | |||
'hotpink' => '#ff69b4', | |||
'indianred' => '#cd5c5c', | |||
'indigo' => '#4b0082', | |||
'ivory' => '#fffff0', | |||
'khaki' => '#f0e68c', | |||
'lavender' => '#e6e6fa', | |||
'lavenderblush' => '#fff0f5', | |||
'lawngreen' => '#7cfc00', | |||
'lemonchiffon' => '#fffacd', | |||
'lightblue' => '#add8e6', | |||
'lightcoral' => '#f08080', | |||
'lightcyan' => '#e0ffff', | |||
'lightgoldenrodyellow' => '#fafad2', | |||
'lightgray' => '#d3d3d3', | |||
'lightgrey' => '#d3d3d3', | |||
'lightgreen' => '#90ee90', | |||
'lightpink' => '#ffb6c1', | |||
'lightsalmon' => '#ffa07a', | |||
'lightseagreen' => '#20b2aa', | |||
'lightskyblue' => '#87cefa', | |||
'lightslategray' => '#778899', | |||
'lightslategrey' => '#778899', | |||
'lightsteelblue' => '#b0c4de', | |||
'lightyellow' => '#ffffe0', | |||
'lime' => '#00ff00', | |||
'limegreen' => '#32cd32', | |||
'linen' => '#faf0e6', | |||
'magenta' => '#ff00ff', | |||
'maroon' => '#800000', | |||
'mediumaquamarine' => '#66cdaa', | |||
'mediumblue' => '#0000cd', | |||
'mediumorchid' => '#ba55d3', | |||
'mediumpurple' => '#9370d8', | |||
'mediumseagreen' => '#3cb371', | |||
'mediumslateblue' => '#7b68ee', | |||
'mediumspringgreen' => '#00fa9a', | |||
'mediumturquoise' => '#48d1cc', | |||
'mediumvioletred' => '#c71585', | |||
'midnightblue' => '#191970', | |||
'mintcream' => '#f5fffa', | |||
'mistyrose' => '#ffe4e1', | |||
'moccasin' => '#ffe4b5', | |||
'navajowhite' => '#ffdead', | |||
'navy' => '#000080', | |||
'oldlace' => '#fdf5e6', | |||
'olive' => '#808000', | |||
'olivedrab' => '#6b8e23', | |||
'orange' => '#ffa500', | |||
'orangered' => '#ff4500', | |||
'orchid' => '#da70d6', | |||
'palegoldenrod' => '#eee8aa', | |||
'palegreen' => '#98fb98', | |||
'paleturquoise' => '#afeeee', | |||
'palevioletred' => '#d87093', | |||
'papayawhip' => '#ffefd5', | |||
'peachpuff' => '#ffdab9', | |||
'peru' => '#cd853f', | |||
'pink' => '#ffc0cb', | |||
'plum' => '#dda0dd', | |||
'powderblue' => '#b0e0e6', | |||
'purple' => '#800080', | |||
'red' => '#ff0000', | |||
'rosybrown' => '#bc8f8f', | |||
'royalblue' => '#4169e1', | |||
'saddlebrown' => '#8b4513', | |||
'salmon' => '#fa8072', | |||
'sandybrown' => '#f4a460', | |||
'seagreen' => '#2e8b57', | |||
'seashell' => '#fff5ee', | |||
'sienna' => '#a0522d', | |||
'silver' => '#c0c0c0', | |||
'skyblue' => '#87ceeb', | |||
'slateblue' => '#6a5acd', | |||
'slategray' => '#708090', | |||
'slategrey' => '#708090', | |||
'snow' => '#fffafa', | |||
'springgreen' => '#00ff7f', | |||
'steelblue' => '#4682b4', | |||
'tan' => '#d2b48c', | |||
'teal' => '#008080', | |||
'thistle' => '#d8bfd8', | |||
'tomato' => '#ff6347', | |||
'turquoise' => '#40e0d0', | |||
'violet' => '#ee82ee', | |||
'wheat' => '#f5deb3', | |||
'white' => '#ffffff', | |||
'whitesmoke' => '#f5f5f5', | |||
'yellow' => '#ffff00', | |||
'yellowgreen' => '#9acd32' | |||
); | |||
public static function hasOwnProperty( $color ) { | |||
return isset( self::$colors[$color] ); | |||
} | |||
public static function color( $color ) { | |||
return self::$colors[$color]; | |||
} | |||
} |
@ -0,0 +1,66 @@ | |||
<?php | |||
/** | |||
* Configurable | |||
* | |||
* @package Less | |||
* @subpackage Core | |||
*/ | |||
abstract class Less_Configurable { | |||
/** | |||
* Array of options | |||
* | |||
* @var array | |||
*/ | |||
protected $options = array(); | |||
/** | |||
* Array of default options | |||
* | |||
* @var array | |||
*/ | |||
protected $defaultOptions = array(); | |||
/** | |||
* Set options | |||
* | |||
* If $options is an object it will be converted into an array by called | |||
* it's toArray method. | |||
* | |||
* @throws Exception | |||
* @param array|object $options | |||
* | |||
*/ | |||
public function setOptions( $options ) { | |||
$options = array_intersect_key( $options, $this->defaultOptions ); | |||
$this->options = array_merge( $this->defaultOptions, $this->options, $options ); | |||
} | |||
/** | |||
* Get an option value by name | |||
* | |||
* If the option is empty or not set a NULL value will be returned. | |||
* | |||
* @param string $name | |||
* @param mixed $default Default value if confiuration of $name is not present | |||
* @return mixed | |||
*/ | |||
public function getOption( $name, $default = null ) { | |||
if ( isset( $this->options[$name] ) ) { | |||
return $this->options[$name]; | |||
} | |||
return $default; | |||
} | |||
/** | |||
* Set an option | |||
* | |||
* @param string $name | |||
* @param mixed $value | |||
*/ | |||
public function setOption( $name, $value ) { | |||
$this->options[$name] = $value; | |||
} | |||
} |
@ -0,0 +1,157 @@ | |||
<?php | |||
/** | |||
* Environment | |||
* | |||
* @package Less | |||
* @subpackage environment | |||
*/ | |||
class Less_Environment { | |||
// public $paths = array(); // option - unmodified - paths to search for imports on | |||
//public static $files = array(); // list of files that have been imported, used for import-once | |||
//public $rootpath; // option - rootpath to append to URL's | |||
//public static $strictImports = null; // option - | |||
//public $insecure; // option - whether to allow imports from insecure ssl hosts | |||
//public $processImports; // option - whether to process imports. if false then imports will not be imported | |||
//public $javascriptEnabled; // option - whether JavaScript is enabled. if undefined, defaults to true | |||
//public $useFileCache; // browser only - whether to use the per file session cache | |||
public $currentFileInfo; // information about the current file - for error reporting and importing and making urls relative etc. | |||
public $importMultiple = false; // whether we are currently importing multiple copies | |||
/** | |||
* @var array | |||
*/ | |||
public $frames = array(); | |||
/** | |||
* @var array | |||
*/ | |||
public $mediaBlocks = array(); | |||