MDL-55285 core: Include library scssphp in core

Part of MDL-55071
This commit is contained in:
Frederic Massart 2016-07-20 16:45:59 +08:00 committed by Dan Poltawski
parent 88af020839
commit 321c986c86
26 changed files with 9922 additions and 0 deletions

View File

@ -0,0 +1,47 @@
<?php
/**
* SCSSPHP
*
* @copyright 2015 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Base;
/**
* Range
*
* @author Anthon Pang <anthon.pang@gmail.com>
*/
class Range
{
public $first;
public $last;
/**
* Initialize range
*
* @param integer|float $first
* @param integer|float $last
*/
public function __construct($first, $last)
{
$this->first = $first;
$this->last = $last;
}
/**
* Test for inclusion in range
*
* @param integer|float $value
*
* @return boolean
*/
public function includes($value)
{
return $value >= $this->first && $value <= $this->last;
}
}

60
lib/scssphp/Block.php Normal file
View File

@ -0,0 +1,60 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2015 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp;
/**
* Block
*
* @author Anthon Pang <anthon.pang@gmail.com>
*/
class Block
{
/**
* @var string
*/
public $type;
/**
* @var \Leafo\ScssPhp\Block
*/
public $parent;
/**
* @var integer
*/
public $sourceIndex;
/**
* @var integer
*/
public $sourceLine;
/**
* @var integer
*/
public $sourceColumn;
/**
* @var array
*/
public $selectors;
/**
* @var array
*/
public $comments;
/**
* @var array
*/
public $children;
}

179
lib/scssphp/Colors.php Normal file
View File

@ -0,0 +1,179 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2015 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp;
/**
* CSS Colors
*
* @author Leaf Corcoran <leafot@gmail.com>
*/
class Colors
{
/**
* CSS Colors
*
* @see http://www.w3.org/TR/css3-color
*
* @var array
*/
public static $cssColors = [
'aliceblue' => '240,248,255',
'antiquewhite' => '250,235,215',
'aqua' => '0,255,255',
'aquamarine' => '127,255,212',
'azure' => '240,255,255',
'beige' => '245,245,220',
'bisque' => '255,228,196',
'black' => '0,0,0',
'blanchedalmond' => '255,235,205',
'blue' => '0,0,255',
'blueviolet' => '138,43,226',
'brown' => '165,42,42',
'burlywood' => '222,184,135',
'cadetblue' => '95,158,160',
'chartreuse' => '127,255,0',
'chocolate' => '210,105,30',
'coral' => '255,127,80',
'cornflowerblue' => '100,149,237',
'cornsilk' => '255,248,220',
'crimson' => '220,20,60',
'cyan' => '0,255,255',
'darkblue' => '0,0,139',
'darkcyan' => '0,139,139',
'darkgoldenrod' => '184,134,11',
'darkgray' => '169,169,169',
'darkgreen' => '0,100,0',
'darkgrey' => '169,169,169',
'darkkhaki' => '189,183,107',
'darkmagenta' => '139,0,139',
'darkolivegreen' => '85,107,47',
'darkorange' => '255,140,0',
'darkorchid' => '153,50,204',
'darkred' => '139,0,0',
'darksalmon' => '233,150,122',
'darkseagreen' => '143,188,143',
'darkslateblue' => '72,61,139',
'darkslategray' => '47,79,79',
'darkslategrey' => '47,79,79',
'darkturquoise' => '0,206,209',
'darkviolet' => '148,0,211',
'deeppink' => '255,20,147',
'deepskyblue' => '0,191,255',
'dimgray' => '105,105,105',
'dimgrey' => '105,105,105',
'dodgerblue' => '30,144,255',
'firebrick' => '178,34,34',
'floralwhite' => '255,250,240',
'forestgreen' => '34,139,34',
'fuchsia' => '255,0,255',
'gainsboro' => '220,220,220',
'ghostwhite' => '248,248,255',
'gold' => '255,215,0',
'goldenrod' => '218,165,32',
'gray' => '128,128,128',
'green' => '0,128,0',
'greenyellow' => '173,255,47',
'grey' => '128,128,128',
'honeydew' => '240,255,240',
'hotpink' => '255,105,180',
'indianred' => '205,92,92',
'indigo' => '75,0,130',
'ivory' => '255,255,240',
'khaki' => '240,230,140',
'lavender' => '230,230,250',
'lavenderblush' => '255,240,245',
'lawngreen' => '124,252,0',
'lemonchiffon' => '255,250,205',
'lightblue' => '173,216,230',
'lightcoral' => '240,128,128',
'lightcyan' => '224,255,255',
'lightgoldenrodyellow' => '250,250,210',
'lightgray' => '211,211,211',
'lightgreen' => '144,238,144',
'lightgrey' => '211,211,211',
'lightpink' => '255,182,193',
'lightsalmon' => '255,160,122',
'lightseagreen' => '32,178,170',
'lightskyblue' => '135,206,250',
'lightslategray' => '119,136,153',
'lightslategrey' => '119,136,153',
'lightsteelblue' => '176,196,222',
'lightyellow' => '255,255,224',
'lime' => '0,255,0',
'limegreen' => '50,205,50',
'linen' => '250,240,230',
'magenta' => '255,0,255',
'maroon' => '128,0,0',
'mediumaquamarine' => '102,205,170',
'mediumblue' => '0,0,205',
'mediumorchid' => '186,85,211',
'mediumpurple' => '147,112,219',
'mediumseagreen' => '60,179,113',
'mediumslateblue' => '123,104,238',
'mediumspringgreen' => '0,250,154',
'mediumturquoise' => '72,209,204',
'mediumvioletred' => '199,21,133',
'midnightblue' => '25,25,112',
'mintcream' => '245,255,250',
'mistyrose' => '255,228,225',
'moccasin' => '255,228,181',
'navajowhite' => '255,222,173',
'navy' => '0,0,128',
'oldlace' => '253,245,230',
'olive' => '128,128,0',
'olivedrab' => '107,142,35',
'orange' => '255,165,0',
'orangered' => '255,69,0',
'orchid' => '218,112,214',
'palegoldenrod' => '238,232,170',
'palegreen' => '152,251,152',
'paleturquoise' => '175,238,238',
'palevioletred' => '219,112,147',
'papayawhip' => '255,239,213',
'peachpuff' => '255,218,185',
'peru' => '205,133,63',
'pink' => '255,192,203',
'plum' => '221,160,221',
'powderblue' => '176,224,230',
'purple' => '128,0,128',
'rebeccapurple' => '102,51,153',
'red' => '255,0,0',
'rosybrown' => '188,143,143',
'royalblue' => '65,105,225',
'saddlebrown' => '139,69,19',
'salmon' => '250,128,114',
'sandybrown' => '244,164,96',
'seagreen' => '46,139,87',
'seashell' => '255,245,238',
'sienna' => '160,82,45',
'silver' => '192,192,192',
'skyblue' => '135,206,235',
'slateblue' => '106,90,205',
'slategray' => '112,128,144',
'slategrey' => '112,128,144',
'snow' => '255,250,250',
'springgreen' => '0,255,127',
'steelblue' => '70,130,180',
'tan' => '210,180,140',
'teal' => '0,128,128',
'thistle' => '216,191,216',
'tomato' => '255,99,71',
'transparent' => '0,0,0,0',
'turquoise' => '64,224,208',
'violet' => '238,130,238',
'wheat' => '245,222,179',
'white' => '255,255,255',
'whitesmoke' => '245,245,245',
'yellow' => '255,255,0',
'yellowgreen' => '154,205,50',
];
}

5209
lib/scssphp/Compiler.php Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,40 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2015 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Compiler;
/**
* Compiler environment
*
* @author Anthon Pang <anthon.pang@gmail.com>
*/
class Environment
{
/**
* @var \Leafo\ScssPhp\Block
*/
public $block;
/**
* @var \Leafo\ScssPhp\Compiler\Environment
*/
public $parent;
/**
* @var array
*/
public $store;
/**
* @var integer
*/
public $depth;
}

View File

@ -0,0 +1,21 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2015 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Exception;
/**
* Compiler exception
*
* @author Oleksandr Savchenko <traveltino@gmail.com>
*/
class CompilerException extends \Exception
{
}

View File

@ -0,0 +1,21 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2015 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Exception;
/**
* Parser Exception
*
* @author Oleksandr Savchenko <traveltino@gmail.com>
*/
class ParserException extends \Exception
{
}

View File

@ -0,0 +1,21 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2015 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Exception;
/**
* Server Exception
*
* @author Anthon Pang <anthon.pang@gmail.com>
*/
class ServerException extends \Exception
{
}

216
lib/scssphp/Formatter.php Normal file
View File

@ -0,0 +1,216 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2015 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp;
use Leafo\ScssPhp\Formatter\OutputBlock;
/**
* Base formatter
*
* @author Leaf Corcoran <leafot@gmail.com>
*/
abstract class Formatter
{
/**
* @var integer
*/
public $indentLevel;
/**
* @var string
*/
public $indentChar;
/**
* @var string
*/
public $break;
/**
* @var string
*/
public $open;
/**
* @var string
*/
public $close;
/**
* @var string
*/
public $tagSeparator;
/**
* @var string
*/
public $assignSeparator;
/**
* @var boolea
*/
public $keepSemicolons;
/**
* Initialize formatter
*
* @api
*/
abstract public function __construct();
/**
* Return indentation (whitespace)
*
* @return string
*/
protected function indentStr()
{
return '';
}
/**
* Return property assignment
*
* @api
*
* @param string $name
* @param mixed $value
*
* @return string
*/
public function property($name, $value)
{
return rtrim($name) . $this->assignSeparator . $value . ';';
}
/**
* Strip semi-colon appended by property(); it's a separator, not a terminator
*
* @api
*
* @param array $lines
*/
public function stripSemicolon(&$lines)
{
if ($this->keepSemicolons) {
return;
}
if (($count = count($lines))
&& substr($lines[$count - 1], -1) === ';'
) {
$lines[$count - 1] = substr($lines[$count - 1], 0, -1);
}
}
/**
* Output lines inside a block
*
* @param \Leafo\ScssPhp\Formatter\OutputBlock $block
*/
protected function blockLines(OutputBlock $block)
{
$inner = $this->indentStr();
$glue = $this->break . $inner;
echo $inner . implode($glue, $block->lines);
if (! empty($block->children)) {
echo $this->break;
}
}
/**
* Output block selectors
*
* @param \Leafo\ScssPhp\Formatter\OutputBlock $block
*/
protected function blockSelectors(OutputBlock $block)
{
$inner = $this->indentStr();
echo $inner
. implode($this->tagSeparator, $block->selectors)
. $this->open . $this->break;
}
/**
* Output block children
*
* @param \Leafo\ScssPhp\Formatter\OutputBlock $block
*/
protected function blockChildren(OutputBlock $block)
{
foreach ($block->children as $child) {
$this->block($child);
}
}
/**
* Output non-empty block
*
* @param \Leafo\ScssPhp\Formatter\OutputBlock $block
*/
protected function block(OutputBlock $block)
{
if (empty($block->lines) && empty($block->children)) {
return;
}
$pre = $this->indentStr();
if (! empty($block->selectors)) {
$this->blockSelectors($block);
$this->indentLevel++;
}
if (! empty($block->lines)) {
$this->blockLines($block);
}
if (! empty($block->children)) {
$this->blockChildren($block);
}
if (! empty($block->selectors)) {
$this->indentLevel--;
if (empty($block->children)) {
echo $this->break;
}
echo $pre . $this->close . $this->break;
}
}
/**
* Entry point to formatting a block
*
* @api
*
* @param \Leafo\ScssPhp\Formatter\OutputBlock $block An abstract syntax tree
*
* @return string
*/
public function format(OutputBlock $block)
{
ob_start();
$this->block($block);
$out = ob_get_clean();
return $out;
}
}

View File

@ -0,0 +1,45 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2015 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Formatter;
use Leafo\ScssPhp\Formatter;
/**
* Compact formatter
*
* @author Leaf Corcoran <leafot@gmail.com>
*/
class Compact extends Formatter
{
/**
* {@inheritdoc}
*/
public function __construct()
{
$this->indentLevel = 0;
$this->indentChar = '';
$this->break = '';
$this->open = ' {';
$this->close = "}\n\n";
$this->tagSeparator = ',';
$this->assignSeparator = ':';
$this->keepSemicolons = true;
}
/**
* {@inheritdoc}
*/
public function indentStr()
{
return ' ';
}
}

View File

@ -0,0 +1,62 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2015 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Formatter;
use Leafo\ScssPhp\Formatter;
use Leafo\ScssPhp\Formatter\OutputBlock;
/**
* Compressed formatter
*
* @author Leaf Corcoran <leafot@gmail.com>
*/
class Compressed extends Formatter
{
/**
* {@inheritdoc}
*/
public function __construct()
{
$this->indentLevel = 0;
$this->indentChar = ' ';
$this->break = '';
$this->open = '{';
$this->close = '}';
$this->tagSeparator = ',';
$this->assignSeparator = ':';
$this->keepSemicolons = false;
}
/**
* {@inheritdoc}
*/
public function blockLines(OutputBlock $block)
{
$inner = $this->indentStr();
$glue = $this->break . $inner;
foreach ($block->lines as $index => $line) {
if (substr($line, 0, 2) === '/*' && substr($line, 2, 1) !== '!') {
unset($block->lines[$index]);
} elseif (substr($line, 0, 3) === '/*!') {
$block->lines[$index] = '/*' . substr($line, 3);
}
}
echo $inner . implode($glue, $block->lines);
if (! empty($block->children)) {
echo $this->break;
}
}
}

View File

@ -0,0 +1,60 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2015 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Formatter;
use Leafo\ScssPhp\Formatter;
use Leafo\ScssPhp\Formatter\OutputBlock;
/**
* Crunched formatter
*
* @author Anthon Pang <anthon.pang@gmail.com>
*/
class Crunched extends Formatter
{
/**
* {@inheritdoc}
*/
public function __construct()
{
$this->indentLevel = 0;
$this->indentChar = ' ';
$this->break = '';
$this->open = '{';
$this->close = '}';
$this->tagSeparator = ',';
$this->assignSeparator = ':';
$this->keepSemicolons = false;
}
/**
* {@inheritdoc}
*/
public function blockLines(OutputBlock $block)
{
$inner = $this->indentStr();
$glue = $this->break . $inner;
foreach ($block->lines as $index => $line) {
if (substr($line, 0, 2) === '/*') {
unset($block->lines[$index]);
}
}
echo $inner . implode($glue, $block->lines);
if (! empty($block->children)) {
echo $this->break;
}
}
}

View File

@ -0,0 +1,119 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2015 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Formatter;
use Leafo\ScssPhp\Formatter;
use Leafo\ScssPhp\Formatter\OutputBlock;
/**
* Debug formatter
*
* @author Anthon Pang <anthon.pang@gmail.com>
*/
class Debug extends Formatter
{
/**
* {@inheritdoc}
*/
public function __construct()
{
$this->indentLevel = 0;
$this->indentChar = '';
$this->break = "\n";
$this->open = ' {';
$this->close = ' }';
$this->tagSeparator = ', ';
$this->assignSeparator = ': ';
$this->keepSemicolons = true;
}
/**
* {@inheritdoc}
*/
protected function indentStr()
{
return str_repeat(' ', $this->indentLevel);
}
/**
* {@inheritdoc}
*/
protected function blockLines(OutputBlock $block)
{
$indent = $this->indentStr();
if (empty($block->lines)) {
echo "{$indent}block->lines: []\n";
return;
}
foreach ($block->lines as $index => $line) {
echo "{$indent}block->lines[{$index}]: $line\n";
}
}
/**
* {@inheritdoc}
*/
protected function blockSelectors(OutputBlock $block)
{
$indent = $this->indentStr();
if (empty($block->selectors)) {
echo "{$indent}block->selectors: []\n";
return;
}
foreach ($block->selectors as $index => $selector) {
echo "{$indent}block->selectors[{$index}]: $selector\n";
}
}
/**
* {@inheritdoc}
*/
protected function blockChildren(OutputBlock $block)
{
$indent = $this->indentStr();
if (empty($block->children)) {
echo "{$indent}block->children: []\n";
return;
}
$this->indentLevel++;
foreach ($block->children as $i => $child) {
$this->block($child);
}
$this->indentLevel--;
}
/**
* {@inheritdoc}
*/
protected function block(OutputBlock $block)
{
$indent = $this->indentStr();
echo "{$indent}block->type: {$block->type}\n" .
"{$indent}block->depth: {$block->depth}\n";
$this->blockSelectors($block);
$this->blockLines($block);
$this->blockChildren($block);
}
}

View File

@ -0,0 +1,68 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2015 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Formatter;
use Leafo\ScssPhp\Formatter;
use Leafo\ScssPhp\Formatter\OutputBlock;
/**
* Expanded formatter
*
* @author Leaf Corcoran <leafot@gmail.com>
*/
class Expanded extends Formatter
{
/**
* {@inheritdoc}
*/
public function __construct()
{
$this->indentLevel = 0;
$this->indentChar = ' ';
$this->break = "\n";
$this->open = ' {';
$this->close = '}';
$this->tagSeparator = ', ';
$this->assignSeparator = ': ';
$this->keepSemicolons = true;
}
/**
* {@inheritdoc}
*/
protected function indentStr()
{
return str_repeat($this->indentChar, $this->indentLevel);
}
/**
* {@inheritdoc}
*/
protected function blockLines(OutputBlock $block)
{
$inner = $this->indentStr();
$glue = $this->break . $inner;
foreach ($block->lines as $index => $line) {
if (substr($line, 0, 2) === '/*') {
$block->lines[$index] = preg_replace('/(\r|\n)+/', $glue, $line);
}
}
echo $inner . implode($glue, $block->lines);
if (empty($block->selectors) || ! empty($block->children)) {
echo $this->break;
}
}
}

View File

@ -0,0 +1,198 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2015 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Formatter;
use Leafo\ScssPhp\Formatter;
use Leafo\ScssPhp\Formatter\OutputBlock;
/**
* Nested formatter
*
* @author Leaf Corcoran <leafot@gmail.com>
*/
class Nested extends Formatter
{
/**
* @var integer
*/
private $depth;
/**
* {@inheritdoc}
*/
public function __construct()
{
$this->indentLevel = 0;
$this->indentChar = ' ';
$this->break = "\n";
$this->open = ' {';
$this->close = ' }';
$this->tagSeparator = ', ';
$this->assignSeparator = ': ';
$this->keepSemicolons = true;
}
/**
* {@inheritdoc}
*/
protected function indentStr()
{
$n = $this->depth - 1;
return str_repeat($this->indentChar, max($this->indentLevel + $n, 0));
}
/**
* {@inheritdoc}
*/
protected function blockLines(OutputBlock $block)
{
$inner = $this->indentStr();
$glue = $this->break . $inner;
foreach ($block->lines as $index => $line) {
if (substr($line, 0, 2) === '/*') {
$block->lines[$index] = preg_replace('/(\r|\n)+/', $glue, $line);
}
}
echo $inner . implode($glue, $block->lines);
if (! empty($block->children)) {
echo $this->break;
}
}
/**
* {@inheritdoc}
*/
protected function blockSelectors(OutputBlock $block)
{
$inner = $this->indentStr();
echo $inner
. implode($this->tagSeparator, $block->selectors)
. $this->open . $this->break;
}
/**
* {@inheritdoc}
*/
protected function blockChildren(OutputBlock $block)
{
foreach ($block->children as $i => $child) {
$this->block($child);
if ($i < count($block->children) - 1) {
echo $this->break;
if (isset($block->children[$i + 1])) {
$next = $block->children[$i + 1];
if ($next->depth === max($block->depth, 1) && $child->depth >= $next->depth) {
echo $this->break;
}
}
}
}
}
/**
* {@inheritdoc}
*/
protected function block(OutputBlock $block)
{
if ($block->type === 'root') {
$this->adjustAllChildren($block);
}
if (empty($block->lines) && empty($block->children)) {
return;
}
$this->depth = $block->depth;
if (! empty($block->selectors)) {
$this->blockSelectors($block);
$this->indentLevel++;
}
if (! empty($block->lines)) {
$this->blockLines($block);
}
if (! empty($block->children)) {
$this->blockChildren($block);
}
if (! empty($block->selectors)) {
$this->indentLevel--;
echo $this->close;
}
if ($block->type === 'root') {
echo $this->break;
}
}
/**
* Adjust the depths of all children, depth first
*
* @param \Leafo\ScssPhp\Formatter\OutputBlock $block
*/
private function adjustAllChildren(OutputBlock $block)
{
// flatten empty nested blocks
$children = [];
foreach ($block->children as $i => $child) {
if (empty($child->lines) && empty($child->children)) {
if (isset($block->children[$i + 1])) {
$block->children[$i + 1]->depth = $child->depth;
}
continue;
}
$children[] = $child;
}
$count = count($children);
for ($i = 0; $i < $count; $i++) {
$depth = $children[$i]->depth;
$j = $i + 1;
if (isset($children[$j]) && $depth < $children[$j]->depth) {
$childDepth = $children[$j]->depth;
for (; $j < $count; $j++) {
if ($depth < $children[$j]->depth && $childDepth >= $children[$j]->depth) {
$children[$j]->depth = $depth + 1;
}
}
}
}
$block->children = $children;
// make relative to parent
foreach ($block->children as $child) {
$this->adjustAllChildren($child);
$child->depth = $child->depth - $block->depth;
}
}
}

View File

@ -0,0 +1,50 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2015 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Formatter;
/**
* Output block
*
* @author Anthon Pang <anthon.pang@gmail.com>
*/
class OutputBlock
{
/**
* @var string
*/
public $type;
/**
* @var integer
*/
public $depth;
/**
* @var array
*/
public $selectors;
/**
* @var array
*/
public $lines;
/**
* @var array
*/
public $children;
/**
* @var \Leafo\ScssPhp\Formatter\OutputBlock
*/
public $parent;
}

20
lib/scssphp/LICENSE.md Normal file
View File

@ -0,0 +1,20 @@
Copyright (c) 2015 Leaf Corcoran, http://leafo.github.io/scssphp
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

40
lib/scssphp/Node.php Normal file
View File

@ -0,0 +1,40 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2015 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp;
/**
* Base node
*
* @author Anthon Pang <anthon.pang@gmail.com>
*/
abstract class Node
{
/**
* @var string
*/
public $type;
/**
* @var integer
*/
public $sourceIndex;
/**
* @var integer
*/
public $sourceLine;
/**
* @var integer
*/
public $sourceColumn;
}

329
lib/scssphp/Node/Number.php Normal file
View File

@ -0,0 +1,329 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2015 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Node;
use Leafo\ScssPhp\Compiler;
use Leafo\ScssPhp\Node;
use Leafo\ScssPhp\Type;
/**
* Dimension + optional units
*
* {@internal
* This is a work-in-progress.
*
* The \ArrayAccess interface is temporary until the migration is complete.
* }}
*
* @author Anthon Pang <anthon.pang@gmail.com>
*/
class Number extends Node implements \ArrayAccess
{
/**
* @var integer
*/
static public $precision = 5;
/**
* @see http://www.w3.org/TR/2012/WD-css3-values-20120308/
*
* @var array
*/
static protected $unitTable = [
'in' => [
'in' => 1,
'pc' => 6,
'pt' => 72,
'px' => 96,
'cm' => 2.54,
'mm' => 25.4,
'q' => 101.6,
],
'turn' => [
'deg' => 360,
'grad' => 400,
'rad' => 6.28318530717958647692528676, // 2 * M_PI
'turn' => 1,
],
's' => [
's' => 1,
'ms' => 1000,
],
'Hz' => [
'Hz' => 1,
'kHz' => 0.001,
],
'dpi' => [
'dpi' => 1,
'dpcm' => 2.54,
'dppx' => 96,
],
];
/**
* @var integer|float
*/
public $dimension;
/**
* @var array
*/
public $units;
/**
* Initialize number
*
* @param mixed $dimension
* @param mixed $initialUnit
*/
public function __construct($dimension, $initialUnit)
{
$this->type = Type::T_NUMBER;
$this->dimension = $dimension;
$this->units = is_array($initialUnit)
? $initialUnit
: ($initialUnit ? [$initialUnit => 1]
: []);
}
/**
* Coerce number to target units
*
* @param array $units
*
* @return \Leafo\ScssPhp\Node\Number
*/
public function coerce($units)
{
if ($this->unitless()) {
return new Number($this->dimension, $units);
}
$dimension = $this->dimension;
foreach (self::$unitTable['in'] as $unit => $conv) {
$from = isset($this->units[$unit]) ? $this->units[$unit] : 0;
$to = isset($units[$unit]) ? $units[$unit] : 0;
$factor = pow($conv, $from - $to);
$dimension /= $factor;
}
return new Number($dimension, $units);
}
/**
* Normalize number
*
* @return \Leafo\ScssPhp\Node\Number
*/
public function normalize()
{
$dimension = $this->dimension;
$units = [];
$this->normalizeUnits($dimension, $units, 'in');
return new Number($dimension, $units);
}
/**
* {@inheritdoc}
*/
public function offsetExists($offset)
{
if ($offset === -3) {
return $this->sourceColumn !== null;
}
if ($offset === -2) {
return $this->sourceLine !== null;
}
if ($offset === -1
|| $offset === 0
|| $offset === 1
|| $offset === 2
) {
return true;
}
return false;
}
/**
* {@inheritdoc}
*/
public function offsetGet($offset)
{
switch ($offset) {
case -3:
return $this->sourceColumn;
case -2:
return $this->sourceLine;
case -1:
return $this->sourceIndex;
case 0:
return $this->type;
case 1:
return $this->dimension;
case 2:
return $this->units;
}
}
/**
* {@inheritdoc}
*/
public function offsetSet($offset, $value)
{
if ($offset === 1) {
$this->dimension = $value;
} elseif ($offset === 2) {
$this->units = $value;
} elseif ($offset == -1) {
$this->sourceIndex = $value;
} elseif ($offset == -2) {
$this->sourceLine = $value;
} elseif ($offset == -3) {
$this->sourceColumn = $value;
}
}
/**
* {@inheritdoc}
*/
public function offsetUnset($offset)
{
if ($offset === 1) {
$this->dimension = null;
} elseif ($offset === 2) {
$this->units = null;
} elseif ($offset === -1) {
$this->sourceIndex = null;
} elseif ($offset === -2) {
$this->sourceLine = null;
} elseif ($offset === -3) {
$this->sourceColumn = null;
}
}
/**
* Returns true if the number is unitless
*
* @return boolean
*/
public function unitless()
{
return ! array_sum($this->units);
}
/**
* Returns unit(s) as the product of numerator units divided by the product of denominator units
*
* @return string
*/
public function unitStr()
{
$numerators = [];
$denominators = [];
foreach ($this->units as $unit => $unitSize) {
if ($unitSize > 0) {
$numerators = array_pad($numerators, count($numerators) + $unitSize, $unit);
continue;
}
if ($unitSize < 0) {
$denominators = array_pad($denominators, count($denominators) + $unitSize, $unit);
continue;
}
}
return implode('*', $numerators) . (count($denominators) ? '/' . implode('*', $denominators) : '');
}
/**
* Output number
*
* @param \Leafo\ScssPhp\Compiler $compiler
*
* @return string
*/
public function output(Compiler $compiler = null)
{
$dimension = round($this->dimension, self::$precision);
$units = array_filter($this->units, function ($unitSize) {
return $unitSize;
});
if (count($units) > 1 && array_sum($units) === 0) {
$dimension = $this->dimension;
$units = [];
$this->normalizeUnits($dimension, $units, 'in');
$dimension = round($dimension, self::$precision);
$units = array_filter($units, function ($unitSize) {
return $unitSize;
});
}
$unitSize = array_sum($units);
if ($compiler && ($unitSize > 1 || $unitSize < 0 || count($units) > 1)) {
$compiler->throwError((string) $dimension . $this->unitStr() . " isn't a valid CSS value.");
}
reset($units);
list($unit, ) = each($units);
return (string) $dimension . $unit;
}
/**
* {@inheritdoc}
*/
public function __toString()
{
return $this->output();
}
/**
* Normalize units
*
* @param integer|float $dimension
* @param array $units
* @param string $baseUnit
*/
private function normalizeUnits(&$dimension, &$units, $baseUnit = 'in')
{
$dimension = $this->dimension;
$units = [];
foreach ($this->units as $unit => $exp) {
if (isset(self::$unitTable[$baseUnit][$unit])) {
$factor = pow(self::$unitTable[$baseUnit][$unit], $exp);
$unit = $baseUnit;
$dimension /= $factor;
}
$units[$unit] = $exp + (isset($units[$unit]) ? $units[$unit] : 0);
}
}
}

2487
lib/scssphp/Parser.php Normal file

File diff suppressed because it is too large Load Diff

463
lib/scssphp/Server.php Normal file
View File

@ -0,0 +1,463 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2015 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp;
use Leafo\ScssPhp\Compiler;
use Leafo\ScssPhp\Exception\ServerException;
use Leafo\ScssPhp\Version;
/**
* Server
*
* @author Leaf Corcoran <leafot@gmail.com>
*/
class Server
{
/**
* @var boolean
*/
private $showErrorsAsCSS;
/**
* @var string
*/
private $dir;
/**
* @var string
*/
private $cacheDir;
/**
* @var \Leafo\ScssPhp\Compiler
*/
private $scss;
/**
* Join path components
*
* @param string $left Path component, left of the directory separator
* @param string $right Path component, right of the directory separator
*
* @return string
*/
protected function join($left, $right)
{
return rtrim($left, '/\\') . DIRECTORY_SEPARATOR . ltrim($right, '/\\');
}
/**
* Get name of requested .scss file
*
* @return string|null
*/
protected function inputName()
{
switch (true) {
case isset($_GET['p']):
return $_GET['p'];
case isset($_SERVER['PATH_INFO']):
return $_SERVER['PATH_INFO'];
case isset($_SERVER['DOCUMENT_URI']):
return substr($_SERVER['DOCUMENT_URI'], strlen($_SERVER['SCRIPT_NAME']));
}
}
/**
* Get path to requested .scss file
*
* @return string
*/
protected function findInput()
{
if (($input = $this->inputName())
&& strpos($input, '..') === false
&& substr($input, -5) === '.scss'
) {
$name = $this->join($this->dir, $input);
if (is_file($name) && is_readable($name)) {
return $name;
}
}
return false;
}
/**
* Get path to cached .css file
*
* @return string
*/
protected function cacheName($fname)
{
return $this->join($this->cacheDir, md5($fname) . '.css');
}
/**
* Get path to meta data
*
* @return string
*/
protected function metadataName($out)
{
return $out . '.meta';
}
/**
* Determine whether .scss file needs to be re-compiled.
*
* @param string $out Output path
* @param string $etag ETag
*
* @return boolean True if compile required.
*/
protected function needsCompile($out, &$etag)
{
if (! is_file($out)) {
return true;
}
$mtime = filemtime($out);
$metadataName = $this->metadataName($out);
if (is_readable($metadataName)) {
$metadata = unserialize(file_get_contents($metadataName));
foreach ($metadata['imports'] as $import => $originalMtime) {
$currentMtime = filemtime($import);
if ($currentMtime !== $originalMtime || $currentMtime > $mtime) {
return true;
}
}
$metaVars = crc32(serialize($this->scss->getVariables()));
if ($metaVars !== $metadata['vars']) {
return true;
}
$etag = $metadata['etag'];
return false;
}
return true;
}
/**
* Get If-Modified-Since header from client request
*
* @return string|null
*/
protected function getIfModifiedSinceHeader()
{
$modifiedSince = null;
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
$modifiedSince = $_SERVER['HTTP_IF_MODIFIED_SINCE'];
if (false !== ($semicolonPos = strpos($modifiedSince, ';'))) {
$modifiedSince = substr($modifiedSince, 0, $semicolonPos);
}
}
return $modifiedSince;
}
/**
* Get If-None-Match header from client request
*
* @return string|null
*/
protected function getIfNoneMatchHeader()
{
$noneMatch = null;
if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
$noneMatch = $_SERVER['HTTP_IF_NONE_MATCH'];
}
return $noneMatch;
}
/**
* Compile .scss file
*
* @param string $in Input path (.scss)
* @param string $out Output path (.css)
*
* @return array
*/
protected function compile($in, $out)
{
$start = microtime(true);
$css = $this->scss->compile(file_get_contents($in), $in);
$elapsed = round((microtime(true) - $start), 4);
$v = Version::VERSION;
$t = date('r');
$css = "/* compiled by scssphp $v on $t (${elapsed}s) */\n\n" . $css;
$etag = md5($css);
file_put_contents($out, $css);
file_put_contents(
$this->metadataName($out),
serialize([
'etag' => $etag,
'imports' => $this->scss->getParsedFiles(),
'vars' => crc32(serialize($this->scss->getVariables())),
])
);
return [$css, $etag];
}
/**
* Format error as a pseudo-element in CSS
*
* @param \Exception $error
*
* @return string
*/
protected function createErrorCSS(\Exception $error)
{
$message = str_replace(
["'", "\n"],
["\\'", "\\A"],
$error->getfile() . ":\n\n" . $error->getMessage()
);
return "body { display: none !important; }
html:after {
background: white;
color: black;
content: '$message';
display: block !important;
font-family: mono;
padding: 1em;
white-space: pre;
}";
}
/**
* Render errors as a pseudo-element within valid CSS, displaying the errors on any
* page that includes this CSS.
*
* @param boolean $show
*/
public function showErrorsAsCSS($show = true)
{
$this->showErrorsAsCSS = $show;
}
/**
* Compile .scss file
*
* @param string $in Input file (.scss)
* @param string $out Output file (.css) optional
*
* @return string|bool
*
* @throws \Leafo\ScssPhp\Exception\ServerException
*/
public function compileFile($in, $out = null)
{
if (! is_readable($in)) {
throw new ServerException('load error: failed to find ' . $in);
}
$pi = pathinfo($in);
$this->scss->addImportPath($pi['dirname'] . '/');
$compiled = $this->scss->compile(file_get_contents($in), $in);
if ($out !== null) {
return file_put_contents($out, $compiled);
}
return $compiled;
}
/**
* Check if file need compiling
*
* @param string $in Input file (.scss)
* @param string $out Output file (.css)
*
* @return bool
*/
public function checkedCompile($in, $out)
{
if (! is_file($out) || filemtime($in) > filemtime($out)) {
$this->compileFile($in, $out);
return true;
}
return false;
}
/**
* Compile requested scss and serve css. Outputs HTTP response.
*
* @param string $salt Prefix a string to the filename for creating the cache name hash
*/
public function serve($salt = '')
{
$protocol = isset($_SERVER['SERVER_PROTOCOL'])
? $_SERVER['SERVER_PROTOCOL']
: 'HTTP/1.0';
if ($input = $this->findInput()) {
$output = $this->cacheName($salt . $input);
$etag = $noneMatch = trim($this->getIfNoneMatchHeader(), '"');
if ($this->needsCompile($output, $etag)) {
try {
list($css, $etag) = $this->compile($input, $output);
$lastModified = gmdate('D, d M Y H:i:s', filemtime($output)) . ' GMT';
header('Last-Modified: ' . $lastModified);
header('Content-type: text/css');
header('ETag: "' . $etag . '"');
echo $css;
} catch (\Exception $e) {
if ($this->showErrorsAsCSS) {
header('Content-type: text/css');
echo $this->createErrorCSS($e);
} else {
header($protocol . ' 500 Internal Server Error');
header('Content-type: text/plain');
echo 'Parse error: ' . $e->getMessage() . "\n";
}
}
return;
}
header('X-SCSS-Cache: true');
header('Content-type: text/css');
header('ETag: "' . $etag . '"');
if ($etag === $noneMatch) {
header($protocol . ' 304 Not Modified');
return;
}
$modifiedSince = $this->getIfModifiedSinceHeader();
$mtime = filemtime($output);
if (strtotime($modifiedSince) === $mtime) {
header($protocol . ' 304 Not Modified');
return;
}
$lastModified = gmdate('D, d M Y H:i:s', $mtime) . ' GMT';
header('Last-Modified: ' . $lastModified);
echo file_get_contents($output);
return;
}
header($protocol . ' 404 Not Found');
header('Content-type: text/plain');
$v = Version::VERSION;
echo "/* INPUT NOT FOUND scss $v */\n";
}
/**
* Based on explicit input/output files does a full change check on cache before compiling.
*
* @param string $in
* @param string $out
* @param boolean $force
*
* @return string Compiled CSS results
*
* @throws \Leafo\ScssPhp\Exception\ServerException
*/
public function checkedCachedCompile($in, $out, $force = false)
{
if (! is_file($in) || ! is_readable($in)) {
throw new ServerException('Invalid or unreadable input file specified.');
}
if (is_dir($out) || ! is_writable(file_exists($out) ? $out : dirname($out))) {
throw new ServerException('Invalid or unwritable output file specified.');
}
if ($force || $this->needsCompile($out, $etag)) {
list($css, $etag) = $this->compile($in, $out);
} else {
$css = file_get_contents($out);
}
return $css;
}
/**
* Constructor
*
* @param string $dir Root directory to .scss files
* @param string $cacheDir Cache directory
* @param \Leafo\ScssPhp\Compiler|null $scss SCSS compiler instance
*/
public function __construct($dir, $cacheDir = null, $scss = null)
{
$this->dir = $dir;
if (! isset($cacheDir)) {
$cacheDir = $this->join($dir, 'scss_cache');
}
$this->cacheDir = $cacheDir;
if (! is_dir($this->cacheDir)) {
mkdir($this->cacheDir, 0755, true);
}
if (! isset($scss)) {
$scss = new Compiler();
$scss->setImportPaths($this->dir);
}
$this->scss = $scss;
$this->showErrorsAsCSS = false;
if (! ini_get('date.timezone')) {
date_default_timezone_set('UTC');
}
}
/**
* Helper method to serve compiled scss
*
* @param string $path Root path
*/
public static function serveFrom($path)
{
$server = new self($path);
$server->serve();
}
}

69
lib/scssphp/Type.php Normal file
View File

@ -0,0 +1,69 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2015 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp;
/**
* Block/node types
*
* @author Anthon Pang <anthon.pang@gmail.com>
*/
class Type
{
const T_ASSIGN = 'assign';
const T_AT_ROOT = 'at-root';
const T_BLOCK = 'block';
const T_BREAK = 'break';
const T_CHARSET = 'charset';
const T_COLOR = 'color';
const T_COMMENT = 'comment';
const T_CONTINUE = 'continue';
const T_CONTROL = 'control';
const T_DEBUG = 'debug';
const T_DIRECTIVE = 'directive';
const T_EACH = 'each';
const T_ELSE = 'else';
const T_ELSEIF = 'elseif';
const T_ERROR = 'error';
const T_EXPRESSION = 'exp';
const T_EXTEND = 'extend';
const T_FOR = 'for';
const T_FUNCTION = 'function';
const T_FUNCTION_CALL = 'fncall';
const T_HSL = 'hsl';
const T_IF = 'if';
const T_IMPORT = 'import';
const T_INCLUDE = 'include';
const T_INTERPOLATE = 'interpolate';
const T_INTERPOLATED = 'interpolated';
const T_KEYWORD = 'keyword';
const T_LIST = 'list';
const T_MAP = 'map';
const T_MEDIA = 'media';
const T_MEDIA_EXPRESSION = 'mediaExp';
const T_MEDIA_TYPE = 'mediaType';
const T_MEDIA_VALUE = 'mediaValue';
const T_MIXIN = 'mixin';
const T_MIXIN_CONTENT = 'mixin_content';
const T_NESTED_PROPERTY = 'nestedprop';
const T_NOT = 'not';
const T_NULL = 'null';
const T_NUMBER = 'number';
const T_RETURN = 'return';
const T_ROOT = 'root';
const T_SCSSPHP_IMPORT_ONCE = 'scssphp-import-once';
const T_SELF = 'self';
const T_STRING = 'string';
const T_UNARY = 'unary';
const T_VARIABLE = 'var';
const T_WARN = 'warn';
const T_WHILE = 'while';
}

55
lib/scssphp/Util.php Normal file
View File

@ -0,0 +1,55 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2015 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp;
use Leafo\ScssPhp\Base\Range;
/**
* Utilties
*
* @author Anthon Pang <anthon.pang@gmail.com>
*/
class Util
{
/**
* Asserts that `value` falls within `range` (inclusive), leaving
* room for slight floating-point errors.
*
* @param string $name The name of the value. Used in the error message.
* @param Range $range Range of values.
* @param array $value The value to check.
* @param string $unit The unit of the value. Used in error reporting.
*
* @return mixed `value` adjusted to fall within range, if it was outside by a floating-point margin.
*
* @throws \Exception
*/
public static function checkRange($name, Range $range, $value, $unit = '')
{
$val = $value[1];
$grace = new Range(-0.00001, 0.00001);
if ($range->includes($val)) {
return $val;
}
if ($grace->includes($val - $range->first)) {
return $range->first;
}
if ($grace->includes($val - $range->last)) {
return $range->last;
}
throw new \Exception("$name {$val} must be between {$range->first} and {$range->last}$unit");
}
}

22
lib/scssphp/Version.php Normal file
View File

@ -0,0 +1,22 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2015 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp;
/**
* SCSSPHP version
*
* @author Leaf Corcoran <leafot@gmail.com>
*/
class Version
{
const VERSION = 'v0.6.5';
}

View File

@ -0,0 +1,15 @@
scssphp
-------
Import git ref: 62536ec1b32b63499684a91d67e8b6d90508bad2
(MOODLE_32_STABLE)
Downloaded from: https://github.com/moodlehq/scssphp
Original at: https://github.com/leafo/scssphp
Import procedure:
- Copy all the files from the folder 'src' this directory.
- Copy the license file from the project root.
Licensed under MIT, Copyright (c) 2015 Leaf Corcoran.

View File

@ -241,6 +241,12 @@
<license>GPL</license>
<version>1.6.3</version>
</library>
<library>
<location>scssphp</location>
<name>scssphp</name>
<license>MIT</license>
<version>0.6.5</version>
</library>
<library>
<location>spout</location>
<name>Spout</name>