Upgrade lessphp

* Upgrade from 0.3.9 to 0.4.0
* Document package source
* Remove overhead

refs #6165
refs #6166
This commit is contained in:
Thomas Gelf 2014-05-09 10:53:54 +00:00
parent d93c060e6a
commit dcf6b998bf
75 changed files with 312 additions and 5115 deletions

View File

@ -1,96 +0,0 @@
# lessphp v0.3.9
### <http://leafo.net/lessphp>
[![Build Status](https://secure.travis-ci.org/leafo/lessphp.png)](http://travis-ci.org/leafo/lessphp)
`lessphp` is a compiler for LESS written in PHP. The documentation is great,
so check it out: <http://leafo.net/lessphp/docs/>.
Here's a quick tutorial:
### How to use in your PHP project
The only file required is `lessc.inc.php`, so copy that to your include directory.
The typical flow of **lessphp** is to create a new instance of `lessc`,
configure it how you like, then tell it to compile something using one built in
compile methods.
The `compile` method compiles a string of LESS code to CSS.
```php
<?php
require "lessc.inc.php";
$less = new lessc;
echo $less->compile(".block { padding: 3 + 4px }");
```
The `compileFile` method reads and compiles a file. It will either return the
result or write it to the path specified by an optional second argument.
```php
<?php
echo $less->compileFile("input.less");
```
The `compileChecked` method is like `compileFile`, but it only compiles if the output
file doesn't exist or it's older than the input file:
```php
<?php
$less->checkedCompile("input.less", "output.css");
```
If there any problem compiling your code, an exception is thrown with a helpful message:
```php
<?php
try {
$less->compile("invalid LESS } {");
} catch (exception $e) {
echo "fatal error: " . $e->getMessage();
}
```
The `lessc` object can be configured through an assortment of instance methods.
Some possible configuration options include [changing the output format][1],
[setting variables from PHP][2], and [controlling the preservation of
comments][3], writing [custom functions][4] and much more. It's all described
in [the documentation][0].
[0]: http://leafo.net/lessphp/docs/
[1]: http://leafo.net/lessphp/docs/#output_formatting
[2]: http://leafo.net/lessphp/docs/#setting_variables_from_php
[3]: http://leafo.net/lessphp/docs/#preserving_comments
[4]: http://leafo.net/lessphp/docs/#custom_functions
### How to use from the 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:
$ plessc input.less > output.css
Using the -r flag, you can specify LESS code directly as an argument or, if
the argument is left off, from standard in:
$ plessc -r "my less code here"
Finally, by using the -w flag you can watch a specified input file and have it
compile as needed to the output file:
$ plessc -w input-file output-file
Errors from watch mode are written to standard out.
The -f flag sets the [output formatter][1]. For example, to compress the
output run this:
$ plessc -f=compressed myfile.less
For more help, run `plessc --help`

2
library/vendor/lessphp/SOURCE vendored Normal file
View File

@ -0,0 +1,2 @@
http://leafo.net/lessphp/src/lessphp-0.4.0.tar.gz
tar xfz lessphp-0.4.0.tar.gz lessphp/lessc.inc.php lessphp/LICENSE

View File

@ -1,25 +0,0 @@
{
"name": "leafo/lessphp",
"type": "library",
"description": "lessphp is a compiler for LESS written in PHP.",
"homepage": "http://leafo.net/lessphp/",
"license": [
"MIT",
"GPL-3.0"
],
"authors": [
{
"name": "Leaf Corcoran",
"email": "leafot@gmail.com",
"homepage": "http://leafo.net"
}
],
"autoload": {
"classmap": ["lessc.inc.php"]
},
"extra": {
"branch-alias": {
"dev-master": "0.3-dev"
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
<?php
/**
* lessphp v0.3.9
* lessphp v0.4.0
* http://leafo.net/lessphp
*
* LESS css compiler, adapted from http://lesscss.org
@ -38,7 +38,7 @@
* handling things like indentation.
*/
class lessc {
static public $VERSION = "v0.3.9";
static public $VERSION = "v0.4.0";
static protected $TRUE = array("keyword", "true");
static protected $FALSE = array("keyword", "false");
@ -55,6 +55,8 @@ class lessc {
protected $numberPrecision = null;
protected $allParsedFiles = array();
// set to the parser that generated the current line when compiling
// so we know how to create error messages
protected $sourceParser = null;
@ -103,12 +105,17 @@ class lessc {
if (substr_compare($url, '.css', -4, 4) === 0) return false;
$realPath = $this->findImport($url);
if ($realPath === null) return false;
if ($this->importDisabled) {
return array(false, "/* import disabled */");
}
if (isset($this->allParsedFiles[realpath($realPath)])) {
return array(false, null);
}
$this->addParsedFile($realPath);
$parser = $this->makeParser($realPath);
$root = $parser->parse(file_get_contents($realPath));
@ -276,6 +283,8 @@ class lessc {
foreach ($this->sortProps($block->props) as $prop) {
$this->compileProp($prop, $block, $out);
}
$out->lines = array_values(array_unique($out->lines));
}
protected function sortProps($props, $split = false) {
@ -450,7 +459,7 @@ class lessc {
return $left == $right;
}
protected function patternMatch($block, $callingArgs) {
protected function patternMatch($block, $orderedArgs, $keywordArgs) {
// match the guards if it has them
// any one of the groups must have all its guards pass for a match
if (!empty($block->guards)) {
@ -458,7 +467,7 @@ class lessc {
foreach ($block->guards as $guardGroup) {
foreach ($guardGroup as $guard) {
$this->pushEnv();
$this->zipSetArgs($block->args, $callingArgs);
$this->zipSetArgs($block->args, $orderedArgs, $keywordArgs);
$negate = false;
if ($guard[0] == "negate") {
@ -487,24 +496,34 @@ class lessc {
}
}
$numCalling = count($callingArgs);
if (empty($block->args)) {
return $block->isVararg || $numCalling == 0;
return $block->isVararg || empty($orderedArgs) && empty($keywordArgs);
}
$remainingArgs = $block->args;
if ($keywordArgs) {
$remainingArgs = array();
foreach ($block->args as $arg) {
if ($arg[0] == "arg" && isset($keywordArgs[$arg[1]])) {
continue;
}
$remainingArgs[] = $arg;
}
}
$i = -1; // no args
// try to match by arity or by argument literal
foreach ($block->args as $i => $arg) {
foreach ($remainingArgs as $i => $arg) {
switch ($arg[0]) {
case "lit":
if (empty($callingArgs[$i]) || !$this->eq($arg[1], $callingArgs[$i])) {
if (empty($orderedArgs[$i]) || !$this->eq($arg[1], $orderedArgs[$i])) {
return false;
}
break;
case "arg":
// no arg and no default value
if (!isset($callingArgs[$i]) && !isset($arg[2])) {
if (!isset($orderedArgs[$i]) && !isset($arg[2])) {
return false;
}
break;
@ -519,14 +538,19 @@ class lessc {
} else {
$numMatched = $i + 1;
// greater than becuase default values always match
return $numMatched >= $numCalling;
return $numMatched >= count($orderedArgs);
}
}
protected function patternMatchAll($blocks, $callingArgs) {
protected function patternMatchAll($blocks, $orderedArgs, $keywordArgs, $skip=array()) {
$matches = null;
foreach ($blocks as $block) {
if ($this->patternMatch($block, $callingArgs)) {
// skip seen blocks that don't have arguments
if (isset($skip[$block->id]) && !isset($block->args)) {
continue;
}
if ($this->patternMatch($block, $orderedArgs, $keywordArgs)) {
$matches[] = $block;
}
}
@ -535,7 +559,7 @@ class lessc {
}
// attempt to find blocks matched by path and args
protected function findBlocks($searchIn, $path, $args, $seen=array()) {
protected function findBlocks($searchIn, $path, $orderedArgs, $keywordArgs, $seen=array()) {
if ($searchIn == null) return null;
if (isset($seen[$searchIn->id])) return null;
$seen[$searchIn->id] = true;
@ -545,7 +569,7 @@ class lessc {
if (isset($searchIn->children[$name])) {
$blocks = $searchIn->children[$name];
if (count($path) == 1) {
$matches = $this->patternMatchAll($blocks, $args);
$matches = $this->patternMatchAll($blocks, $orderedArgs, $keywordArgs, $seen);
if (!empty($matches)) {
// This will return all blocks that match in the closest
// scope that has any matching block, like lessjs
@ -555,7 +579,7 @@ class lessc {
$matches = array();
foreach ($blocks as $subBlock) {
$subMatches = $this->findBlocks($subBlock,
array_slice($path, 1), $args, $seen);
array_slice($path, 1), $orderedArgs, $keywordArgs, $seen);
if (!is_null($subMatches)) {
foreach ($subMatches as $sm) {
@ -567,39 +591,51 @@ class lessc {
return count($matches) > 0 ? $matches : null;
}
}
if ($searchIn->parent === $searchIn) return null;
return $this->findBlocks($searchIn->parent, $path, $args, $seen);
return $this->findBlocks($searchIn->parent, $path, $orderedArgs, $keywordArgs, $seen);
}
// sets all argument names in $args to either the default value
// or the one passed in through $values
protected function zipSetArgs($args, $values) {
$i = 0;
protected function zipSetArgs($args, $orderedValues, $keywordValues) {
$assignedValues = array();
foreach ($args as $a) {
$i = 0;
foreach ($args as $a) {
if ($a[0] == "arg") {
if ($i < count($values) && !is_null($values[$i])) {
$value = $values[$i];
if (isset($keywordValues[$a[1]])) {
// has keyword arg
$value = $keywordValues[$a[1]];
} elseif (isset($orderedValues[$i])) {
// has ordered arg
$value = $orderedValues[$i];
$i++;
} elseif (isset($a[2])) {
// has default value
$value = $a[2];
} else $value = null;
} else {
$this->throwError("Failed to assign arg " . $a[1]);
$value = null; // :(
}
$value = $this->reduce($value);
$this->set($a[1], $value);
$assignedValues[] = $value;
} else {
// a lit
$i++;
}
$i++;
}
// check for a rest
$last = end($args);
if ($last[0] == "rest") {
$rest = array_slice($values, count($args) - 1);
$rest = array_slice($orderedValues, count($args) - 1);
$this->set($last[1], $this->reduce(array("list", " ", $rest)));
}
$this->env->arguments = $assignedValues;
// wow is this the only true use of PHP's + operator for arrays?
$this->env->arguments = $assignedValues + $orderedValues;
}
// compile a prop and update $lines or $blocks appropriately
@ -624,8 +660,28 @@ class lessc {
case 'mixin':
list(, $path, $args, $suffix) = $prop;
$args = array_map(array($this, "reduce"), (array)$args);
$mixins = $this->findBlocks($block, $path, $args);
$orderedArgs = array();
$keywordArgs = array();
foreach ((array)$args as $arg) {
$argval = null;
switch ($arg[0]) {
case "arg":
if (!isset($arg[2])) {
$orderedArgs[] = $this->reduce(array("variable", $arg[1]));
} else {
$keywordArgs[$arg[1]] = $this->reduce($arg[2]);
}
break;
case "lit":
$orderedArgs[] = $this->reduce($arg[1]);
break;
default:
$this->throwError("Unknown arg type: " . $arg[0]);
}
}
$mixins = $this->findBlocks($block, $path, $orderedArgs, $keywordArgs);
if ($mixins === null) {
// fwrite(STDERR,"failed to find block: ".implode(" > ", $path)."\n");
@ -633,6 +689,10 @@ class lessc {
}
foreach ($mixins as $mixin) {
if ($mixin === $block && !$orderedArgs) {
continue;
}
$haveScope = false;
if (isset($mixin->parent->scope)) {
$haveScope = true;
@ -644,7 +704,7 @@ class lessc {
if (isset($mixin->args)) {
$haveArgs = true;
$this->pushEnv();
$this->zipSetArgs($mixin->args, $args);
$this->zipSetArgs($mixin->args, $orderedArgs, $keywordArgs);
}
$oldParent = $mixin->parent;
@ -701,7 +761,9 @@ class lessc {
list(,$importId) = $prop;
$import = $this->env->imports[$importId];
if ($import[0] === false) {
$out->lines[] = $import[1];
if (isset($import[1])) {
$out->lines[] = $import[1];
}
} else {
list(, $bottom, $parser, $importDir) = $import;
$this->compileImportedProps($bottom, $block, $out, $parser, $importDir);
@ -789,6 +851,60 @@ class lessc {
}
}
protected function lib_pow($args) {
list($base, $exp) = $this->assertArgs($args, 2, "pow");
return pow($this->assertNumber($base), $this->assertNumber($exp));
}
protected function lib_pi() {
return pi();
}
protected function lib_mod($args) {
list($a, $b) = $this->assertArgs($args, 2, "mod");
return $this->assertNumber($a) % $this->assertNumber($b);
}
protected function lib_tan($num) {
return tan($this->assertNumber($num));
}
protected function lib_sin($num) {
return sin($this->assertNumber($num));
}
protected function lib_cos($num) {
return cos($this->assertNumber($num));
}
protected function lib_atan($num) {
$num = atan($this->assertNumber($num));
return array("number", $num, "rad");
}
protected function lib_asin($num) {
$num = asin($this->assertNumber($num));
return array("number", $num, "rad");
}
protected function lib_acos($num) {
$num = acos($this->assertNumber($num));
return array("number", $num, "rad");
}
protected function lib_sqrt($num) {
return sqrt($this->assertNumber($num));
}
protected function lib_extract($value) {
list($list, $idx) = $this->assertArgs($value, 2, "extract");
$idx = $this->assertNumber($idx);
// 1 indexed
if ($list[0] == "list" && isset($list[2][$idx - 1])) {
return $list[2][$idx - 1];
}
}
protected function lib_isnumber($value) {
return $this->toBool($value[0] == "number");
}
@ -1013,19 +1129,24 @@ class lessc {
}
// mixes two colors by weight
// mix(@color1, @color2, @weight);
// mix(@color1, @color2, [@weight: 50%]);
// http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html#mix-instance_method
protected function lib_mix($args) {
if ($args[0] != "list" || count($args[2]) < 3)
if ($args[0] != "list" || count($args[2]) < 2)
$this->throwError("mix expects (color1, color2, weight)");
list($first, $second, $weight) = $args[2];
list($first, $second) = $args[2];
$first = $this->assertColor($first);
$second = $this->assertColor($second);
$first_a = $this->lib_alpha($first);
$second_a = $this->lib_alpha($second);
$weight = $weight[1] / 100.0;
if (isset($args[2][2])) {
$weight = $args[2][2][1] / 100.0;
} else {
$weight = 0.5;
}
$w = $weight * 2 - 1;
$a = $first_a - $second_a;
@ -1076,6 +1197,25 @@ class lessc {
$this->throwError($error);
}
protected function assertArgs($value, $expectedArgs, $name="") {
if ($expectedArgs == 1) {
return $value;
} else {
if ($value[0] !== "list" || $value[1] != ",") $this->throwError("expecting list");
$values = $value[2];
$numValues = count($values);
if ($expectedArgs != $numValues) {
if ($name) {
$name = $name . ": ";
}
$this->throwError("${name}expecting $expectedArgs arguments, got $numValues");
}
return $values;
}
}
protected function toHSL($color) {
if ($color[0] == 'hsl') return $color;
@ -1220,6 +1360,10 @@ class lessc {
$var = $this->compileValue($reduced);
$res = $this->reduce(array("variable", $this->vPrefix . $var));
if ($res[0] == "raw_color") {
$res = $this->coerceColor($res);
}
if (empty($value[2])) $res = $this->lib_e($res);
return $res;
@ -1681,7 +1825,6 @@ class lessc {
$this->importDir = (array)$this->importDir;
$this->importDir[] = $pi['dirname'].'/';
$this->allParsedFiles = array();
$this->addParsedFile($fname);
$out = $this->compile(file_get_contents($fname), $fname);
@ -2065,7 +2208,7 @@ class lessc_parser {
static protected $supressDivisionProps =
array('/border-radius$/i', '/^font$/i');
protected $blockDirectives = array("font-face", "keyframes", "page", "-moz-document");
protected $blockDirectives = array("font-face", "keyframes", "page", "-moz-document", "viewport", "-moz-viewport", "-o-viewport", "-ms-viewport");
protected $lineDirectives = array("charset");
/**
@ -2304,7 +2447,7 @@ class lessc_parser {
// mixin
if ($this->mixinTags($tags) &&
($this->argumentValues($argv) || true) &&
($this->argumentDef($argv, $isVararg) || true) &&
($this->keyword($suffix) || true) && $this->end())
{
$tags = $this->fixTags($tags);
@ -2653,7 +2796,6 @@ class lessc_parser {
}
if (!empty($rejectStrs) && in_array($tok, $rejectStrs)) {
$ount = null;
break;
}
@ -2773,38 +2915,18 @@ class lessc_parser {
return false;
}
// consume a list of property values delimited by ; and wrapped in ()
protected function argumentValues(&$args, $delim = ',') {
$s = $this->seek();
if (!$this->literal('(')) return false;
$values = array();
while (true) {
if ($this->expressionList($value)) $values[] = $value;
if (!$this->literal($delim)) break;
else {
if ($value == null) $values[] = null;
$value = null;
}
}
if (!$this->literal(')')) {
$this->seek($s);
return false;
}
$args = $values;
return true;
}
// consume an argument definition list surrounded by ()
// each argument is a variable name with optional value
// or at the end a ... or a variable named followed by ...
protected function argumentDef(&$args, &$isVararg, $delim = ',') {
// arguments are separated by , unless a ; is in the list, then ; is the
// delimiter.
protected function argumentDef(&$args, &$isVararg) {
$s = $this->seek();
if (!$this->literal('(')) return false;
$values = array();
$delim = ",";
$method = "expressionList";
$isVararg = false;
while (true) {
@ -2813,28 +2935,77 @@ class lessc_parser {
break;
}
if ($this->variable($vname)) {
$arg = array("arg", $vname);
$ss = $this->seek();
if ($this->assign() && $this->expressionList($value)) {
$arg[] = $value;
} else {
$this->seek($ss);
if ($this->literal("...")) {
$arg[0] = "rest";
$isVararg = true;
if ($this->$method($value)) {
if ($value[0] == "variable") {
$arg = array("arg", $value[1]);
$ss = $this->seek();
if ($this->assign() && $this->$method($rhs)) {
$arg[] = $rhs;
} else {
$this->seek($ss);
if ($this->literal("...")) {
$arg[0] = "rest";
$isVararg = true;
}
}
$values[] = $arg;
if ($isVararg) break;
continue;
} else {
$values[] = array("lit", $value);
}
$values[] = $arg;
if ($isVararg) break;
continue;
}
if ($this->value($literal)) {
$values[] = array("lit", $literal);
}
if (!$this->literal($delim)) break;
if (!$this->literal($delim)) {
if ($delim == "," && $this->literal(";")) {
// found new delim, convert existing args
$delim = ";";
$method = "propertyValue";
// transform arg list
if (isset($values[1])) { // 2 items
$newList = array();
foreach ($values as $i => $arg) {
switch($arg[0]) {
case "arg":
if ($i) {
$this->throwError("Cannot mix ; and , as delimiter types");
}
$newList[] = $arg[2];
break;
case "lit":
$newList[] = $arg[1];
break;
case "rest":
$this->throwError("Unexpected rest before semicolon");
}
}
$newList = array("list", ", ", $newList);
switch ($values[0][0]) {
case "arg":
$newArg = array("arg", $values[0][1], $newList);
break;
case "lit":
$newArg = array("lit", $newList);
break;
}
} elseif ($values) { // 1 item
$newArg = $values[0];
}
if ($newArg) {
$values = array($newArg);
}
} else {
break;
}
}
}
if (!$this->literal(')')) {
@ -2876,32 +3047,69 @@ class lessc_parser {
}
// a bracketed value (contained within in a tag definition)
protected function tagBracket(&$value) {
protected function tagBracket(&$parts, &$hasExpression) {
// speed shortcut
if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != "[") {
return false;
}
$s = $this->seek();
if ($this->literal('[') && $this->to(']', $c, true) && $this->literal(']', false)) {
$value = '['.$c.']';
// whitespace?
if ($this->whitespace()) $value .= " ";
// escape parent selector, (yuck)
$value = str_replace($this->lessc->parentSelector, "$&$", $value);
return true;
}
$hasInterpolation = false;
$this->seek($s);
return false;
}
if ($this->literal("[", false)) {
$attrParts = array("[");
// keyword, string, operator
while (true) {
if ($this->literal("]", false)) {
$this->count--;
break; // get out early
}
protected function tagExpression(&$value) {
$s = $this->seek();
if ($this->literal("(") && $this->expression($exp) && $this->literal(")")) {
$value = array('exp', $exp);
return true;
if ($this->match('\s+', $m)) {
$attrParts[] = " ";
continue;
}
if ($this->string($str)) {
// escape parent selector, (yuck)
foreach ($str[2] as &$chunk) {
$chunk = str_replace($this->lessc->parentSelector, "$&$", $chunk);
}
$attrParts[] = $str;
$hasInterpolation = true;
continue;
}
if ($this->keyword($word)) {
$attrParts[] = $word;
continue;
}
if ($this->interpolation($inter, false)) {
$attrParts[] = $inter;
$hasInterpolation = true;
continue;
}
// operator, handles attr namespace too
if ($this->match('[|-~\$\*\^=]+', $m)) {
$attrParts[] = $m[0];
continue;
}
break;
}
if ($this->literal("]", false)) {
$attrParts[] = "]";
foreach ($attrParts as $part) {
$parts[] = $part;
}
$hasExpression = $hasExpression || $hasInterpolation;
return true;
}
$this->seek($s);
}
$this->seek($s);
@ -2917,13 +3125,9 @@ class lessc_parser {
$s = $this->seek();
if (!$simple && $this->tagExpression($tag)) {
return true;
}
$hasExpression = false;
$parts = array();
while ($this->tagBracket($first)) $parts[] = $first;
while ($this->tagBracket($parts, $hasExpression));
$oldWhite = $this->eatWhiteDefault;
$this->eatWhiteDefault = false;
@ -2933,9 +3137,7 @@ class lessc_parser {
$parts[] = $m[1];
if ($simple) break;
while ($this->tagBracket($brack)) {
$parts[] = $brack;
}
while ($this->tagBracket($parts, $hasExpression));
continue;
}
@ -3062,7 +3264,7 @@ class lessc_parser {
protected function end() {
if ($this->literal(';')) {
return true;
} elseif ($this->count == strlen($this->buffer) || $this->buffer{$this->count} == '}') {
} elseif ($this->count == strlen($this->buffer) || $this->buffer[$this->count] == '}') {
// if there is end of file or a closing block next then we don't need a ;
return true;
}
@ -3326,7 +3528,7 @@ class lessc_parser {
break;
case '"':
case "'":
if (preg_match('/'.$min[0].'.*?'.$min[0].'/', $text, $m, 0, $count))
if (preg_match('/'.$min[0].'.*?(?<!\\\\)'.$min[0].'/', $text, $m, 0, $count))
$count += strlen($m[0]) - 1;
break;
case '//':

View File

@ -1,250 +0,0 @@
#!/usr/bin/env php
<?php
// Command line utility to compile LESS to STDOUT
// Leaf Corcoran <leafot@gmail.com>, 2012
$exe = array_shift($argv); // remove filename
$HELP = <<<EOT
Usage: $exe [options] input-file [output-file]
Options include:
-h, --help Show this message
-v Print the version
-f=format Set the output format, includes "default", "compressed"
-c Keep /* */ comments in output
-r Read from STDIN instead of input-file
-w Watch input-file, and compile to output-file if it is changed
-T Dump formatted parse tree
-X Dump raw parse tree
EOT;
$opts = getopt('hvrwncXTf:', array('help'));
while (count($argv) > 0 && preg_match('/^-([-hvrwncXT]$|[f]=)/', $argv[0])) {
array_shift($argv);
}
function has() {
global $opts;
foreach (func_get_args() as $arg) {
if (isset($opts[$arg])) return true;
}
return false;
}
if (has("h", "help")) {
exit($HELP);
}
error_reporting(E_ALL);
$path = realpath(dirname(__FILE__)).'/';
require $path."lessc.inc.php";
$VERSION = lessc::$VERSION;
$fa = "Fatal Error: ";
function err($msg) {
fwrite(STDERR, $msg."\n");
}
if (php_sapi_name() != "cli") {
err($fa.$argv[0]." must be run in the command line.");
exit(1);
}
function make_less($fname = null) {
global $opts;
$l = new lessc($fname);
if (has("f")) {
$format = $opts["f"];
if ($format != "default") $l->setFormatter($format);
}
if (has("c")) {
$l->setPreserveComments(true);
}
return $l;
}
function process($data, $import = null) {
global $fa;
$l = make_less();
if ($import) $l->importDir = $import;
try {
echo $l->parse($data);
exit(0);
} catch (exception $ex) {
err($fa."\n".str_repeat('=', 20)."\n".
$ex->getMessage());
exit(1);
}
}
if (has("v")) {
exit($VERSION."\n");
}
if (has("r")) {
if (!empty($argv)) {
$data = $argv[0];
} else {
$data = "";
while (!feof(STDIN)) {
$data .= fread(STDIN, 8192);
}
}
exit(process($data));
}
if (has("w")) {
// need two files
if (!is_file($in = array_shift($argv)) ||
null == $out = array_shift($argv))
{
err($fa.$exe." -w infile outfile");
exit(1);
}
echo "Watching ".$in.
(has("n") ? ' with notifications' : '').
", press Ctrl + c to exit.\n";
$cache = $in;
$last_action = 0;
while (true) {
clearstatcache();
// check if anything has changed since last fail
$updated = false;
if (is_array($cache)) {
foreach ($cache['files'] as $fname=>$_) {
if (filemtime($fname) > $last_action) {
$updated = true;
break;
}
}
} else $updated = true;
// try to compile it
if ($updated) {
$last_action = time();
try {
$cache = lessc::cexecute($cache);
echo "Writing updated file: ".$out."\n";
if (!file_put_contents($out, $cache['compiled'])) {
err($fa."Could not write to file ".$out);
exit(1);
}
} catch (exception $ex) {
echo "\nFatal Error:\n".str_repeat('=', 20)."\n".
$ex->getMessage()."\n\n";
if (has("n")) {
`notify-send -u critical "compile failed" "{$ex->getMessage()}"`;
}
}
}
sleep(1);
}
exit(0);
}
if (!$fname = array_shift($argv)) {
echo $HELP;
exit(1);
}
function dumpValue($node, $depth = 0) {
if (is_object($node)) {
$indent = str_repeat(" ", $depth);
$out = array();
foreach ($node->props as $prop) {
$out[] = $indent . dumpValue($prop, $depth + 1);
}
$out = implode("\n", $out);
if (!empty($node->tags)) {
$out = "+ ".implode(", ", $node->tags)."\n".$out;
}
return $out;
} elseif (is_array($node)) {
if (empty($node)) return "[]";
$type = $node[0];
if ($type == "block")
return dumpValue($node[1], $depth);
$out = array();
foreach ($node as $value) {
$out[] = dumpValue($value, $depth);
}
return "{ ".implode(", ", $out)." }";
} else {
if (is_string($node) && preg_match("/[\s,]/", $node)) {
return '"'.$node.'"';
}
return $node; // normal value
}
}
function stripValue($o, $toStrip) {
if (is_array($o) || is_object($o)) {
$isObject = is_object($o);
$o = (array)$o;
foreach ($toStrip as $removeKey) {
if (!empty($o[$removeKey])) {
$o[$removeKey] = "*stripped*";
}
}
foreach ($o as $k => $v) {
$o[$k] = stripValue($v, $toStrip);
}
if ($isObject) {
$o = (object)$o;
}
}
return $o;
}
function dumpWithoutParent($o, $alsoStrip=array()) {
$toStrip = array_merge(array("parent"), $alsoStrip);
print_r(stripValue($o, $toStrip));
}
try {
$less = make_less($fname);
if (has("T", "X")) {
$parser = new lessc_parser($less, $fname);
$tree = $parser->parse(file_get_contents($fname));
if (has("X"))
$out = print_r($tree, 1);
else
$out = dumpValue($tree)."\n";
} else {
$out = $less->parse();
}
if (!$fout = array_shift($argv)) {
echo $out;
} else {
file_put_contents($fout, $out);
}
} catch (exception $ex) {
err($fa.$ex->getMessage());
exit(1);
}
?>

View File

@ -1,189 +0,0 @@
<?php
require_once __DIR__ . "/../lessc.inc.php";
class ApiTest extends PHPUnit_Framework_TestCase {
public function setUp() {
$this->less = new lessc();
$this->less->importDir = array(__DIR__ . "/inputs/test-imports");
}
public function testPreserveComments() {
$input = <<<EOD
// what is going on?
/** what the heck **/
/**
Here is a block comment
**/
// this is a comment
/*hello*/div /*yeah*/ { //surew
border: 1px solid red; // world
/* another property */
color: url('http://mage-page.com');
string: "hello /* this is not a comment */";
world: "// neither is this";
string: 'hello /* this is not a comment */' /*what if this is a comment */;
world: '// neither is this' // hell world;
;
what-ever: 100px;
background: url(/*this is not a comment?*/); // uhh what happens here
}
EOD;
$outputWithComments = <<<EOD
/** what the heck **/
/**
Here is a block comment
**/
/*hello*/
/*yeah*/
div /*yeah*/ {
/* another property */
border: 1px solid red;
color: url('http://mage-page.com');
string: "hello /* this is not a comment */";
world: "// neither is this";
/*what if this is a comment */
string: 'hello /* this is not a comment */';
world: '// neither is this';
what-ever: 100px;
/*this is not a comment?*/
background: url();
}
EOD;
$outputWithoutComments = <<<EOD
div {
border: 1px solid red;
color: url('http://mage-page.com');
string: "hello /* this is not a comment */";
world: "// neither is this";
string: 'hello /* this is not a comment */';
world: '// neither is this';
what-ever: 100px;
background: url(/*this is not a comment?*/);
}
EOD;
$this->assertEquals($this->compile($input), trim($outputWithoutComments));
$this->less->setPreserveComments(true);
$this->assertEquals($this->compile($input), trim($outputWithComments));
}
public function testOldInterface() {
$this->less = new lessc(__DIR__ . "/inputs/hi.less");
$out = $this->less->parse(array("hello" => "10px"));
$this->assertEquals(trim($out), trim('
div:before {
content: "hi!";
}'));
}
public function testInjectVars() {
$out = $this->less->parse(".magic { color: @color; width: @base - 200; }",
array(
'color' => 'red',
'base' => '960px'
));
$this->assertEquals(trim($out), trim("
.magic {
color: red;
width: 760px;
}"));
}
public function testDisableImport() {
$this->less->importDisabled = true;
$this->assertEquals(
"/* import disabled */",
$this->compile("@import 'file3';"));
}
public function testUserFunction() {
$this->less->registerFunction("add-two", function($list) {
list($a, $b) = $list[2];
return $a[1] + $b[1];
});
$this->assertEquals(
$this->compile("result: add-two(10, 20);"),
"result: 30;");
return $this->less;
}
/**
* @depends testUserFunction
*/
public function testUnregisterFunction($less) {
$less->unregisterFunction("add-two");
$this->assertEquals(
$this->compile("result: add-two(10, 20);"),
"result: add-two(10,20);");
}
public function testFormatters() {
$src = "
div, pre {
color: blue;
span, .big, hello.world {
height: 20px;
color:#ffffff + #000;
}
}";
$this->less->setFormatter("compressed");
$this->assertEquals(
$this->compile($src), "div,pre{color:blue;}div span,div .big,div hello.world,pre span,pre .big,pre hello.world{height:20px;color:#fff;}");
// TODO: fix the output order of tags
$this->less->setFormatter("lessjs");
$this->assertEquals(
$this->compile($src),
"div,
pre {
color: blue;
}
div span,
div .big,
div hello.world,
pre span,
pre .big,
pre hello.world {
height: 20px;
color: #ffffff;
}");
$this->less->setFormatter("classic");
$this->assertEquals(
$this->compile($src),
trim("div, pre { color:blue; }
div span, div .big, div hello.world, pre span, pre .big, pre hello.world {
height:20px;
color:#ffffff;
}
"));
}
public function compile($str) {
return trim($this->less->parse($str));
}
}

View File

@ -1,71 +0,0 @@
<?php
require_once __DIR__ . "/../lessc.inc.php";
// Runs all the tests in inputs/ and compares their output to ouputs/
function _dump($value) {
fwrite(STDOUT, print_r($value, true));
}
function _quote($str) {
return preg_quote($str, "/");
}
class InputTest extends PHPUnit_Framework_TestCase {
protected static $inputDir = "inputs";
protected static $outputDir = "outputs";
public function setUp() {
$this->less = new lessc();
$this->less->importDir = array(__DIR__ . "/" . self::$inputDir . "/test-imports");
}
/**
* @dataProvider fileNameProvider
*/
public function testInputFile($inFname) {
if ($pattern = getenv("BUILD")) {
return $this->buildInput($inFname);
}
$outFname = self::outputNameFor($inFname);
if (!is_readable($outFname)) {
$this->fail("$outFname is missing, ".
"consider building tests with BUILD=true");
}
$input = file_get_contents($inFname);
$output = file_get_contents($outFname);
$this->assertEquals($output, $this->less->parse($input));
}
public function fileNameProvider() {
return array_map(function($a) { return array($a); },
self::findInputNames());
}
// only run when env is set
public function buildInput($inFname) {
$css = $this->less->parse(file_get_contents($inFname));
file_put_contents(self::outputNameFor($inFname), $css);
}
static public function findInputNames($pattern="*.less") {
$files = glob(__DIR__ . "/" . self::$inputDir . "/" . $pattern);
return array_filter($files, "is_file");
}
static public function outputNameFor($input) {
$front = _quote(__DIR__ . "/");
$out = preg_replace("/^$front/", "", $input);
$in = _quote(self::$inputDir . "/");
$out = preg_replace("/$in/", self::$outputDir . "/", $out);
$out = preg_replace("/.less$/", ".css", $out);
return __DIR__ . "/" . $out;
}
}

View File

@ -1,13 +0,0 @@
lessphp uses [phpunit](https://github.com/sebastianbergmann/phpunit/) for it's tests
`InputTest.php` iterates through all the less files in `inputs/`, compiles them,
then compares the result with the respective file in `outputs/`.
From the root you can run `make` to run all the tests.
## bootstrap.sh
Clones twitter bootsrap, compiles it with lessc and lessphp, cleans up results
with sort.php, and outputs diff. To run it, you need to have git and lessc
installed.

View File

@ -1,38 +0,0 @@
#!/bin/sh
echo "This script clones Twitter Bootstrap, compiles it with lessc and lessphp,"
echo "cleans up results with sort.php, and outputs diff. To run it, you need to"
echo "have git and lessc installed."
echo ""
if [ -z "$input" ]; then
input="bootstrap/less/bootstrap.less"
fi
dest=$(basename "$input")
dest="${dest%.*}"
if [ -z "$@" ]; then
diff_tool="diff -b -u -t -B"
else
diff_tool=$@
fi
mkdir -p tmp
if [ ! -d 'bootstrap/' ]; then
echo ">> Cloning bootstrap to bootstrap/"
git clone https://github.com/twitter/bootstrap
fi
echo ">> lessc compilation ($input)"
lessc "$input" "tmp/$dest.lessc.css"
echo ">> lessphp compilation ($input)"
../plessc "$input" "tmp/$dest.lessphp.css"
echo ">> Cleanup and convert"
php sort.php "tmp/$dest.lessc.css" > "tmp/$dest.lessc.clean.css"
php sort.php "tmp/$dest.lessphp.css" > "tmp/$dest.lessphp.clean.css"
echo ">> Doing diff"
$diff_tool "tmp/$dest.lessc.clean.css" "tmp/$dest.lessphp.clean.css"

View File

@ -1,36 +0,0 @@
/* accessors */
#defaults {
@width: 960px;
@color: black;
.something {
@space: 10px;
@hello {
color: green;
}
}
}
.article { color: #294366; }
.comment {
width: #defaults[@width];
color: .article['color'];
padding: #defaults > .something[@space];
}
.wow {
height: .comment['width'];
background-color: .comment['color'];
color: #defaults > .something > @hello['color'];
padding: #defaults > non-existant['padding'];
margin: #defaults > .something['non-existant'];
}
.mix {
#defaults;
font-size: .something[@space];
}

View File

@ -1,77 +0,0 @@
// simple arity
.hello(@a) {
color: one;
}
.hello(@a, @b) {
color: two;
}
.hello(@a, @b, @c) {
color: three;
}
.world(@a, @b, @c) {
color: three;
}
.world(@a, @b) {
color: two;
}
.world(@a) {
color: one;
}
.one {
.hello(1);
.world(1);
}
.two {
.hello(1, 1);
.world(1, 1);
}
.three {
.hello(1, 1, 1);
.world(1, 1, 1);
}
// arity with default values
.foo(@a, @b: cool) {
color: two;
}
.foo(@a, @b: cool, @c: yeah) {
color: three;
}
.baz(@a, @b, @c: yeah) {
color: three;
}
.baz(@a, @b: cool) {
color: two;
}
.multi-foo {
.foo(1);
.foo(1, 1);
.foo(1,1,1);
}
.multi-baz {
.baz(1);
.baz(1, 1);
.baz(1,1,1);
}

View File

@ -1,41 +0,0 @@
* { color: blue; }
E { color: blue; }
E[foo] { color: blue; }
[foo] { color: blue; }
[foo] .helloWorld { color: blue; }
[foo].helloWorld { color: blue; }
E[foo="barbar"] { color: blue; }
E[foo~="hello#$@%@$#^"] { color: blue; }
E[foo^="color: green;"] { color: blue; }
E[foo$="239023"] { color: blue; }
E[foo*="29302"] { color: blue; }
E[foo|="239032"] { color: blue; }
E:root { color: blue; }
E:nth-child(odd) { color: blue; }
E:nth-child(2n+1) { color: blue; }
E:nth-child(5) { color: blue; }
E:nth-last-child(-n+2) { color: blue; }
E:nth-of-type(2n) { color: blue; }
E:nth-last-of-type(n) { color: blue; }
E:first-child { color: blue; }
E:last-child { color: blue; }
E:first-of-type { color: blue; }
E:last-of-type { color: blue; }
E:only-child { color: blue; }
E:only-of-type { color: blue; }
E:empty { color: blue; }
E:lang(en) { color: blue; }
E::first-line { color: blue; }
E::before { color: blue; }
E#id { color: blue; }
E:not(:link) { color: blue; }
E F { color: blue; }
E > F { color: blue; }
E + F { color: blue; }
E ~ F { color: blue; }

View File

@ -1,73 +0,0 @@
// builtin
@something: "hello world";
@color: #112233;
@color2: rgba(44,55,66, .6);
body {
color: @something;
@num: 7 / 6;
height: @num + 4;
height: floor(@num) + 4px;
height: ceil(@num) + 4px;
@num2: 2 / 3;
width: @num2;
width: round(@num2);
width: floor(@num2);
width: ceil(@num2);
width: round(10px / 3);
color: rgbahex(@color);
color: rgbahex(@color2);
color: argb(@color2);
}
format {
@r: 32;
format: %("rgb(%d, %d, %d)", @r, 128, 64);
format-string: %("hello %s", "world");
format-multiple: %("hello %s %d", "earth", 2);
format-url-encode: %('red is %A', #ff0000);
eformat: e(%("rgb(%d, %d, %d)", @r, 128, 64));
}
#functions {
str: isstring("hello");
str: isstring(one, two);
num: isnumber(2323px);
num: isnumber(2323);
num: isnumber(4/5);
num: isnumber("hello");
col: iscolor(red);
col: iscolor(hello);
col: iscolor(rgba(0,0,0,0.3));
col: iscolor(#fff);
key: iskeyword(hello);
key: iskeyword(3D);
px: ispixel(10px);
px: ispixel(10);
per: ispercentage(10%);
per: ispercentage(10);
em: isem(10em);
em: isem(10);
}
#unit {
@unit: "em";
height: unit(10px);
height: unit(10px, "s");
height: unit(10px, @unit);
height: unit(0.07407s) * 100%;
}

View File

@ -1,153 +0,0 @@
body {
color:rgb(red(#f00), red(#0F0), red(#00f));
color:rgb(red(#f00), green(#0F0), blue(#00f));
color:rgb(red(#0ff), green(#f0f), blue(#ff0));
color: hsl(34, 50%, 40%);
color: hsla(34, 50%, 40%, 0.3);
lighten: lighten(#efefef, 10%);
lighten: lighten(rgb(23, 53, 231), 22%);
lighten: lighten(rgba(212, 103, 88, 0.5), 10%);
darken: darken(#efefef, 10%);
darken: darken(rgb(23, 53, 231), 22%);
darken: darken(rgba(23, 53, 231, 0.5), 10%);
saturate: saturate(#efefef, 10%);
saturate: saturate(rgb(23, 53, 231), 22%);
saturate: saturate(rgba(23, 53, 231, 0.5), 10%);
desaturate: desaturate(#efefef, 10%);
desaturate: desaturate(rgb(23, 53, 231), 22%);
desaturate: desaturate(rgba(23, 53, 231, 0.5), 10%);
spin: spin(#efefef, 12);
spin: spin(rgb(23, 53, 231), 15);
spin: spin(rgba(23, 53, 231, 0.5), 19);
spin: spin(#efefef, -12);
spin: spin(rgb(23, 53, 231), -15);
spin: spin(rgba(23, 53, 231, 0.5), -19);
one: fadein(#abcdef, 10%);
one: fadeout(#abcdef, -10%);
two: fadeout(#029f23, 10%);
two: fadein(#029f23, -10%);
three: fadein(rgba(1,2,3, 0.5), 10%);
three: fadeout(rgba(1,2,3, 0.5), -10%);
four: fadeout(rgba(1,2,3, 0), 10%);
four: fadein(rgba(1,2,3, 0), -10%);
hue: hue(rgb(34,20,40));
sat: saturation(rgb(34,20,40));
lit: lightness(rgb(34,20,40));
@old: #34fa03;
@new: hsl(hue(@old), 45%, 90%);
what: @new;
zero: saturate(#123456, -100%);
zero: saturate(#123456, 100%);
zero: saturate(#000000, 100%);
zero: saturate(#ffffff, 100%);
zero: lighten(#123456, -100%);
zero: lighten(#123456, 100%);
zero: lighten(#000000, 100%);
zero: lighten(#ffffff, 100%);
zero: spin(#123456, -100);
zero: spin(#123456, 100);
zero: spin(#000000, 100);
zero: spin(#ffffff, 100);
}
alpha {
// g: alpha(red);
g: alpha(rgba(0,0,0,0));
g: alpha(rgb(155,55,0));
}
fade {
f: fade(red, 50%);
f: fade(#fff, 20%);
f: fade(rgba(34,23,64,0.4), 50%);
}
@a: rgb(255,255,255);
@b: rgb(0,0,0);
.mix {
color: mix(@a, @b, 50%);
color: mix(rgba(5,3,1,0.3), rgba(6,3,2, 0.8), 50%);
}
.contrast {
color: contrast(#000, red, blue);
color: contrast(#fff, red, blue);
}
.percent {
per: percentage(0.5);
}
// color keywords
.colorz {
color: whitesmoke - 10;
color: spin(red, 34);
color: spin(blah);
}
// purposfuly whacky to match less.js
@color: #fcf8e3;
body {
start: @color;
spin: spin(@color, -10); // #fcf4e3
chained: darken(spin(@color, -10), 3%); // gives #fbeed5, should be #fbefd5
direct: darken(#fcf4e3, 3%); // #fbefd5
}
// spin around
pre {
@errorBackground: #f2dede;
spin: spin(@errorBackground, -10);
}
dd {
@white: #fff;
background-color: mix(@white, darken(@white, 10%), 60%);
}
// math
.ops {
c: red * 0.3;
c: green / 2;
c: purple % 7;
c: 4 * salmon;
c: 1 + salmon;
c: 132 / red;
c: 132 - red;
c: 132- red;
}
.transparent {
r: red(transparent);
g: green(transparent);
b: blue(transparent);
a: alpha(transparent);
}

View File

@ -1,39 +0,0 @@
@mixin {
height: 22px;
ul {
height: 20px;
li {
@color: red;
height: 10px;
div span, link {
margin: 10px;
color: @color;
}
}
div, p {
border: 1px;
&.hello {
color: green;
}
:what {
color: blue;
}
}
a {
b {
color: blue;
}
}
}
}
body {
@mixin;
}

View File

@ -1,15 +0,0 @@
@hello: "utf-8";
@charset @hello;
@-moz-document url-prefix(){
div {
color: red;
}
}
@page :left { margin-left: 4cm; }
@page :right { margin-left: 3cm; }
@page { margin: 2cm }

View File

@ -1,20 +0,0 @@
body {
@hello: "world";
border: e("this is simple");
border: e(this is simple); // bug in lessjs
border: e("this is simple", "cool lad");
border: e(1232);
border: e(@hello);
border: e("one" + 'more'); // no string addition lessjs
border: e(); // syntax error lessjs
line-height: ~"eating rice";
line-height: ~"string cheese";
line-height: a b c ~"string me" d e f;
line-height: ~"string @{hello}";
}
.class {
filter: ~"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='image.png')";
}

View File

@ -1,28 +0,0 @@
@font-directory: 'fonts/';
@some-family: Gentium;
@font-face: maroon; // won't collide with @font-face { }
@font-face {
font-family: Graublau Sans Web;
src: url(@{font-directory}GraublauWeb.otf) format("opentype");
}
@font-face {
font-family: @some-family;
src: url('@{font-directory}Gentium.ttf');
}
@font-face {
font-family: @some-family;
src: url("@{font-directory}GentiumItalic.ttf");
font-style: italic;
}
h2 {
font-family: @some-family;
crazy: @font-face;
}

View File

@ -1,88 +0,0 @@
.simple(@hi) when (@hi) {
color: yellow;
}
.something(@hi) when (@hi = cool) {
color: red;
}
.another(@x) when (@x > 10) {
color: green;
}
.flipped(@x) when (@x =< 10) {
color: teal;
}
.yeah(@arg) when (isnumber(@arg)) {
color: purple;
}
.yeah(@arg) when (ispixel(@arg)) {
color: silver;
}
.hello(@arg) when not (@arg) {
color: orange;
}
dd {
.simple(true);
.simple(2344px);
}
b {
.something(cool);
.something(birthday);
}
img {
.another(12);
.another(2);
.flipped(12);
.flipped(2);
}
body {
.yeah("world");
.yeah(232px);
.yeah(232);
.hello(true);
}
.something(@x) when (@x) and (@y), not (@x = what) {
color: blue;
}
div {
@y: true;
.something(true);
}
pre {
.something(what);
}
.coloras(@g) when (iscolor(@g)) {
color: true @g;
}
link {
.coloras(red);
.coloras(10px);
.coloras(ffjref);
.coloras(#fff);
.coloras(#fffddd);
.coloras(rgb(0,0,0));
.coloras(rgba(0,0,0, .34));
}

View File

@ -1,6 +0,0 @@
// css hacks
:root .alert-message, :root .btn {
border-radius: 0 \0;
}

View File

@ -1,5 +0,0 @@
div:before {
content: "hi!";
}

View File

@ -1,12 +0,0 @@
foo {
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=1, startColorstr=#c0ff3300, endColorstr=#ff000000);
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=1, startColorstr=#c0ff3300, endColorstr=#ff000000);
}
foo {
filter: alpha(opacity=20);
filter: alpha(opacity=20, enabled=true);
filter: blaznicate(foo=bar, baz=bang bip, bart=#fa4600);
}

View File

@ -1,56 +0,0 @@
@import 'file1.less'; // file found and imported
@import "not-found";
@import "something.css" media;
@import url("something.css") media;
@import url(something.css) media, screen, print;
@color: maroon;
@import url(file2); // found and imported
body {
line-height: 10em;
@colors;
}
div {
@color: fuchsia;
@import "file2";
}
.mixin-import() {
@import "file3";
}
.one {
.mixin-import();
color: blue;
}
.two {
.mixin-import();
}
#merge-import-mixins {
@import "a";
@import "b";
div { .just-a-class; }
}
@import "inner/file1";
// test bubbling variables up from imports, while preserving order
pre {
color: @someValue;
}
@import "file3";

View File

@ -1,33 +0,0 @@
@cool-hello: "yes";
@cool-yes: "okay";
@var: "hello";
div {
color: ~"@{cool-hello}";
color: ~"@{cool-@{var}}";
color: ~"@{cool-@{cool-@{var}}}";
}
// interpolation in selectors
@hello: 10;
@world: "yeah";
@{hello}@{world} {
color: blue;
}
@{hello} {
color: blue;
}
hello world @{hello} {
color: red;
}
#@{world} {
color: "hello @{hello}";
}

View File

@ -1,52 +0,0 @@
@keyframes 'bounce' {
from {
top: 100px;
animation-timing-function: ease-out;
}
25% {
top: 50px;
animation-timing-function: ease-in;
}
50% {
top: 100px;
animation-timing-function: ease-out;
}
75% {
top: 75px;
animation-timing-function: ease-in;
}
to {
top: 100px;
}
}
@-webkit-keyframes flowouttoleft {
0% { -webkit-transform: translateX(0) scale(1); }
60%, 70% { -webkit-transform: translateX(0) scale(.7); }
100% { -webkit-transform: translateX(-100%) scale(.7); }
}
div {
animation-name: 'diagonal-slide';
animation-duration: 5s;
animation-iteration-count: 10;
}
@keyframes 'diagonal-slide' {
from {
left: 0;
top: 0;
}
to {
left: 100px;
top: 100px;
}
}

View File

@ -1,121 +0,0 @@
.unary {
// all operators are parsable as unary operators, anything
// but - throws an error right now though,
// this gives two numbers
sub: 10 -5;
// add: 10 +5; // error
// div: 10 /5; // error
// mul: 10 *5; // error
}
.spaces {
// we can make the parser do math by leaving out the
// space after the first value, or putting spaces on both sides
sub: 10-5;
sub: 10 - 5;
add: 10+5;
add: 10 + 5;
// div: 10/5; // this wont work, read on
div: 10 / 5;
mul: 10*5;
mul: 10 * 5;
}
// these properties have divison not in parenthases
.supress-division {
border-radius: 10px / 10px;
border-radius: 10px/10px;
border-radius: hello (10px/10px) world;
@x: 10px;
font: @x/30 sans-serif;
font: 10px / 20px sans-serif;
font: 10px/20px sans-serif;
border-radius:0 15px 15px 15px / 0 50% 50% 50%;
}
.parens {
// if you are unsure, then just wrap the expression in parentheses and it will
// always evaluate.
// notice we no longer have unary operators, and these will evaluate
sub: (10 -5);
add: (10 +5);
div: (10 /5);
div: (10/5); // no longer interpreted as the shorthand
mul: (10 *5);
}
.keyword-names {
// watch out when doing math with keywords, - is a valid keyword character
@a: 100;
@b: 25;
@a-: "hello";
height: @a-@b; // here we get "hello" 25, not 75
}
.negation {
hello: -(1px);
hello: 0-(1px);
@something: 10;
hello: -@something;
}
// and now here are the tests
.test {
single: (5);
single: 5+(5);
single: (5)+((5));
parens: (5 +(5)) -2;
// parens: ((5 +(5)) -2); // FAILS - fixme
math: (5 + 5)*(2 / 1);
math: (5+5)*(2/1);
width: 2 * (4 * (2 + (1 + 6))) - 1;
height: ((2+3)*(2+3) / (9-4)) + 1;
padding: (2px + 4px) 1em 2px 2;
@var: (2 * 2);
padding: (2 * @var) 4 4 (@var * 1px);
width: (@var * @var) * 6;
height: (7 * 7) + (8 * 8);
margin: 4 * (5 + 5) / 2 - (@var * 2);
}
.percents {
color: 100 * 10%;
color: 10% * 100;
color: 10% * 10%;
color: 100px * 10%; // lessjs makes this px
color: 10% * 100px; // lessjs makes this %
color: 20% + 10%;
color: 20% - 10%;
color: 20% / 10%;
}
.misc {
x: 10px * 4em;
y: 10 * 4em;
}
.cond {
y: 10 < 10;
y: 10 >= 10;
}

View File

@ -1,68 +0,0 @@
@media screen, 3D {
P { color: green; }
}
@media print {
body { font-size: 10pt }
}
@media screen {
body { font-size: 13px }
}
@media screen, print {
body { line-height: 1.2 }
}
@media all and (min-width: 0px) {
body { line-height: 1.2 }
}
@media all and (min-width: 0) {
body { line-height: 1.2 }
}
@media
screen and (min-width: 102.5em) and (max-width: 117.9375em),
screen and (min-width: 150em) {
body { color: blue }
}
@media screen and (min-height: 100px + 10px) {
body { color: red; }
}
@cool: 100px;
@media screen and (height: @cool) and (width: @cool + 10), (size: @cool + 20) {
body { color: red; }
}
// media bubbling
@media test {
div {
height: 20px;
@media (hello) {
color: red;
pre {
color: orange;
}
}
}
}
// should not cross boundary
@media yeah {
@page {
@media cool {
color: red;
}
}
}
// variable in query
@mobile: ~"(max-width: 599px)";
@media @mobile {
.helloworld { color: blue }
}

View File

@ -1,93 +0,0 @@
@color: #fff;
@base_path: "/assets/images/";
@images: @base_path + "test/";
.topbar { background: url(@{images}topbar.png); }
.hello { test: empty-function(@images, 40%, to(@color)); }
.css3 {
background-image: -webkit-gradient(linear, 0% 0%, 0% 90%,
from(#E9A000), to(#A37000));
}
/**
Here is a block comment
**/
// this is a comment
.test, /*hello*/.world {
border: 1px solid red; // world
/* another property */
color: url(http://mage-page.com);
string: "hello /* this is not a comment */";
world: "// neither is this";
string: 'hello /* this is not a comment */' /*what if this is a comment */;
world: '// neither is this' // hell world;
;
what-/*something?*/ever: 100px;
background: url(/*no comment here*/);
}
.urls {
@var: "http://google.com";
background: url(@var);
background: url(@{var});
background: url("@{var}");
}
.mix(@arg) { color: @arg; }
@aaa: aaa;
@bbb: bbb;
// make sure the opening selector isn't too greedy
.cool {.mix("@{aaa}, @{bbb}")}
.cool();
.cool("{hello");
.cool('{hello');
// merging of mixins
.span-17 { float: left; }
.span-17 { width: 660px; }
.x {.span-17;}
.hi {
pre {
color: red;
}
}
.hi {
pre {
color: blue;
}
}
.rad {
.hi;
}
hello {
numbers: 1.0 0.1 .1 1.;
numbers: 1.0s 0.1s .1s 1.s;
numbers: -1.0s -0.1s -.1s -1.s;
numbers: -1.0 -0.1 -.1 -1.;
}
#string {
hello: 'what\'s going on here';
hello: 'blah blag @{ blah blah';
join: 3434 + "hello";
join: 3434 + hello;
}

View File

@ -1,40 +0,0 @@
@outer: 10px;
@class(@var:22px, @car: 400px + @outer) {
margin: @var;
height: @car;
}
@group {
@f(@color) {
color: @color;
}
.cool {
border-bottom: 1px solid green;
}
}
.class(@width:200px) {
padding: @width;
}
body {
.class(2.0em);
@group > @f(red);
@class(10px, 10px + 2);
@group > .cool;
}
@lots(@a: 10px, @b: 20px, @c: 30px, @d: 40px, @e: 4px, @f:3px, @g:2px, @h: 1px) {
padding: @a @b @c @d;
margin: @e @f @g @h;
}
.skip_args {
@class(,12px);
@lots(,,,88px,,12px);
@group > @f(red,,,,);
@group > @f(red);
}

View File

@ -1,100 +0,0 @@
@tester {
p, div { height: 10px; }
}
#test1 {
div { color: red; }
@tester;
}
@cool {
a,b,i { width: 1px; }
}
#test2 {
b { color: red; }
@cool;
}
#test3 {
@cool;
b { color: red; }
}
@cooler {
a { margin: 1px; }
}
#test4 {
a, div, html { color: blue; }
@cooler;
}
@hi {
img, strong { float: right; }
}
#test5 {
img, strong { padding: 2px; }
@hi;
}
@nested {
div, span {
a {
color: red;
}
}
}
#test6 {
div, span {
a {
line-height: 10px;
}
}
@nested;
}
@broken-nesting {
div, span {
strong, b {
color: red;
}
}
}
#test7 {
div {
strong {
margin: 1px;
}
}
@broken-nesting;
}
@another-nest {
a,b {
i {
color: red;
}
s {
color: blue;
}
}
}
#test8 {
a, b {
i,s {
background: red;
}
}
@another-nest;
}

View File

@ -1,159 +0,0 @@
@rounded-corners {
border-radius: 10px;
}
.bold {
@font-size: 20px;
font-size: @font-size;
font-weight: bold;
}
body #window {
@rounded-corners;
.bold;
line-height: @font-size * 1.5;
}
#bundle {
.button {
display: block;
border: 1px solid black;
background-color: grey;
&:hover { background-color: white }
}
}
#header a {
color: orange;
#bundle > .button; // mixin the button class
}
div {
@abstract {
hello: world;
b {
color: blue;
}
}
@abstract > b;
@abstract;
}
@poop {
big: baby;
}
body {
div;
}
// not using > to list mixins
.hello {
.world {
color: blue;
}
}
.foobar {
.hello .world;
}
.butter {
.this .one .isnt .found;
}
// arguments
.spam(@something: 100, @dad: land) {
@wow: 23434;
foo: @arguments;
bar: @arguments;
}
.eggs {
.spam(1px, 2px);
.spam();
}
.first(@one, @two, @three, @four: cool) {
cool: @arguments;
}
#hello {
.first(one, two, three);
}
#hello-important {
.first(one, two, three) !important;
}
.rad(@name) {
cool: @arguments;
}
#world {
@hello: "world";
.rad("@{hello}");
}
.second(@x, @y:skip, @z: me) {
things: @arguments;
}
#another {
.second(red, blue, green);
.second(red blue green);
}
.another(@x, @y:skip, @z:me) {
.cool {
color: @arguments;
}
}
#day {
.another(one,two, three);
.another(one two three);
}
.to-be-important() {
color: red;
@color: red;
height: 20px;
pre {
color: @color;
}
}
.mix-suffix {
.to-be-important() !important;
}
#search-all {
.red() {
color:#f00 !important;
}
}
#search-all {
.green() {
color: #0f0 !important;
}
}
.search-test {
#search-all > .red();
#search-all > .green();
}

View File

@ -1,60 +0,0 @@
#header {
color: black;
.navigation {
font-size: 12px;
.border {
.outside {
color: blue;
}
}
}
.logo {
width: 300px;
&:hover { text-decoration: none }
}
}
a { b { ul { li { color: green; } } } }
this { will { not { show { } } } }
.cool {
div & { color: green; }
p & span { color: yellow; }
}
another {
.cool;
}
b {
& .something {
color: blue;
}
&.something {
color: blue;
}
}
.foo {
.bar, .baz {
& .qux {
display: block;
}
.qux & {
display: inline;
}
.qux & .biz {
display: none;
}
}
}
b {
hello [x="&yeah"] {
color: red;
}
}

View File

@ -1,167 +0,0 @@
.demo (light, @color) {
color: lighten(@color, 10%);
}
.demo (@_, @color) {
display: block;
}
@switch: light;
.class {
.demo(@switch, #888);
}
// by arity
.mixin () {
zero: 0;
}
.mixin (@a: 1px) {
one: 1;
}
.mixin (@a) {
one-req: 1;
}
.mixin (@a: 1px, @b: 2px) {
two: 2;
}
.mixin (@a, @b, @c) {
three-req: 3;
}
.mixin (@a: 1px, @b: 2px, @c: 3px) {
three: 3;
}
.zero {
.mixin();
}
.one {
.mixin(1);
}
.two {
.mixin(1, 2);
}
.three {
.mixin(1, 2, 3);
}
//
.mixout ('left') {
left: 1;
}
.mixout ('right') {
right: 1;
}
.left {
.mixout('left');
}
.right {
.mixout('right');
}
//
.border (@side, @width) {
color: black;
.border-side(@side, @width);
}
.border-side (left, @w) {
border-left: @w;
}
.border-side (right, @w) {
border-right: @w;
}
.border-right {
.border(right, 4px);
}
.border-left {
.border(left, 4px);
}
//
.border-radius (@r) {
both: @r * 10;
}
.border-radius (@r, left) {
left: @r;
}
.border-radius (@r, right) {
right: @r;
}
.only-right {
.border-radius(33, right);
}
.only-left {
.border-radius(33, left);
}
.left-right {
.border-radius(33);
}
.hola(hello, @hello...) {
color: blue;
}
#hola {
.hola(hello, world);
.hola(jello, world);
}
.resty(@hello, @world, @the_rest...) {
padding: @hello @world;
rest: @the_rest;
}
#nnn {
.body(10, 10, 10, 10, 10);
.body(10, 10, 10);
.body(10, 10);
.body(10);
.body();
}
.defaults(@aa, @bb:e343, @cc: "heah", ...) {
height: @aa;
}
#defaults_1 {
.defaults();
.defaults(one);
.defaults(two, one);
.defaults(three, two, one);
.defaults(four, three, two, one);
}
.thing() { color: green; }
.thing(...) { color: blue; }
.thing { color: red; }
#aa {
.thing();
}
#bb {
.thing;
}
#cc {
.thing(1);
}

View File

@ -1,40 +0,0 @@
@a: 10;
@some {
@b: @a + 10;
div {
@c: @b + 10;
other {
@d: @c + 10;
world {
@e: @d + 10;
height: @e;
}
}
}
}
body {
@some;
}
@some;
.test(@x: 10) {
height: @x;
.test(@y: 11) {
height: @y;
.test(@z: 12) {
height: @z;
}
.test;
}
.test;
}
pre {
.test;
}

View File

@ -1,29 +0,0 @@
@color: blue;
(~"something @{color}"), world {
color: blue;
}
.div {
@color: red;
(3434) {
height: 100px;
}
(~"cool @{color}") {
height: 4000px;
}
}
.heck(@a) { color: @a+10 }
.spanX (@index) when (@index > 0) {
(~".span@{index}") { .heck(@index) }
.spanX(@index - 1);
}
.spanX (0) {}
.spanX (5);

View File

@ -1,120 +0,0 @@
// these are the demos from the lessphp homepage
default {
@base: 24px;
@border-color: #B2B;
.underline { border-bottom: 1px solid green }
#header {
color: black;
border: 1px solid @border-color + #222222;
.navigation {
font-size: @base / 2;
a {
.underline;
}
}
.logo {
width: 300px;
&:hover { text-decoration: none }
}
}
}
variables {
@a: 2;
@x: @a * @a;
@y: @x + 1;
@z: @x * 2 + @y;
@nice-blue: #5B83AD;
@light-blue: @nice-blue + #111;
@b: @a * 10;
@c: #888;
@fonts: "Trebuchet MS", Verdana, sans-serif;
.variables {
width: @z + 1cm; // 14cm
height: @b + @x + 0px; // 24px
color: @c;
background: @light-blue;
font-family: @fonts;
}
}
mixins {
.bordered {
border-top: dotted 1px black;
border-bottom: solid 2px black;
}
#menu a {
color: #111;
.bordered;
}
.post a {
color: red;
.bordered;
}
}
nested-rules {
#header {
color: black;
.navigation {
font-size: 12px;
}
.logo {
width: 300px;
&:hover { text-decoration: none }
}
}
}
namespaces {
#bundle {
.button {
display: block;
border: 1px solid black;
background-color: grey;
&:hover { background-color: white }
}
}
#header a {
color: orange;
#bundle > .button; // mixin the button class
}
}
mixin-functions {
@outer: 10px;
@class(@var:22px, @car: 400px + @outer) {
margin: @var;
height: @car;
}
@group {
@f(@color) {
color: @color;
}
.cool {
border-bottom: 1px solid green;
}
}
.class(@width:200px) {
padding: @width;
}
body {
.class(2.0em);
@group > @f(red);
@class(10px, 10px + 2);
@group > .cool;
}
}

View File

@ -1,6 +0,0 @@
.just-a-class { background: red; }
.some-mixin() {
height: 200px;
}

View File

@ -1,12 +0,0 @@
.just-a-class { background: blue; }
.hello {
.some-mixin();
}
@media cool {
color: red;
.some-mixin();
}

View File

@ -1,16 +0,0 @@
/**
* This is a test import file
*/
@colors {
div.bright {
color: red;
}
div.sad {
color: blue;
}
}

View File

@ -1,6 +0,0 @@
b {
color: @color;
padding: 16px;
}

View File

@ -1,7 +0,0 @@
h2 {
background: url("../images/logo.png") no-repeat;
}
@someValue: hello-from-file-3;

View File

@ -1,6 +0,0 @@
.inner {
content: "inner/file1.less"
}
@import "file2"; // should get the one in inner

View File

@ -1,4 +0,0 @@
.inner {
content: "inner/file2.less"
}

View File

@ -1,45 +0,0 @@
@a: 2;
@x: @a * @a;
@y: @x + 1;
@z: @y + @x * 2;
@m: @z % @y;
@nice-blue: #5B83AD;
@light-blue: @nice-blue + #111;
@rgb-color: rgb(20%, 15%, 80%);
@rgba-color: rgba(23,68,149,0.5);
@b: @a * 10px;
@c: #888;
@fonts: "Trebuchet MS", Verdana, sans-serif;
.variables {
width: @z + 1cm; // 14cm
height: @b + @x + 0px; // 24px
margin-top: -@b; // -20px
margin-bottom: 10 - -@b; // 30px
@d: @c + #001;
color: @d;
background: @light-blue;
font-family: @fonts;
margin: @m + 0px; // 3px
font: 10px/12px serif;
font: 120%/120% serif;
}
.external {
color: @c;
border: 1px solid @rgb-color;
background: @rgba-color;
padding: @nonexistant + 4px;
}
@hello: 44px;
@something: "hello";
@cool: something;
color: @@something;
color: @@@cool;

View File

@ -1,14 +0,0 @@
.article { color:#294366; }
.comment {
width:960px;
color:#294366;
padding:10px;
}
.wow {
height:960px;
background-color:#294366;
color:green;
padding:;
margin:;
}
.mix { font-size:10px; }

View File

@ -1,25 +0,0 @@
.one {
color: one;
color: one;
}
.two {
color: two;
color: two;
}
.three {
color: three;
color: three;
}
.multi-foo {
color: two;
color: three;
color: two;
color: three;
color: three;
}
.multi-baz {
color: two;
color: three;
color: two;
color: three;
}

View File

@ -1,105 +0,0 @@
* {
color: blue;
}
E {
color: blue;
}
E[foo] {
color: blue;
}
[foo] {
color: blue;
}
[foo] .helloWorld {
color: blue;
}
[foo].helloWorld {
color: blue;
}
E[foo="barbar"] {
color: blue;
}
E[foo~="hello#$@%@$#^"] {
color: blue;
}
E[foo^="color: green;"] {
color: blue;
}
E[foo$="239023"] {
color: blue;
}
E[foo*="29302"] {
color: blue;
}
E[foo|="239032"] {
color: blue;
}
E:root {
color: blue;
}
E:nth-child(odd) {
color: blue;
}
E:nth-child(2n+1) {
color: blue;
}
E:nth-child(5) {
color: blue;
}
E:nth-last-child(-n+2) {
color: blue;
}
E:nth-of-type(2n) {
color: blue;
}
E:nth-last-of-type(n) {
color: blue;
}
E:first-child {
color: blue;
}
E:last-child {
color: blue;
}
E:first-of-type {
color: blue;
}
E:last-of-type {
color: blue;
}
E:only-child {
color: blue;
}
E:only-of-type {
color: blue;
}
E:empty {
color: blue;
}
E:lang(en) {
color: blue;
}
E::first-line {
color: blue;
}
E::before {
color: blue;
}
E#id {
color: blue;
}
E:not(:link) {
color: blue;
}
E F {
color: blue;
}
E > F {
color: blue;
}
E + F {
color: blue;
}
E ~ F {
color: blue;
}

View File

@ -1,47 +0,0 @@
body {
color: "hello world";
height: 5.1666666666667;
height: 5px;
height: 6px;
width: 0.66666666666667;
width: 1;
width: 0;
width: 1;
width: 3px;
color: #ff112233;
color: #992c3742;
color: #992c3742;
}
format {
format: "rgb(32, 128, 64)";
format-string: "hello world";
format-multiple: "hello earth 2";
format-url-encode: 'red is %A';
eformat: rgb(32, 128, 64);
}
#functions {
str: true;
str: false;
num: true;
num: true;
num: true;
num: false;
col: true;
col: false;
col: true;
col: true;
key: true;
key: false;
px: true;
px: false;
per: true;
per: false;
em: true;
em: false;
}
#unit {
height: 10;
height: 10s;
height: 10em;
height: 7.407%;
}

View File

@ -1,102 +0,0 @@
body {
color: #ff0000;
color: #ffffff;
color: #000000;
color: #996d33;
color: rgba(153,109,51,0.3);
lighten: #ffffff;
lighten: #7c8df2;
lighten: rgba(222,140,129,0.5);
darken: #d6d6d6;
darken: #0d1e81;
darken: rgba(18,42,185,0.5);
saturate: #f1eded;
saturate: #0025fe;
saturate: rgba(10,44,244,0.5);
desaturate: #efefef;
desaturate: #3349cb;
desaturate: rgba(36,62,218,0.5);
spin: #efefef;
spin: #2d17e7;
spin: rgba(59,23,231,0.5);
spin: #efefef;
spin: #1769e7;
spin: rgba(23,119,231,0.5);
one: #abcdef;
one: #abcdef;
two: rgba(2,159,35,0.9);
two: rgba(2,159,35,0.9);
three: rgba(1,2,3,0.6);
three: rgba(1,2,3,0.6);
four: rgba(1,2,3,0);
four: rgba(1,2,3,0);
hue: 282;
sat: 33;
lit: 12;
what: #dff1da;
zero: #343434;
zero: #003468;
zero: #000000;
zero: #ffffff;
zero: #000000;
zero: #ffffff;
zero: #ffffff;
zero: #ffffff;
zero: #1d5612;
zero: #56124b;
zero: #000000;
zero: #ffffff;
}
alpha {
g: 0;
g: 1;
}
fade {
f: rgba(255,0,0,0.5);
f: rgba(255,255,255,0.2);
f: rgba(34,23,64,0.5);
}
.mix {
color: #808080;
color: rgba(6,3,2,-0.25);
}
.contrast {
color: #0000ff;
color: #ff0000;
}
.percent {
per: 50%;
}
.colorz {
color: #ebebeb;
color: #ff9100;
color: #000000;
}
body {
start: #fcf8e3;
spin: #fcf4e3;
chained: #fbeed5;
direct: #fbefd5;
}
pre {
spin: #f2dee1;
}
dd {
background-color: #f5f5f5;
}
.ops {
c: #4d0000;
c: #004000;
c: #020002;
c: #ffffff;
c: #fb8173;
c: 132 / #ff0000;
c: 132 - #ff0000;
c: 132- #ff0000;
}
.transparent {
r: 0;
g: 0;
b: 0;
a: 0;
}

View File

@ -1,29 +0,0 @@
body {
height: 22px;
}
body ul {
height: 20px;
}
body ul li {
height: 10px;
}
body ul li div span,
body ul li link {
margin: 10px;
color: red;
}
body ul div,
body ul p {
border: 1px;
}
body ul div.hello,
body ul p.hello {
color: green;
}
body ul div :what,
body ul p :what {
color: blue;
}
body ul a b {
color: blue;
}

View File

@ -1,15 +0,0 @@
@charset "utf-8";
@-moz-document url-prefix() {
div {
color: red;
}
}
@page :left {
margin-left: 4cm;
}
@page :right {
margin-left: 3cm;
}
@page {
margin: 2cm;
}

View File

@ -1,16 +0,0 @@
body {
border: this is simple;
border: this;
border: this is simple;
border: 1232;
border: world;
border: onemore;
border: ;
line-height: eating rice;
line-height: string cheese;
line-height: a b c string me d e f;
line-height: string world;
}
.class {
filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='image.png');
}

View File

@ -1,17 +0,0 @@
@font-face {
font-family: Graublau Sans Web;
src: url(fonts/GraublauWeb.otf) format("opentype");
}
@font-face {
font-family: Gentium;
src: url('fonts/Gentium.ttf');
}
@font-face {
font-family: Gentium;
src: url("fonts/GentiumItalic.ttf");
font-style: italic;
}
h2 {
font-family: Gentium;
crazy: maroon;
}

View File

@ -1,27 +0,0 @@
dd {
color: yellow;
}
b {
color: red;
color: blue;
color: blue;
}
img {
color: green;
color: teal;
}
body {
color: purple;
color: silver;
color: purple;
}
div {
color: blue;
}
link {
color: true red;
color: true #fff;
color: true #fffddd;
color: true #000000;
color: true rgba(0,0,0,0.34);
}

View File

@ -1,4 +0,0 @@
:root .alert-message,
:root .btn {
border-radius: 0 \0;
}

View File

@ -1,3 +0,0 @@
div:before {
content: "hi!";
}

View File

@ -1,9 +0,0 @@
foo {
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=1,startColorstr=#c0ff3300,endColorstr=#ff000000);
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=1,startColorstr=#c0ff3300,endColorstr=#ff000000);
}
foo {
filter: alpha(opacity=20);
filter: alpha(opacity=20,enabled=true);
filter: blaznicate(foo=bar,baz=bang bip,bart=#fa4600);
}

View File

@ -1,61 +0,0 @@
@import "not-found";
@import "something.css" media;
@import url("something.css") media;
@import url(something.css) media, screen, print;
b {
color: maroon;
padding: 16px;
}
body {
line-height: 10em;
}
body div.bright {
color: red;
}
body div.sad {
color: blue;
}
div b {
color: fuchsia;
padding: 16px;
}
.one {
color: blue;
}
.one h2 {
background: url("../images/logo.png") no-repeat;
}
.two h2 {
background: url("../images/logo.png") no-repeat;
}
#merge-import-mixins .just-a-class {
background: red;
}
#merge-import-mixins .just-a-class {
background: blue;
}
#merge-import-mixins .hello {
height: 200px;
}
@media cool {
#merge-import-mixins {
color: red;
height: 200px;
}
}
#merge-import-mixins div {
background: red;
background: blue;
}
.inner {
content: "inner/file1.less";
}
.inner {
content: "inner/file2.less";
}
pre {
color: hello-from-file-3;
}
h2 {
background: url("../images/logo.png") no-repeat;
}

View File

@ -1,17 +0,0 @@
div {
color: yes;
color: yes;
color: okay;
}
10"yeah" {
color: blue;
}
10 {
color: blue;
}
hello world 10 {
color: red;
}
#"yeah" {
color: "hello 10";
}

View File

@ -1,48 +0,0 @@
@keyframes 'bounce' {
from {
top: 100px;
animation-timing-function: ease-out;
}
25% {
top: 50px;
animation-timing-function: ease-in;
}
50% {
top: 100px;
animation-timing-function: ease-out;
}
75% {
top: 75px;
animation-timing-function: ease-in;
}
to {
top: 100px;
}
}
@-webkit-keyframes flowouttoleft {
0% {
-webkit-transform: translateX(0) scale(1);
}
60%,
70% {
-webkit-transform: translateX(0) scale(.7);
}
100% {
-webkit-transform: translateX(-100%) scale(.7);
}
}
div {
animation-name: 'diagonal-slide';
animation-duration: 5s;
animation-iteration-count: 10;
}
@keyframes 'diagonal-slide' {
from {
left: 0;
top: 0;
}
to {
left: 100px;
top: 100px;
}
}

View File

@ -1,69 +0,0 @@
.unary {
sub: 10 -5;
}
.spaces {
sub: 5;
sub: 5;
add: 15;
add: 15;
div: 2;
mul: 50;
mul: 50;
}
.supress-division {
border-radius: 10px/10px;
border-radius: 10px/10px;
border-radius: hello(10px/10px) world;
font: 10px/30 sans-serif;
font: 10px/20px sans-serif;
font: 10px/20px sans-serif;
border-radius: 0 15px 15px 15px/0 50% 50% 50%;
}
.parens {
sub: 5;
add: 15;
div: 2;
div: 2;
mul: 50;
}
.keyword-names {
height: "hello" 25;
}
.negation {
hello: -1px;
hello: -1px;
hello: -10;
}
.test {
single: 5;
single: 10;
single: 10;
parens: 10 -2;
math: 20;
math: 20;
width: 71;
height: 6;
padding: 6px 1em 2px 2;
padding: 8 4 4 4px;
width: 96;
height: 113;
margin: 12;
}
.percents {
color: 1000%;
color: 1000%;
color: 100%;
color: 1000px;
color: 1000%;
color: 30%;
color: 10%;
color: 2%;
}
.misc {
x: 40px;
y: 40em;
}
.cond {
y: false;
y: true;
}

View File

@ -1,70 +0,0 @@
@media screen,3D {
P {
color: green;
}
}
@media print {
body {
font-size: 10pt;
}
}
@media screen {
body {
font-size: 13px;
}
}
@media screen,print {
body {
line-height: 1.2;
}
}
@media all and (min-width: 0px) {
body {
line-height: 1.2;
}
}
@media all and (min-width: 0) {
body {
line-height: 1.2;
}
}
@media screen and (min-width: 102.5em) and (max-width: 117.9375em),screen and (min-width: 150em) {
body {
color: blue;
}
}
@media screen and (min-height: 110px) {
body {
color: red;
}
}
@media screen and (height: 100px) and (width: 110px),(size: 120px) {
body {
color: red;
}
}
@media test {
div {
height: 20px;
}
}
@media test and (hello) {
div {
color: red;
}
div pre {
color: orange;
}
}
@media yeah {
@page {
@media cool {
color: red;
}
}
}
@media (max-width: 599px) {
.helloworld {
color: blue;
}
}

View File

@ -1,63 +0,0 @@
color: "aaa, bbb";
.topbar {
background: url(/assets/images/test/topbar.png);
}
.hello {
test: empty-function("/assets/images/test/",40%,to(#fff));
}
.css3 {
background-image: -webkit-gradient(linear,0% 0%,0% 90%,from(#E9A000),to(#A37000));
}
.test,
.world {
border: 1px solid red;
color: url(http://mage-page.com);
string: "hello /* this is not a comment */";
world: "// neither is this";
string: 'hello /* this is not a comment */';
world: '// neither is this';
what-ever: 100px;
background: url(/*no comment here*/);
}
.urls {
background: url("http://google.com");
background: url(http://google.com);
background: url("http://google.com");
}
.cool {
color: "aaa, bbb";
}
.span-17 {
float: left;
}
.span-17 {
width: 660px;
}
.x {
float: left;
width: 660px;
}
.hi pre {
color: red;
}
.hi pre {
color: blue;
}
.rad pre {
color: red;
}
.rad pre {
color: blue;
}
hello {
numbers: 1.0 0.1 .1 1.;
numbers: 1.0s 0.1s .1s 1.s;
numbers: -1s -0.1s -0.1s -1s;
numbers: -1 -0.1 -0.1 -1;
}
#string {
hello: 'what\'s going on here';
hello: 'blah blag @{ blah blah';
join: "3434hello";
join: 3434hello;
}

View File

@ -1,14 +0,0 @@
body {
padding: 2.0em;
color: red;
margin: 10px;
height: 12px;
border-bottom: 1px solid green;
}
.skip_args {
margin: 22px;
height: 12px;
padding: 10px 20px 30px 88px;
margin: 4px 12px 2px 1px;
color: red;
}

View File

@ -1,42 +0,0 @@
#test1 div {
color:red;
height:10px;
}
#test1 p { height:10px; }
#test2 b {
color:red;
width:1px;
}
#test2 a, #test2 i { width:1px; }
#test3 a, #test3 i { width:1px; }
#test3 b {
width:1px;
color:red;
}
#test4 a {
color:blue;
margin:1px;
}
#test4 div, #test4 html { color:blue; }
#test5 img, #test5 strong {
padding:2px;
float:right;
}
#test6 div a, #test6 span a {
line-height:10px;
color:red;
}
#test7 div strong {
margin:1px;
color:red;
}
#test7 div b { color:red; }
#test7 span strong, #test7 span b { color:red; }
#test8 a i, #test8 b i {
background:red;
color:red;
}
#test8 a s, #test8 b s {
background:red;
color:blue;
}

View File

@ -1,83 +0,0 @@
.bold {
font-size: 20px;
font-weight: bold;
}
body #window {
border-radius: 10px;
font-size: 20px;
font-weight: bold;
line-height: 30px;
}
#bundle .button {
display: block;
border: 1px solid black;
background-color: grey;
}
#bundle .button:hover {
background-color: white;
}
#header a {
color: orange;
display: block;
border: 1px solid black;
background-color: grey;
}
#header a:hover {
background-color: white;
}
div {
color: blue;
hello: world;
}
div b {
color: blue;
}
body {
color: blue;
hello: world;
}
body b {
color: blue;
}
.hello .world {
color: blue;
}
.foobar {
color: blue;
}
.eggs {
foo: 1px 2px;
bar: 1px 2px;
foo: 100 land;
bar: 100 land;
}
#hello {
cool: one two three cool;
}
#hello-important {
cool: one two three cool !important;
}
#world {
cool: "world";
}
#another {
things: red blue green;
things: red blue green skip me;
}
#day .cool {
color: one two three;
}
#day .cool {
color: one two three skip me;
}
.mix-suffix {
color: red !important;
height: 20px !important;
}
.mix-suffix pre {
color: red;
}
.search-test {
color: #f00 !important;
color: #0f0 !important;
}

View File

@ -1,51 +0,0 @@
#header {
color: black;
}
#header .navigation {
font-size: 12px;
}
#header .navigation .border .outside {
color: blue;
}
#header .logo {
width: 300px;
}
#header .logo:hover {
text-decoration: none;
}
a b ul li {
color: green;
}
div .cool {
color: green;
}
p .cool span {
color: yellow;
}
div another {
color: green;
}
p another span {
color: yellow;
}
b .something {
color: blue;
}
b.something {
color: blue;
}
.foo .bar .qux,
.foo .baz .qux {
display: block;
}
.qux .foo .bar,
.qux .foo .baz {
display: inline;
}
.qux .foo .bar .biz,
.qux .foo .baz .biz {
display: none;
}
b hello [x="&yeah"] {
color: red;
}

View File

@ -1,6 +0,0 @@
#header .navigation .border .outside { color:blue; }
#header .navigation { font-size:12px; }
#header .logo:hover { text-decoration:none; }
#header .logo { width:300px; }
#header { color:black; }
a b ul li { color:green; }

View File

@ -1,72 +0,0 @@
.class {
color: #a2a2a2;
display: block;
}
.zero {
zero: 0;
one: 1;
two: 2;
three: 3;
}
.one {
one: 1;
one-req: 1;
two: 2;
three: 3;
}
.two {
two: 2;
three: 3;
}
.three {
three-req: 3;
three: 3;
}
.left {
left: 1;
}
.right {
right: 1;
}
.border-right {
color: black;
border-right: 4px;
}
.border-left {
color: black;
border-left: 4px;
}
.only-right {
right: 33;
}
.only-left {
left: 33;
}
.left-right {
both: 330;
}
#hola {
color: blue;
}
#defaults_1 {
height: one;
height: two;
height: three;
height: four;
}
.thing {
color: red;
}
#aa {
color: green;
color: blue;
color: red;
}
#bb {
color: green;
color: blue;
color: red;
}
#cc {
color: blue;
}

View File

@ -1,11 +0,0 @@
body div other world {
height: 50;
}
div other world {
height: 50;
}
pre {
height: 10;
height: 11;
height: 12;
}

View File

@ -1,25 +0,0 @@
something blue,
world {
color: blue;
}
.div 3434 {
height: 100px;
}
.div cool red {
height: 4000px;
}
.span5 {
color: 15;
}
.span4 {
color: 14;
}
.span3 {
color: 13;
}
.span2 {
color: 12;
}
.span1 {
color: 11;
}

View File

@ -1,76 +0,0 @@
default .underline {
border-bottom: 1px solid green;
}
default #header {
color: black;
border: 1px solid #dd44dd;
}
default #header .navigation {
font-size: 12px;
}
default #header .navigation a {
border-bottom: 1px solid green;
}
default #header .logo {
width: 300px;
}
default #header .logo:hover {
text-decoration: none;
}
variables .variables {
width: 14cm;
height: 24px;
color: #888;
background: #6c94be;
font-family: "Trebuchet MS", Verdana, sans-serif;
}
mixins .bordered {
border-top: dotted 1px black;
border-bottom: solid 2px black;
}
mixins #menu a {
color: #111;
border-top: dotted 1px black;
border-bottom: solid 2px black;
}
mixins .post a {
color: red;
border-top: dotted 1px black;
border-bottom: solid 2px black;
}
nested-rules #header {
color: black;
}
nested-rules #header .navigation {
font-size: 12px;
}
nested-rules #header .logo {
width: 300px;
}
nested-rules #header .logo:hover {
text-decoration: none;
}
namespaces #bundle .button {
display: block;
border: 1px solid black;
background-color: grey;
}
namespaces #bundle .button:hover {
background-color: white;
}
namespaces #header a {
color: orange;
display: block;
border: 1px solid black;
background-color: grey;
}
namespaces #header a:hover {
background-color: white;
}
mixin-functions body {
padding: 2.0em;
color: red;
margin: 10px;
height: 12px;
border-bottom: 1px solid green;
}

View File

@ -1,20 +0,0 @@
color: 44px;
color: 44px;
.variables {
width: 14cm;
height: 24px;
margin-top: -20px;
margin-bottom: 30px;
color: #888899;
background: #6c94be;
font-family: "Trebuchet MS", Verdana, sans-serif;
margin: 3px;
font: 10px/12px serif;
font: 120%/120% serif;
}
.external {
color: #888;
border: 1px solid #3326cc;
background: rgba(23,68,149,0.5);
padding: 4px;
}

View File

@ -1,57 +0,0 @@
<?php
error_reporting(E_ALL);
require realpath(dirname(__FILE__)).'/../lessc.inc.php';
// sorts the selectors in stylesheet in order to normalize it for comparison
$exe = array_shift($argv); // remove filename
if (!$fname = array_shift($argv)) {
$fname = "php://stdin";
}
class lesscNormalized extends lessc {
public $numberPrecision = 3;
public function compileValue($value) {
if ($value[0] == "raw_color") {
$value = $this->coerceColor($value);
}
return parent::compileValue($value);
}
}
class SortingFormatter extends lessc_formatter_lessjs {
function sortKey($block) {
if (!isset($block->sortKey)) {
sort($block->selectors, SORT_STRING);
$block->sortKey = implode(",", $block->selectors);
}
return $block->sortKey;
}
function sortBlock($block) {
usort($block->children, function($a, $b) {
$sort = strcmp($this->sortKey($a), $this->sortKey($b));
if ($sort == 0) {
// TODO
}
return $sort;
});
}
function block($block) {
$this->sortBlock($block);
return parent::block($block);
}
}
$less = new lesscNormalized();
$less->setFormatter(new SortingFormatter);
echo $less->parse(file_get_contents($fname));