mirror of
https://github.com/moodle/moodle.git
synced 2025-08-04 16:36:37 +02:00
Merge branch 'MDL-67379-master' of git://github.com/rezaies/moodle
This commit is contained in:
commit
6e2c4af47d
13 changed files with 1412 additions and 717 deletions
|
@ -57,12 +57,12 @@ class Cache
|
||||||
public function __construct($options)
|
public function __construct($options)
|
||||||
{
|
{
|
||||||
// check $cacheDir
|
// check $cacheDir
|
||||||
if (isset($options['cache_dir'])) {
|
if (isset($options['cacheDir'])) {
|
||||||
self::$cacheDir = $options['cache_dir'];
|
self::$cacheDir = $options['cacheDir'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty(self::$cacheDir)) {
|
if (empty(self::$cacheDir)) {
|
||||||
throw new Exception('cache_dir not set');
|
throw new Exception('cacheDir not set');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($options['prefix'])) {
|
if (isset($options['prefix'])) {
|
||||||
|
@ -74,7 +74,7 @@ class Cache
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($options['forceRefresh'])) {
|
if (isset($options['forceRefresh'])) {
|
||||||
self::$forceRefresh = $options['force_refresh'];
|
self::$forceRefresh = $options['forceRefresh'];
|
||||||
}
|
}
|
||||||
|
|
||||||
self::checkCacheDir();
|
self::checkCacheDir();
|
||||||
|
@ -97,7 +97,7 @@ class Cache
|
||||||
{
|
{
|
||||||
$fileCache = self::$cacheDir . self::cacheName($operation, $what, $options);
|
$fileCache = self::$cacheDir . self::cacheName($operation, $what, $options);
|
||||||
|
|
||||||
if ((! self::$forceRefresh || (self::$forceRefresh === 'once' &&
|
if (((self::$forceRefresh === false) || (self::$forceRefresh === 'once' &&
|
||||||
isset(self::$refreshed[$fileCache]))) && file_exists($fileCache)
|
isset(self::$refreshed[$fileCache]))) && file_exists($fileCache)
|
||||||
) {
|
) {
|
||||||
$cacheTime = filemtime($fileCache);
|
$cacheTime = filemtime($fileCache);
|
||||||
|
@ -176,13 +176,13 @@ class Cache
|
||||||
self::$cacheDir = str_replace('\\', '/', self::$cacheDir);
|
self::$cacheDir = str_replace('\\', '/', self::$cacheDir);
|
||||||
self::$cacheDir = rtrim(self::$cacheDir, '/') . '/';
|
self::$cacheDir = rtrim(self::$cacheDir, '/') . '/';
|
||||||
|
|
||||||
if (! file_exists(self::$cacheDir)) {
|
if (! is_dir(self::$cacheDir)) {
|
||||||
if (! mkdir(self::$cacheDir)) {
|
if (! mkdir(self::$cacheDir)) {
|
||||||
throw new Exception('Cache directory couldn\'t be created: ' . self::$cacheDir);
|
throw new Exception('Cache directory couldn\'t be created: ' . self::$cacheDir);
|
||||||
}
|
}
|
||||||
} elseif (! is_dir(self::$cacheDir)) {
|
}
|
||||||
throw new Exception('Cache directory doesn\'t exist: ' . self::$cacheDir);
|
|
||||||
} elseif (! is_writable(self::$cacheDir)) {
|
if (! is_writable(self::$cacheDir)) {
|
||||||
throw new Exception('Cache directory isn\'t writable: ' . self::$cacheDir);
|
throw new Exception('Cache directory isn\'t writable: ' . self::$cacheDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ class Colors
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
public static $cssColors = [
|
protected static $cssColors = [
|
||||||
'aliceblue' => '240,248,255',
|
'aliceblue' => '240,248,255',
|
||||||
'antiquewhite' => '250,235,215',
|
'antiquewhite' => '250,235,215',
|
||||||
'aqua' => '0,255,255',
|
'aqua' => '0,255,255',
|
||||||
|
@ -176,4 +176,71 @@ class Colors
|
||||||
'yellow' => '255,255,0',
|
'yellow' => '255,255,0',
|
||||||
'yellowgreen' => '154,205,50',
|
'yellowgreen' => '154,205,50',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert named color in a [r,g,b[,a]] array
|
||||||
|
*
|
||||||
|
* @param string $colorName
|
||||||
|
*
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
|
public static function colorNameToRGBa($colorName)
|
||||||
|
{
|
||||||
|
if (is_string($colorName) && isset(static::$cssColors[$colorName])) {
|
||||||
|
$rgba = explode(',', static::$cssColors[$colorName]);
|
||||||
|
|
||||||
|
// only case with opacity is transparent, with opacity=0, so we can intval on opacity also
|
||||||
|
$rgba = array_map('intval', $rgba);
|
||||||
|
|
||||||
|
return $rgba;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse conversion : from RGBA to a color name if possible
|
||||||
|
*
|
||||||
|
* @param integer $r
|
||||||
|
* @param integer $g
|
||||||
|
* @param integer $b
|
||||||
|
* @param integer $a
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public static function RGBaToColorName($r, $g, $b, $a = 1)
|
||||||
|
{
|
||||||
|
static $reverseColorTable = null;
|
||||||
|
|
||||||
|
if (! is_numeric($r) || ! is_numeric($g) || ! is_numeric($b) || ! is_numeric($a)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($a < 1) {
|
||||||
|
# specific case we dont' revert according to spec
|
||||||
|
#if (! $a && ! $r && ! $g && ! $b) {
|
||||||
|
# return 'transparent';
|
||||||
|
#}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_null($reverseColorTable)) {
|
||||||
|
$reverseColorTable = [];
|
||||||
|
|
||||||
|
foreach (static::$cssColors as $name => $rgb_str) {
|
||||||
|
$rgb_str = explode(',', $rgb_str);
|
||||||
|
|
||||||
|
if (count($rgb_str) == 3) {
|
||||||
|
$reverseColorTable[intval($rgb_str[0])][intval($rgb_str[1])][intval($rgb_str[2])] = $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($reverseColorTable[intval($r)][intval($g)][intval($b)])) {
|
||||||
|
return $reverseColorTable[intval($r)][intval($g)][intval($b)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -81,6 +81,11 @@ abstract class Formatter
|
||||||
*/
|
*/
|
||||||
protected $sourceMapGenerator;
|
protected $sourceMapGenerator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $strippedSemicolon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize formatter
|
* Initialize formatter
|
||||||
*
|
*
|
||||||
|
@ -113,24 +118,6 @@ abstract class Formatter
|
||||||
return rtrim($name) . $this->assignSeparator . $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
|
* Output lines inside a block
|
||||||
*
|
*
|
||||||
|
@ -207,6 +194,10 @@ abstract class Formatter
|
||||||
if (! empty($block->selectors)) {
|
if (! empty($block->selectors)) {
|
||||||
$this->indentLevel--;
|
$this->indentLevel--;
|
||||||
|
|
||||||
|
if (! $this->keepSemicolons) {
|
||||||
|
$this->strippedSemicolon = '';
|
||||||
|
}
|
||||||
|
|
||||||
if (empty($block->children)) {
|
if (empty($block->children)) {
|
||||||
$this->write($this->break);
|
$this->write($this->break);
|
||||||
}
|
}
|
||||||
|
@ -217,8 +208,10 @@ abstract class Formatter
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test and clean safely empty children
|
* Test and clean safely empty children
|
||||||
|
*
|
||||||
* @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block
|
* @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block
|
||||||
* @return bool
|
*
|
||||||
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
protected function testEmptyChildren($block)
|
protected function testEmptyChildren($block)
|
||||||
{
|
{
|
||||||
|
@ -228,14 +221,16 @@ abstract class Formatter
|
||||||
foreach ($block->children as $k => &$child) {
|
foreach ($block->children as $k => &$child) {
|
||||||
if (! $this->testEmptyChildren($child)) {
|
if (! $this->testEmptyChildren($child)) {
|
||||||
$isEmpty = false;
|
$isEmpty = false;
|
||||||
} else {
|
continue;
|
||||||
if ($child->type === Type::T_MEDIA || $child->type === Type::T_DIRECTIVE) {
|
}
|
||||||
$child->children = [];
|
|
||||||
$child->selectors = null;
|
if ($child->type === Type::T_MEDIA || $child->type === Type::T_DIRECTIVE) {
|
||||||
}
|
$child->children = [];
|
||||||
|
$child->selectors = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $isEmpty;
|
return $isEmpty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,8 +249,8 @@ abstract class Formatter
|
||||||
$this->sourceMapGenerator = null;
|
$this->sourceMapGenerator = null;
|
||||||
|
|
||||||
if ($sourceMapGenerator) {
|
if ($sourceMapGenerator) {
|
||||||
$this->currentLine = 1;
|
$this->currentLine = 1;
|
||||||
$this->currentColumn = 0;
|
$this->currentColumn = 0;
|
||||||
$this->sourceMapGenerator = $sourceMapGenerator;
|
$this->sourceMapGenerator = $sourceMapGenerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,10 +266,32 @@ abstract class Formatter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Output content
|
||||||
|
*
|
||||||
* @param string $str
|
* @param string $str
|
||||||
*/
|
*/
|
||||||
protected function write($str)
|
protected function write($str)
|
||||||
{
|
{
|
||||||
|
if (! empty($this->strippedSemicolon)) {
|
||||||
|
echo $this->strippedSemicolon;
|
||||||
|
|
||||||
|
$this->strippedSemicolon = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maybe Strip semi-colon appended by property(); it's a separator, not a terminator
|
||||||
|
* will be striped for real before a closing, otherwise displayed unchanged starting the next write
|
||||||
|
*/
|
||||||
|
if (! $this->keepSemicolons &&
|
||||||
|
$str &&
|
||||||
|
(strpos($str, ';') !== false) &&
|
||||||
|
(substr($str, -1) === ';')
|
||||||
|
) {
|
||||||
|
$str = substr($str, 0, -1);
|
||||||
|
|
||||||
|
$this->strippedSemicolon = ';';
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->sourceMapGenerator) {
|
if ($this->sourceMapGenerator) {
|
||||||
$this->sourceMapGenerator->addMapping(
|
$this->sourceMapGenerator->addMapping(
|
||||||
$this->currentLine,
|
$this->currentLine,
|
||||||
|
|
|
@ -55,7 +55,7 @@ class Expanded extends Formatter
|
||||||
|
|
||||||
foreach ($block->lines as $index => $line) {
|
foreach ($block->lines as $index => $line) {
|
||||||
if (substr($line, 0, 2) === '/*') {
|
if (substr($line, 0, 2) === '/*') {
|
||||||
$block->lines[$index] = preg_replace('/(\r|\n)+/', $glue, $line);
|
$block->lines[$index] = preg_replace('/[\r\n]+/', $glue, $line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,24 +63,13 @@ class Nested extends Formatter
|
||||||
|
|
||||||
foreach ($block->lines as $index => $line) {
|
foreach ($block->lines as $index => $line) {
|
||||||
if (substr($line, 0, 2) === '/*') {
|
if (substr($line, 0, 2) === '/*') {
|
||||||
$block->lines[$index] = preg_replace('/(\r|\n)+/', $glue, $line);
|
$block->lines[$index] = preg_replace('/[\r\n]+/', $glue, $line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->write($inner . implode($glue, $block->lines));
|
$this->write($inner . implode($glue, $block->lines));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function hasFlatChild($block)
|
|
||||||
{
|
|
||||||
foreach ($block->children as $child) {
|
|
||||||
if (empty($child->selectors)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
|
@ -109,7 +98,7 @@ class Nested extends Formatter
|
||||||
array_pop($depths);
|
array_pop($depths);
|
||||||
$this->depth--;
|
$this->depth--;
|
||||||
|
|
||||||
if (!$this->depth && ($block->depth <= 1 || (!$this->indentLevel && $block->type === Type::T_COMMENT)) &&
|
if (! $this->depth && ($block->depth <= 1 || (! $this->indentLevel && $block->type === Type::T_COMMENT)) &&
|
||||||
(($block->selectors && ! $isMediaOrDirective) || $previousHasSelector)
|
(($block->selectors && ! $isMediaOrDirective) || $previousHasSelector)
|
||||||
) {
|
) {
|
||||||
$downLevel = $this->break;
|
$downLevel = $this->break;
|
||||||
|
@ -170,15 +159,18 @@ class Nested extends Formatter
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->blockLines($block);
|
$this->blockLines($block);
|
||||||
|
|
||||||
$closeBlock = $this->break;
|
$closeBlock = $this->break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! empty($block->children)) {
|
if (! empty($block->children)) {
|
||||||
if ($this->depth>0 && ($isMediaOrDirective || ! $this->hasFlatChild($block))) {
|
if ($this->depth > 0 && ($isMediaOrDirective || ! $this->hasFlatChild($block))) {
|
||||||
array_pop($depths);
|
array_pop($depths);
|
||||||
|
|
||||||
$this->depth--;
|
$this->depth--;
|
||||||
$this->blockChildren($block);
|
$this->blockChildren($block);
|
||||||
$this->depth++;
|
$this->depth++;
|
||||||
|
|
||||||
$depths[] = $block->depth;
|
$depths[] = $block->depth;
|
||||||
} else {
|
} else {
|
||||||
$this->blockChildren($block);
|
$this->blockChildren($block);
|
||||||
|
@ -193,13 +185,19 @@ class Nested extends Formatter
|
||||||
if (! empty($block->selectors)) {
|
if (! empty($block->selectors)) {
|
||||||
$this->indentLevel--;
|
$this->indentLevel--;
|
||||||
|
|
||||||
|
if (! $this->keepSemicolons) {
|
||||||
|
$this->strippedSemicolon = '';
|
||||||
|
}
|
||||||
|
|
||||||
$this->write($this->close);
|
$this->write($this->close);
|
||||||
|
|
||||||
$closeBlock = $this->break;
|
$closeBlock = $this->break;
|
||||||
|
|
||||||
if ($this->depth > 1 && ! empty($block->children)) {
|
if ($this->depth > 1 && ! empty($block->children)) {
|
||||||
array_pop($depths);
|
array_pop($depths);
|
||||||
$this->depth--;
|
$this->depth--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $isMediaOrDirective) {
|
if (! $isMediaOrDirective) {
|
||||||
$previousHasSelector = true;
|
$previousHasSelector = true;
|
||||||
}
|
}
|
||||||
|
@ -209,4 +207,22 @@ class Nested extends Formatter
|
||||||
$this->write($this->break);
|
$this->write($this->break);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block has flat child
|
||||||
|
*
|
||||||
|
* @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
private function hasFlatChild($block)
|
||||||
|
{
|
||||||
|
foreach ($block->children as $child) {
|
||||||
|
if (empty($child->selectors)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,11 +141,11 @@ class Number extends Node implements \ArrayAccess
|
||||||
public function offsetExists($offset)
|
public function offsetExists($offset)
|
||||||
{
|
{
|
||||||
if ($offset === -3) {
|
if ($offset === -3) {
|
||||||
return $this->sourceColumn !== null;
|
return ! is_null($this->sourceColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($offset === -2) {
|
if ($offset === -2) {
|
||||||
return $this->sourceLine !== null;
|
return ! is_null($this->sourceLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($offset === -1 ||
|
if ($offset === -1 ||
|
||||||
|
|
|
@ -218,8 +218,8 @@ class Parser
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*
|
*
|
||||||
* @param string $buffer
|
* @param string $buffer
|
||||||
* @param string $out
|
* @param string|array $out
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
|
@ -245,8 +245,8 @@ class Parser
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*
|
*
|
||||||
* @param string $buffer
|
* @param string $buffer
|
||||||
* @param string $out
|
* @param string|array $out
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
|
@ -272,10 +272,10 @@ class Parser
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*
|
*
|
||||||
* @param string $buffer
|
* @param string $buffer
|
||||||
* @param string $out
|
* @param string|array $out
|
||||||
*
|
*
|
||||||
* @return array
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function parseMediaQueryList($buffer, &$out)
|
public function parseMediaQueryList($buffer, &$out)
|
||||||
{
|
{
|
||||||
|
@ -287,7 +287,6 @@ class Parser
|
||||||
|
|
||||||
$this->saveEncoding();
|
$this->saveEncoding();
|
||||||
|
|
||||||
|
|
||||||
$isMediaQuery = $this->mediaQueryList($out);
|
$isMediaQuery = $this->mediaQueryList($out);
|
||||||
|
|
||||||
$this->restoreEncoding();
|
$this->restoreEncoding();
|
||||||
|
@ -343,11 +342,14 @@ class Parser
|
||||||
if ($this->literal('@at-root', 8) &&
|
if ($this->literal('@at-root', 8) &&
|
||||||
($this->selectors($selector) || true) &&
|
($this->selectors($selector) || true) &&
|
||||||
($this->map($with) || true) &&
|
($this->map($with) || true) &&
|
||||||
|
(($this->matchChar('(')
|
||||||
|
&& $this->interpolation($with)
|
||||||
|
&& $this->matchChar(')')) || true) &&
|
||||||
$this->matchChar('{', false)
|
$this->matchChar('{', false)
|
||||||
) {
|
) {
|
||||||
$atRoot = $this->pushSpecialBlock(Type::T_AT_ROOT, $s);
|
$atRoot = $this->pushSpecialBlock(Type::T_AT_ROOT, $s);
|
||||||
$atRoot->selector = $selector;
|
$atRoot->selector = $selector;
|
||||||
$atRoot->with = $with;
|
$atRoot->with = $with;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -383,9 +385,18 @@ class Parser
|
||||||
($this->argValues($argValues) || true) &&
|
($this->argValues($argValues) || true) &&
|
||||||
$this->matchChar(')') || true) &&
|
$this->matchChar(')') || true) &&
|
||||||
($this->end() ||
|
($this->end() ||
|
||||||
|
($this->literal('using', 5) &&
|
||||||
|
$this->argumentDef($argUsing) &&
|
||||||
|
($this->end() || $this->matchChar('{') && $hasBlock = true)) ||
|
||||||
$this->matchChar('{') && $hasBlock = true)
|
$this->matchChar('{') && $hasBlock = true)
|
||||||
) {
|
) {
|
||||||
$child = [Type::T_INCLUDE, $mixinName, isset($argValues) ? $argValues : null, null];
|
$child = [
|
||||||
|
Type::T_INCLUDE,
|
||||||
|
$mixinName,
|
||||||
|
isset($argValues) ? $argValues : null,
|
||||||
|
null,
|
||||||
|
isset($argUsing) ? $argUsing : null
|
||||||
|
];
|
||||||
|
|
||||||
if (! empty($hasBlock)) {
|
if (! empty($hasBlock)) {
|
||||||
$include = $this->pushSpecialBlock(Type::T_INCLUDE, $s);
|
$include = $this->pushSpecialBlock(Type::T_INCLUDE, $s);
|
||||||
|
@ -524,9 +535,9 @@ class Parser
|
||||||
$this->matchChar('{', false)
|
$this->matchChar('{', false)
|
||||||
) {
|
) {
|
||||||
$for = $this->pushSpecialBlock(Type::T_FOR, $s);
|
$for = $this->pushSpecialBlock(Type::T_FOR, $s);
|
||||||
$for->var = $varName[1];
|
$for->var = $varName[1];
|
||||||
$for->start = $start;
|
$for->start = $start;
|
||||||
$for->end = $end;
|
$for->end = $end;
|
||||||
$for->until = isset($forUntil);
|
$for->until = isset($forUntil);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -536,7 +547,13 @@ class Parser
|
||||||
|
|
||||||
if ($this->literal('@if', 3) && $this->valueList($cond) && $this->matchChar('{', false)) {
|
if ($this->literal('@if', 3) && $this->valueList($cond) && $this->matchChar('{', false)) {
|
||||||
$if = $this->pushSpecialBlock(Type::T_IF, $s);
|
$if = $this->pushSpecialBlock(Type::T_IF, $s);
|
||||||
$if->cond = $cond;
|
while ($cond[0] === Type::T_LIST
|
||||||
|
&& !empty($cond['enclosing'])
|
||||||
|
&& $cond['enclosing'] === 'parent'
|
||||||
|
&& count($cond[2]) == 1) {
|
||||||
|
$cond = reset($cond[2]);
|
||||||
|
}
|
||||||
|
$if->cond = $cond;
|
||||||
$if->cases = [];
|
$if->cases = [];
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -577,8 +594,15 @@ class Parser
|
||||||
|
|
||||||
$this->seek($s);
|
$this->seek($s);
|
||||||
|
|
||||||
if ($this->literal('@content', 8) && $this->end()) {
|
#if ($this->literal('@content', 8))
|
||||||
$this->append([Type::T_MIXIN_CONTENT], $s);
|
|
||||||
|
if ($this->literal('@content', 8) &&
|
||||||
|
($this->end() ||
|
||||||
|
$this->matchChar('(') &&
|
||||||
|
$this->argValues($argContent) &&
|
||||||
|
$this->matchChar(')') &&
|
||||||
|
$this->end())) {
|
||||||
|
$this->append([Type::T_MIXIN_CONTENT, isset($argContent) ? $argContent : null], $s);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -633,9 +657,10 @@ class Parser
|
||||||
|
|
||||||
if ($this->literal('@supports', 9) &&
|
if ($this->literal('@supports', 9) &&
|
||||||
($t1=$this->supportsQuery($supportQuery)) &&
|
($t1=$this->supportsQuery($supportQuery)) &&
|
||||||
($t2=$this->matchChar('{', false)) ) {
|
($t2=$this->matchChar('{', false))
|
||||||
|
) {
|
||||||
$directive = $this->pushSpecialBlock(Type::T_DIRECTIVE, $s);
|
$directive = $this->pushSpecialBlock(Type::T_DIRECTIVE, $s);
|
||||||
$directive->name = 'supports';
|
$directive->name = 'supports';
|
||||||
$directive->value = $supportQuery;
|
$directive->value = $supportQuery;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -665,6 +690,19 @@ class Parser
|
||||||
|
|
||||||
$this->seek($s);
|
$this->seek($s);
|
||||||
|
|
||||||
|
// maybe it's a generic blockless directive
|
||||||
|
if ($this->matchChar('@', false) &&
|
||||||
|
$this->keyword($dirName) &&
|
||||||
|
$this->valueList($dirValue) &&
|
||||||
|
$this->end()
|
||||||
|
) {
|
||||||
|
$this->append([Type::T_DIRECTIVE, [$dirName, $dirValue]], $s);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->seek($s);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -709,7 +747,7 @@ class Parser
|
||||||
|
|
||||||
if ($this->eatWhiteDefault) {
|
if ($this->eatWhiteDefault) {
|
||||||
$this->whitespace();
|
$this->whitespace();
|
||||||
$this->append(null); // collect comments at the begining if needed
|
$this->append(null); // collect comments at the beginning if needed
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -751,7 +789,7 @@ class Parser
|
||||||
if ($this->matchChar('}', false)) {
|
if ($this->matchChar('}', false)) {
|
||||||
$block = $this->popBlock();
|
$block = $this->popBlock();
|
||||||
|
|
||||||
if (!isset($block->type) || $block->type !== Type::T_IF) {
|
if (! isset($block->type) || $block->type !== Type::T_IF) {
|
||||||
if ($this->env->parent) {
|
if ($this->env->parent) {
|
||||||
$this->append(null); // collect comments before next statement if needed
|
$this->append(null); // collect comments before next statement if needed
|
||||||
}
|
}
|
||||||
|
@ -823,7 +861,7 @@ class Parser
|
||||||
|
|
||||||
$this->env = $b;
|
$this->env = $b;
|
||||||
|
|
||||||
// collect comments at the begining of a block if needed
|
// collect comments at the beginning of a block if needed
|
||||||
if ($this->eatWhiteDefault) {
|
if ($this->eatWhiteDefault) {
|
||||||
$this->whitespace();
|
$this->whitespace();
|
||||||
|
|
||||||
|
@ -1055,16 +1093,17 @@ class Parser
|
||||||
if (isset($m[1]) && empty($this->commentsSeen[$this->count])) {
|
if (isset($m[1]) && empty($this->commentsSeen[$this->count])) {
|
||||||
// comment that are kept in the output CSS
|
// comment that are kept in the output CSS
|
||||||
$comment = [];
|
$comment = [];
|
||||||
|
$startCommentCount = $this->count;
|
||||||
$endCommentCount = $this->count + strlen($m[1]);
|
$endCommentCount = $this->count + strlen($m[1]);
|
||||||
|
|
||||||
// find interpolations in comment
|
// find interpolations in comment
|
||||||
$p = strpos($this->buffer, '#{', $this->count);
|
$p = strpos($this->buffer, '#{', $this->count);
|
||||||
|
|
||||||
while ($p !== false && $p < $endCommentCount) {
|
while ($p !== false && $p < $endCommentCount) {
|
||||||
$c = substr($this->buffer, $this->count, $p - $this->count);
|
$c = substr($this->buffer, $this->count, $p - $this->count);
|
||||||
$comment[] = $c;
|
$comment[] = $c;
|
||||||
$this->count = $p;
|
$this->count = $p;
|
||||||
$out = null;
|
$out = null;
|
||||||
|
|
||||||
if ($this->interpolation($out)) {
|
if ($this->interpolation($out)) {
|
||||||
// keep right spaces in the following string part
|
// keep right spaces in the following string part
|
||||||
|
@ -1076,7 +1115,7 @@ class Parser
|
||||||
$out[3] = '';
|
$out[3] = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$comment[] = $out;
|
$comment[] = [Type::T_COMMENT, substr($this->buffer, $p, $this->count - $p), $out];
|
||||||
} else {
|
} else {
|
||||||
$comment[] = substr($this->buffer, $this->count, 2);
|
$comment[] = substr($this->buffer, $this->count, 2);
|
||||||
|
|
||||||
|
@ -1094,10 +1133,11 @@ class Parser
|
||||||
$this->appendComment([Type::T_COMMENT, $c]);
|
$this->appendComment([Type::T_COMMENT, $c]);
|
||||||
} else {
|
} else {
|
||||||
$comment[] = $c;
|
$comment[] = $c;
|
||||||
$this->appendComment([Type::T_COMMENT, [Type::T_STRING, '', $comment]]);
|
$staticComment = substr($this->buffer, $startCommentCount, $endCommentCount - $startCommentCount);
|
||||||
|
$this->appendComment([Type::T_COMMENT, $staticComment, [Type::T_STRING, '', $comment]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->commentsSeen[$this->count] = true;
|
$this->commentsSeen[$startCommentCount] = true;
|
||||||
$this->count = $endCommentCount;
|
$this->count = $endCommentCount;
|
||||||
} else {
|
} else {
|
||||||
// comment that are ignored and not kept in the output css
|
// comment that are ignored and not kept in the output css
|
||||||
|
@ -1118,8 +1158,21 @@ class Parser
|
||||||
protected function appendComment($comment)
|
protected function appendComment($comment)
|
||||||
{
|
{
|
||||||
if (! $this->discardComments) {
|
if (! $this->discardComments) {
|
||||||
if ($comment[0] === Type::T_COMMENT && is_string($comment[1])) {
|
if ($comment[0] === Type::T_COMMENT) {
|
||||||
$comment[1] = substr(preg_replace(['/^\s+/m', '/^(.)/m'], ['', ' \1'], $comment[1]), 1);
|
if (is_string($comment[1])) {
|
||||||
|
$comment[1] = substr(preg_replace(['/^\s+/m', '/^(.)/m'], ['', ' \1'], $comment[1]), 1);
|
||||||
|
}
|
||||||
|
if (isset($comment[2]) and is_array($comment[2]) and $comment[2][0] === Type::T_STRING) {
|
||||||
|
foreach ($comment[2][2] as $k => $v) {
|
||||||
|
if (is_string($v)) {
|
||||||
|
$p = strpos($v, "\n");
|
||||||
|
if ($p !== false) {
|
||||||
|
$comment[2][2][$k] = substr($v, 0, $p + 1)
|
||||||
|
. preg_replace(['/^\s+/m', '/^(.)/m'], ['', ' \1'], substr($v, $p+1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->env->comments[] = $comment;
|
$this->env->comments[] = $comment;
|
||||||
|
@ -1135,7 +1188,7 @@ class Parser
|
||||||
protected function append($statement, $pos = null)
|
protected function append($statement, $pos = null)
|
||||||
{
|
{
|
||||||
if (! is_null($statement)) {
|
if (! is_null($statement)) {
|
||||||
if ($pos !== null) {
|
if (! is_null($pos)) {
|
||||||
list($line, $column) = $this->getSourcePosition($pos);
|
list($line, $column) = $this->getSourcePosition($pos);
|
||||||
|
|
||||||
$statement[static::SOURCE_LINE] = $line;
|
$statement[static::SOURCE_LINE] = $line;
|
||||||
|
@ -1247,12 +1300,14 @@ class Parser
|
||||||
$s = $this->count;
|
$s = $this->count;
|
||||||
|
|
||||||
$not = false;
|
$not = false;
|
||||||
|
|
||||||
if (($this->literal('not', 3) && ($not = true) || true) &&
|
if (($this->literal('not', 3) && ($not = true) || true) &&
|
||||||
$this->matchChar('(') &&
|
$this->matchChar('(') &&
|
||||||
($this->expression($property)) &&
|
($this->expression($property)) &&
|
||||||
$this->literal(': ', 2) &&
|
$this->literal(': ', 2) &&
|
||||||
$this->valueList($value) &&
|
$this->valueList($value) &&
|
||||||
$this->matchChar(')')) {
|
$this->matchChar(')')
|
||||||
|
) {
|
||||||
$support = [Type::T_STRING, '', [[Type::T_KEYWORD, ($not ? 'not ' : '') . '(']]];
|
$support = [Type::T_STRING, '', [[Type::T_KEYWORD, ($not ? 'not ' : '') . '(']]];
|
||||||
$support[2][] = $property;
|
$support[2][] = $property;
|
||||||
$support[2][] = [Type::T_KEYWORD, ': '];
|
$support[2][] = [Type::T_KEYWORD, ': '];
|
||||||
|
@ -1267,7 +1322,8 @@ class Parser
|
||||||
|
|
||||||
if ($this->matchChar('(') &&
|
if ($this->matchChar('(') &&
|
||||||
$this->supportsQuery($subQuery) &&
|
$this->supportsQuery($subQuery) &&
|
||||||
$this->matchChar(')')) {
|
$this->matchChar(')')
|
||||||
|
) {
|
||||||
$parts[] = [Type::T_STRING, '', [[Type::T_KEYWORD, '('], $subQuery, [Type::T_KEYWORD, ')']]];
|
$parts[] = [Type::T_STRING, '', [[Type::T_KEYWORD, '('], $subQuery, [Type::T_KEYWORD, ')']]];
|
||||||
$s = $this->count;
|
$s = $this->count;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1275,7 +1331,8 @@ class Parser
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->literal('not', 3) &&
|
if ($this->literal('not', 3) &&
|
||||||
$this->supportsQuery($subQuery)) {
|
$this->supportsQuery($subQuery)
|
||||||
|
) {
|
||||||
$parts[] = [Type::T_STRING, '', [[Type::T_KEYWORD, 'not '], $subQuery]];
|
$parts[] = [Type::T_STRING, '', [[Type::T_KEYWORD, 'not '], $subQuery]];
|
||||||
$s = $this->count;
|
$s = $this->count;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1284,12 +1341,15 @@ class Parser
|
||||||
|
|
||||||
if ($this->literal('selector(', 9) &&
|
if ($this->literal('selector(', 9) &&
|
||||||
$this->selector($selector) &&
|
$this->selector($selector) &&
|
||||||
$this->matchChar(')')) {
|
$this->matchChar(')')
|
||||||
|
) {
|
||||||
$support = [Type::T_STRING, '', [[Type::T_KEYWORD, 'selector(']]];
|
$support = [Type::T_STRING, '', [[Type::T_KEYWORD, 'selector(']]];
|
||||||
|
|
||||||
$selectorList = [Type::T_LIST, '', []];
|
$selectorList = [Type::T_LIST, '', []];
|
||||||
|
|
||||||
foreach ($selector as $sc) {
|
foreach ($selector as $sc) {
|
||||||
$compound = [Type::T_STRING, '', []];
|
$compound = [Type::T_STRING, '', []];
|
||||||
|
|
||||||
foreach ($sc as $scp) {
|
foreach ($sc as $scp) {
|
||||||
if (is_array($scp)) {
|
if (is_array($scp)) {
|
||||||
$compound[2][] = $scp;
|
$compound[2][] = $scp;
|
||||||
|
@ -1297,6 +1357,7 @@ class Parser
|
||||||
$compound[2][] = [Type::T_KEYWORD, $scp];
|
$compound[2][] = [Type::T_KEYWORD, $scp];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$selectorList[2][] = $compound;
|
$selectorList[2][] = $compound;
|
||||||
}
|
}
|
||||||
$support[2][] = $selectorList;
|
$support[2][] = $selectorList;
|
||||||
|
@ -1317,6 +1378,7 @@ class Parser
|
||||||
if ($this->literal('and', 3) &&
|
if ($this->literal('and', 3) &&
|
||||||
$this->genericList($expressions, 'supportsQuery', ' and', false)) {
|
$this->genericList($expressions, 'supportsQuery', ' and', false)) {
|
||||||
array_unshift($expressions[2], [Type::T_STRING, '', $parts]);
|
array_unshift($expressions[2], [Type::T_STRING, '', $parts]);
|
||||||
|
|
||||||
$parts = [$expressions];
|
$parts = [$expressions];
|
||||||
$s = $this->count;
|
$s = $this->count;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1326,6 +1388,7 @@ class Parser
|
||||||
if ($this->literal('or', 2) &&
|
if ($this->literal('or', 2) &&
|
||||||
$this->genericList($expressions, 'supportsQuery', ' or', false)) {
|
$this->genericList($expressions, 'supportsQuery', ' or', false)) {
|
||||||
array_unshift($expressions[2], [Type::T_STRING, '', $parts]);
|
array_unshift($expressions[2], [Type::T_STRING, '', $parts]);
|
||||||
|
|
||||||
$parts = [$expressions];
|
$parts = [$expressions];
|
||||||
$s = $this->count;
|
$s = $this->count;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1336,7 +1399,9 @@ class Parser
|
||||||
if ($this->eatWhiteDefault) {
|
if ($this->eatWhiteDefault) {
|
||||||
$this->whitespace();
|
$this->whitespace();
|
||||||
}
|
}
|
||||||
|
|
||||||
$out = [Type::T_STRING, '', $parts];
|
$out = [Type::T_STRING, '', $parts];
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1408,6 +1473,7 @@ class Parser
|
||||||
|
|
||||||
if (! $this->variable($keyword) || ! $this->matchChar(':')) {
|
if (! $this->variable($keyword) || ! $this->matchChar(':')) {
|
||||||
$this->seek($s);
|
$this->seek($s);
|
||||||
|
|
||||||
$keyword = null;
|
$keyword = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1436,7 +1502,12 @@ class Parser
|
||||||
*/
|
*/
|
||||||
protected function valueList(&$out)
|
protected function valueList(&$out)
|
||||||
{
|
{
|
||||||
return $this->genericList($out, 'spaceList', ',');
|
$discardComments = $this->discardComments;
|
||||||
|
$this->discardComments = true;
|
||||||
|
$res = $this->genericList($out, 'spaceList', ',');
|
||||||
|
$this->discardComments = $discardComments;
|
||||||
|
|
||||||
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1463,17 +1534,19 @@ class Parser
|
||||||
*/
|
*/
|
||||||
protected function genericList(&$out, $parseItem, $delim = '', $flatten = true)
|
protected function genericList(&$out, $parseItem, $delim = '', $flatten = true)
|
||||||
{
|
{
|
||||||
$s = $this->count;
|
$s = $this->count;
|
||||||
$items = [];
|
$items = [];
|
||||||
$value = null;
|
$value = null;
|
||||||
|
|
||||||
while ($this->$parseItem($value)) {
|
while ($this->$parseItem($value)) {
|
||||||
|
$trailing_delim = false;
|
||||||
$items[] = $value;
|
$items[] = $value;
|
||||||
|
|
||||||
if ($delim) {
|
if ($delim) {
|
||||||
if (! $this->literal($delim, strlen($delim))) {
|
if (! $this->literal($delim, strlen($delim))) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
$trailing_delim = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1483,6 +1556,9 @@ class Parser
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($trailing_delim) {
|
||||||
|
$items[] = [Type::T_NULL];
|
||||||
|
}
|
||||||
if ($flatten && count($items) === 1) {
|
if ($flatten && count($items) === 1) {
|
||||||
$out = $items[0];
|
$out = $items[0];
|
||||||
} else {
|
} else {
|
||||||
|
@ -1496,41 +1572,58 @@ class Parser
|
||||||
* Parse expression
|
* Parse expression
|
||||||
*
|
*
|
||||||
* @param array $out
|
* @param array $out
|
||||||
|
* @param bool $listOnly
|
||||||
|
* @param bool $lookForExp
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
protected function expression(&$out)
|
protected function expression(&$out, $listOnly = false, $lookForExp = true)
|
||||||
{
|
{
|
||||||
$s = $this->count;
|
$s = $this->count;
|
||||||
$discard = $this->discardComments;
|
$discard = $this->discardComments;
|
||||||
$this->discardComments = true;
|
$this->discardComments = true;
|
||||||
|
$allowedTypes = ($listOnly ? [Type::T_LIST] : [Type::T_LIST, Type::T_MAP]);
|
||||||
|
|
||||||
if ($this->matchChar('(')) {
|
if ($this->matchChar('(')) {
|
||||||
if ($this->parenExpression($out, $s, ")")) {
|
if ($this->enclosedExpression($lhs, $s, ")", $allowedTypes)) {
|
||||||
$this->discardComments = $discard;
|
if ($lookForExp) {
|
||||||
return true;
|
$out = $this->expHelper($lhs, 0);
|
||||||
}
|
} else {
|
||||||
|
$out = $lhs;
|
||||||
$this->seek($s);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->matchChar('[')) {
|
|
||||||
if ($this->parenExpression($out, $s, "]", [Type::T_LIST, Type::T_KEYWORD])) {
|
|
||||||
if ($out[0] !== Type::T_LIST && $out[0] !== Type::T_MAP) {
|
|
||||||
$out = [Type::T_STRING, '', [ '[', $out, ']' ]];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->discardComments = $discard;
|
$this->discardComments = $discard;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->seek($s);
|
$this->seek($s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->value($lhs)) {
|
if (in_array(Type::T_LIST, $allowedTypes) && $this->matchChar('[')) {
|
||||||
$out = $this->expHelper($lhs, 0);
|
if ($this->enclosedExpression($lhs, $s, "]", [Type::T_LIST])) {
|
||||||
|
if ($lookForExp) {
|
||||||
|
$out = $this->expHelper($lhs, 0);
|
||||||
|
} else {
|
||||||
|
$out = $lhs;
|
||||||
|
}
|
||||||
|
$this->discardComments = $discard;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->seek($s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$listOnly && $this->value($lhs)) {
|
||||||
|
if ($lookForExp) {
|
||||||
|
$out = $this->expHelper($lhs, 0);
|
||||||
|
} else {
|
||||||
|
$out = $lhs;
|
||||||
|
}
|
||||||
|
|
||||||
$this->discardComments = $discard;
|
$this->discardComments = $discard;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1548,15 +1641,35 @@ class Parser
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
protected function parenExpression(&$out, $s, $closingParen = ")", $allowedTypes = [Type::T_LIST, Type::T_MAP])
|
protected function enclosedExpression(&$out, $s, $closingParen = ")", $allowedTypes = [Type::T_LIST, Type::T_MAP])
|
||||||
{
|
{
|
||||||
if ($this->matchChar($closingParen)) {
|
if ($this->matchChar($closingParen) && in_array(Type::T_LIST, $allowedTypes)) {
|
||||||
$out = [Type::T_LIST, '', []];
|
$out = [Type::T_LIST, '', []];
|
||||||
|
switch ($closingParen) {
|
||||||
|
case ")":
|
||||||
|
$out['enclosing'] = 'parent'; // parenthesis list
|
||||||
|
break;
|
||||||
|
case "]":
|
||||||
|
$out['enclosing'] = 'bracket'; // bracketed list
|
||||||
|
break;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->valueList($out) && $this->matchChar($closingParen) && in_array($out[0], $allowedTypes)) {
|
if ($this->valueList($out) && $this->matchChar($closingParen)
|
||||||
|
&& in_array($out[0], [Type::T_LIST, Type::T_KEYWORD])
|
||||||
|
&& in_array(Type::T_LIST, $allowedTypes)) {
|
||||||
|
if ($out[0] !== Type::T_LIST || ! empty($out['enclosing'])) {
|
||||||
|
$out = [Type::T_LIST, '', [$out]];
|
||||||
|
}
|
||||||
|
switch ($closingParen) {
|
||||||
|
case ")":
|
||||||
|
$out['enclosing'] = 'parent'; // parenthesis list
|
||||||
|
break;
|
||||||
|
case "]":
|
||||||
|
$out['enclosing'] = 'bracket'; // bracketed list
|
||||||
|
break;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1600,7 +1713,7 @@ class Parser
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $this->value($rhs)) {
|
if (! $this->value($rhs) && ! $this->expression($rhs, true, false)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1655,7 +1768,7 @@ class Parser
|
||||||
|
|
||||||
$this->seek($s);
|
$this->seek($s);
|
||||||
|
|
||||||
if ($this->literal('url(', 4, false) && $this->match('\s*(\/\/\S+)\s*', $m)) {
|
if ($this->literal('url(', 4, false) && $this->match('\s*(\/\/[^\s\)]+)\s*', $m)) {
|
||||||
$content = 'url(' . $m[1];
|
$content = 'url(' . $m[1];
|
||||||
|
|
||||||
if ($this->matchChar(')')) {
|
if ($this->matchChar(')')) {
|
||||||
|
@ -1751,6 +1864,7 @@ class Parser
|
||||||
// unicode range with wildcards
|
// unicode range with wildcards
|
||||||
if ($this->literal('U+', 2) && $this->match('([0-9A-F]+\?*)(-([0-9A-F]+))?', $m, false)) {
|
if ($this->literal('U+', 2) && $this->match('([0-9A-F]+\?*)(-([0-9A-F]+))?', $m, false)) {
|
||||||
$out = [Type::T_KEYWORD, 'U+' . $m[0]];
|
$out = [Type::T_KEYWORD, 'U+' . $m[0]];
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2040,55 +2154,16 @@ class Parser
|
||||||
*/
|
*/
|
||||||
protected function color(&$out)
|
protected function color(&$out)
|
||||||
{
|
{
|
||||||
$color = [Type::T_COLOR];
|
$s = $this->count;
|
||||||
$s = $this->count;
|
|
||||||
|
|
||||||
if ($this->match('(#([0-9a-f]+))', $m)) {
|
if ($this->match('(#([0-9a-f]+))', $m)) {
|
||||||
$nofValues = strlen($m[2]);
|
if (in_array(strlen($m[2]), [3,4,6,8])) {
|
||||||
$hasAlpha = $nofValues === 4 || $nofValues === 8;
|
$out = [Type::T_KEYWORD, $m[0]];
|
||||||
$channels = $hasAlpha ? [4, 3, 2, 1] : [3, 2, 1];
|
return true;
|
||||||
|
|
||||||
switch ($nofValues) {
|
|
||||||
case 3:
|
|
||||||
case 4:
|
|
||||||
$num = hexdec($m[2]);
|
|
||||||
|
|
||||||
foreach ($channels as $i) {
|
|
||||||
$t = $num & 0xf;
|
|
||||||
$color[$i] = $t << 4 | $t;
|
|
||||||
$num >>= 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 6:
|
|
||||||
case 8:
|
|
||||||
$num = hexdec($m[2]);
|
|
||||||
|
|
||||||
foreach ($channels as $i) {
|
|
||||||
$color[$i] = $num & 0xff;
|
|
||||||
$num >>= 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
$this->seek($s);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($hasAlpha) {
|
$this->seek($s);
|
||||||
if ($color[4] === 255) {
|
return false;
|
||||||
$color[4] = 1; // fully opaque
|
|
||||||
} else {
|
|
||||||
$color[4] = round($color[4] / 255, 3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$out = $color;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -2322,8 +2397,8 @@ class Parser
|
||||||
/**
|
/**
|
||||||
* Parser interpolation
|
* Parser interpolation
|
||||||
*
|
*
|
||||||
* @param array $out
|
* @param string|array $out
|
||||||
* @param boolean $lookWhite save information about whitespace before and after
|
* @param boolean $lookWhite save information about whitespace before and after
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
|
@ -2428,7 +2503,8 @@ class Parser
|
||||||
/**
|
/**
|
||||||
* Parse comma separated selector list
|
* Parse comma separated selector list
|
||||||
*
|
*
|
||||||
* @param array $out
|
* @param array $out
|
||||||
|
* @param boolean $subSelector
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
|
@ -2463,7 +2539,8 @@ class Parser
|
||||||
/**
|
/**
|
||||||
* Parse whitespace separated selector list
|
* Parse whitespace separated selector list
|
||||||
*
|
*
|
||||||
* @param array $out
|
* @param array $out
|
||||||
|
* @param boolean $subSelector
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
|
@ -2472,9 +2549,17 @@ class Parser
|
||||||
$selector = [];
|
$selector = [];
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
$s = $this->count;
|
||||||
|
|
||||||
if ($this->match('[>+~]+', $m, true)) {
|
if ($this->match('[>+~]+', $m, true)) {
|
||||||
$selector[] = [$m[0]];
|
if ($subSelector && is_string($subSelector) && strpos($subSelector, 'nth-') === 0 &&
|
||||||
continue;
|
$m[0] === '+' && $this->match("(\d+|n\b)", $counter)
|
||||||
|
) {
|
||||||
|
$this->seek($s);
|
||||||
|
} else {
|
||||||
|
$selector[] = [$m[0]];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->selectorSingle($part, $subSelector)) {
|
if ($this->selectorSingle($part, $subSelector)) {
|
||||||
|
@ -2507,7 +2592,8 @@ class Parser
|
||||||
* div[yes=no]#something.hello.world:nth-child(-2n+1)%placeholder
|
* div[yes=no]#something.hello.world:nth-child(-2n+1)%placeholder
|
||||||
* }}
|
* }}
|
||||||
*
|
*
|
||||||
* @param array $out
|
* @param array $out
|
||||||
|
* @param boolean $subSelector
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
|
@ -2606,10 +2692,13 @@ class Parser
|
||||||
$ss = $this->count;
|
$ss = $this->count;
|
||||||
|
|
||||||
if ($nameParts === ['not'] || $nameParts === ['is'] ||
|
if ($nameParts === ['not'] || $nameParts === ['is'] ||
|
||||||
$nameParts === ['has'] || $nameParts === ['where']
|
$nameParts === ['has'] || $nameParts === ['where'] ||
|
||||||
|
$nameParts === ['slotted'] ||
|
||||||
|
$nameParts === ['nth-child'] || $nameParts == ['nth-last-child'] ||
|
||||||
|
$nameParts === ['nth-of-type'] || $nameParts == ['nth-last-of-type']
|
||||||
) {
|
) {
|
||||||
if ($this->matchChar('(') &&
|
if ($this->matchChar('(', true) &&
|
||||||
($this->selectors($subs, true) || true) &&
|
($this->selectors($subs, reset($nameParts)) || true) &&
|
||||||
$this->matchChar(')')
|
$this->matchChar(')')
|
||||||
) {
|
) {
|
||||||
$parts[] = '(';
|
$parts[] = '(';
|
||||||
|
@ -2619,10 +2708,12 @@ class Parser
|
||||||
foreach ($ps as &$p) {
|
foreach ($ps as &$p) {
|
||||||
$parts[] = $p;
|
$parts[] = $p;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($sub) && reset($sub)) {
|
if (count($sub) && reset($sub)) {
|
||||||
$parts[] = ' ';
|
$parts[] = ' ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($subs) && reset($subs)) {
|
if (count($subs) && reset($subs)) {
|
||||||
$parts[] = ', ';
|
$parts[] = ', ';
|
||||||
}
|
}
|
||||||
|
@ -2655,6 +2746,17 @@ class Parser
|
||||||
|
|
||||||
$this->seek($s);
|
$this->seek($s);
|
||||||
|
|
||||||
|
// 2n+1
|
||||||
|
if ($subSelector && is_string($subSelector) && strpos($subSelector, 'nth-') === 0) {
|
||||||
|
if ($this->match("(\s*(\+\s*|\-\s*)?(\d+|n|\d+n))+", $counter)) {
|
||||||
|
$parts[] = $counter[0];
|
||||||
|
//$parts[] = str_replace(' ', '', $counter[0]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->seek($s);
|
||||||
|
|
||||||
// attribute selector
|
// attribute selector
|
||||||
if ($char === '[' &&
|
if ($char === '[' &&
|
||||||
$this->matchChar('[') &&
|
$this->matchChar('[') &&
|
||||||
|
@ -2769,7 +2871,7 @@ class Parser
|
||||||
/**
|
/**
|
||||||
* Parse a placeholder
|
* Parse a placeholder
|
||||||
*
|
*
|
||||||
* @param string $placeholder
|
* @param string|array $placeholder
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
|
@ -2785,6 +2887,7 @@ class Parser
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->interpolation($placeholder)) {
|
if ($this->interpolation($placeholder)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2846,12 +2949,9 @@ class Parser
|
||||||
while ($lastNode[0] === Type::T_KEYWORD && in_array($lastNode[1], ['!default', '!global'])) {
|
while ($lastNode[0] === Type::T_KEYWORD && in_array($lastNode[1], ['!default', '!global'])) {
|
||||||
array_pop($token[2]);
|
array_pop($token[2]);
|
||||||
|
|
||||||
$node = end($token[2]);
|
$node = end($token[2]);
|
||||||
|
$token = $this->flattenList($token);
|
||||||
$token = $this->flattenList($token);
|
$flags[] = $lastNode[1];
|
||||||
|
|
||||||
$flags[] = $lastNode[1];
|
|
||||||
|
|
||||||
$lastNode = $node;
|
$lastNode = $node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2869,9 +2969,8 @@ class Parser
|
||||||
protected function stripOptionalFlag(&$selectors)
|
protected function stripOptionalFlag(&$selectors)
|
||||||
{
|
{
|
||||||
$optional = false;
|
$optional = false;
|
||||||
|
|
||||||
$selector = end($selectors);
|
$selector = end($selectors);
|
||||||
$part = end($selector);
|
$part = end($selector);
|
||||||
|
|
||||||
if ($part === ['!optional']) {
|
if ($part === ['!optional']) {
|
||||||
array_pop($selectors[count($selectors) - 1]);
|
array_pop($selectors[count($selectors) - 1]);
|
||||||
|
@ -2915,6 +3014,8 @@ class Parser
|
||||||
$validChars = $allowNewline ? '.' : "[^\n]";
|
$validChars = $allowNewline ? '.' : "[^\n]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$m = null;
|
||||||
|
|
||||||
if (! $this->match('(' . $validChars . '*?)' . $this->pregQuote($what), $m, ! $until)) {
|
if (! $this->match('(' . $validChars . '*?)' . $this->pregQuote($what), $m, ! $until)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -3014,9 +3115,10 @@ class Parser
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$iniDirective = 'mbstring' . '.func_overload'; // deprecated in PHP 7.2
|
// deprecated in PHP 7.2
|
||||||
|
$iniDirective = 'mbstring.func_overload';
|
||||||
|
|
||||||
if (ini_get($iniDirective) & 2) {
|
if (extension_loaded('mbstring') && ini_get($iniDirective) & 2) {
|
||||||
$this->encoding = mb_internal_encoding();
|
$this->encoding = mb_internal_encoding();
|
||||||
|
|
||||||
mb_internal_encoding('iso-8859-1');
|
mb_internal_encoding('iso-8859-1');
|
||||||
|
@ -3028,7 +3130,7 @@ class Parser
|
||||||
*/
|
*/
|
||||||
private function restoreEncoding()
|
private function restoreEncoding()
|
||||||
{
|
{
|
||||||
if ($this->encoding) {
|
if (extension_loaded('mbstring') && $this->encoding) {
|
||||||
mb_internal_encoding($this->encoding);
|
mb_internal_encoding($this->encoding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,8 +130,17 @@ class Base64VLQ
|
||||||
private static function fromVLQSigned($value)
|
private static function fromVLQSigned($value)
|
||||||
{
|
{
|
||||||
$negate = ($value & 1) === 1;
|
$negate = ($value & 1) === 1;
|
||||||
$value = $value >> 1;
|
$value = ($value >> 1) & ~(1<<(8 * PHP_INT_SIZE - 1)); // unsigned right shift
|
||||||
|
|
||||||
return $negate ? -$value : $value;
|
if (! $negate) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to OR 0x80000000 here to ensure the 32nd bit (the sign bit) is
|
||||||
|
// always set for negative numbers. If `value` were 1, (meaning `negate` is
|
||||||
|
// true and all other bits were zeros), `value` would now be 0. -0 is just
|
||||||
|
// 0, and doesn't flip the 32nd bit as intended. All positive numbers will
|
||||||
|
// successfully flip the 32nd bit without issue, so it's a noop for them.
|
||||||
|
return -$value | 0x80000000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,217 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* SCSSPHP
|
|
||||||
*
|
|
||||||
* @copyright 2012-2019 Leaf Corcoran
|
|
||||||
*
|
|
||||||
* @license http://opensource.org/licenses/MIT MIT
|
|
||||||
*
|
|
||||||
* @link http://scssphp.github.io/scssphp
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace ScssPhp\ScssPhp\SourceMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base64 VLQ Encoder
|
|
||||||
*
|
|
||||||
* {@internal Derivative of oyejorge/less.php's lib/SourceMap/Base64VLQ.php, relicensed with permission. }}
|
|
||||||
*
|
|
||||||
* @author Josh Schmidt <oyejorge@gmail.com>
|
|
||||||
* @author Nicolas FRANÇOIS <nicolas.francois@frog-labs.com>
|
|
||||||
*/
|
|
||||||
class Base64VLQEncoder
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Shift
|
|
||||||
*
|
|
||||||
* @var integer
|
|
||||||
*/
|
|
||||||
private $shift = 5;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mask
|
|
||||||
*
|
|
||||||
* @var integer
|
|
||||||
*/
|
|
||||||
private $mask = 0x1F; // == (1 << shift) == 0b00011111
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Continuation bit
|
|
||||||
*
|
|
||||||
* @var integer
|
|
||||||
*/
|
|
||||||
private $continuationBit = 0x20; // == (mask - 1 ) == 0b00100000
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Char to integer map
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
private $charToIntMap = [
|
|
||||||
'A' => 0, 'B' => 1, 'C' => 2, 'D' => 3, 'E' => 4, 'F' => 5, 'G' => 6, 'H' => 7,
|
|
||||||
'I' => 8, 'J' => 9, 'K' => 10, 'L' => 11, 'M' => 12, 'N' => 13, 'O' => 14, 'P' => 15,
|
|
||||||
'Q' => 16, 'R' => 17, 'S' => 18, 'T' => 19, 'U' => 20, 'V' => 21, 'W' => 22, 'X' => 23,
|
|
||||||
'Y' => 24, 'Z' => 25, 'a' => 26, 'b' => 27, 'c' => 28, 'd' => 29, 'e' => 30, 'f' => 31,
|
|
||||||
'g' => 32, 'h' => 33, 'i' => 34, 'j' => 35, 'k' => 36, 'l' => 37, 'm' => 38, 'n' => 39,
|
|
||||||
'o' => 40, 'p' => 41, 'q' => 42, 'r' => 43, 's' => 44, 't' => 45, 'u' => 46, 'v' => 47,
|
|
||||||
'w' => 48, 'x' => 49, 'y' => 50, 'z' => 51, 0 => 52, 1 => 53, 2 => 54, 3 => 55,
|
|
||||||
4 => 56, 5 => 57, 6 => 58, 7 => 59, 8 => 60, 9 => 61, '+' => 62, '/' => 63,
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Integer to char map
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
private $intToCharMap = [
|
|
||||||
0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D', 4 => 'E', 5 => 'F', 6 => 'G', 7 => 'H',
|
|
||||||
8 => 'I', 9 => 'J', 10 => 'K', 11 => 'L', 12 => 'M', 13 => 'N', 14 => 'O', 15 => 'P',
|
|
||||||
16 => 'Q', 17 => 'R', 18 => 'S', 19 => 'T', 20 => 'U', 21 => 'V', 22 => 'W', 23 => 'X',
|
|
||||||
24 => 'Y', 25 => 'Z', 26 => 'a', 27 => 'b', 28 => 'c', 29 => 'd', 30 => 'e', 31 => 'f',
|
|
||||||
32 => 'g', 33 => 'h', 34 => 'i', 35 => 'j', 36 => 'k', 37 => 'l', 38 => 'm', 39 => 'n',
|
|
||||||
40 => 'o', 41 => 'p', 42 => 'q', 43 => 'r', 44 => 's', 45 => 't', 46 => 'u', 47 => 'v',
|
|
||||||
48 => 'w', 49 => 'x', 50 => 'y', 51 => 'z', 52 => '0', 53 => '1', 54 => '2', 55 => '3',
|
|
||||||
56 => '4', 57 => '5', 58 => '6', 59 => '7', 60 => '8', 61 => '9', 62 => '+', 63 => '/',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
// I leave it here for future reference
|
|
||||||
// foreach (str_split('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/') as $i => $char)
|
|
||||||
// {
|
|
||||||
// $this->charToIntMap[$char] = $i;
|
|
||||||
// $this->intToCharMap[$i] = $char;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert from a two-complement value to a value where the sign bit is
|
|
||||||
* is placed in the least significant bit. For example, as decimals:
|
|
||||||
* 1 becomes 2 (10 binary), -1 becomes 3 (11 binary)
|
|
||||||
* 2 becomes 4 (100 binary), -2 becomes 5 (101 binary)
|
|
||||||
* We generate the value for 32 bit machines, hence -2147483648 becomes 1, not 4294967297,
|
|
||||||
* even on a 64 bit machine.
|
|
||||||
*
|
|
||||||
* @param string $aValue
|
|
||||||
*/
|
|
||||||
public function toVLQSigned($aValue)
|
|
||||||
{
|
|
||||||
return 0xffffffff & ($aValue < 0 ? ((-$aValue) << 1) + 1 : ($aValue << 1) + 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert to a two-complement value from a value where the sign bit is
|
|
||||||
* is placed in the least significant bit. For example, as decimals:
|
|
||||||
* 2 (10 binary) becomes 1, 3 (11 binary) becomes -1
|
|
||||||
* 4 (100 binary) becomes 2, 5 (101 binary) becomes -2
|
|
||||||
* We assume that the value was generated with a 32 bit machine in mind.
|
|
||||||
* Hence
|
|
||||||
* 1 becomes -2147483648
|
|
||||||
* even on a 64 bit machine.
|
|
||||||
*
|
|
||||||
* @param integer $aValue
|
|
||||||
*/
|
|
||||||
public function fromVLQSigned($aValue)
|
|
||||||
{
|
|
||||||
return $aValue & 1 ? $this->zeroFill(~$aValue + 2, 1) | (-1 - 0x7fffffff) : $this->zeroFill($aValue, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the base 64 VLQ encoded value.
|
|
||||||
*
|
|
||||||
* @param string $aValue The value to encode
|
|
||||||
*
|
|
||||||
* @return string The encoded value
|
|
||||||
*/
|
|
||||||
public function encode($aValue)
|
|
||||||
{
|
|
||||||
$encoded = '';
|
|
||||||
$vlq = $this->toVLQSigned($aValue);
|
|
||||||
|
|
||||||
do {
|
|
||||||
$digit = $vlq & $this->mask;
|
|
||||||
$vlq = $this->zeroFill($vlq, $this->shift);
|
|
||||||
|
|
||||||
if ($vlq > 0) {
|
|
||||||
$digit |= $this->continuationBit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$encoded .= $this->base64Encode($digit);
|
|
||||||
} while ($vlq > 0);
|
|
||||||
|
|
||||||
return $encoded;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the value decoded from base 64 VLQ.
|
|
||||||
*
|
|
||||||
* @param string $encoded The encoded value to decode
|
|
||||||
*
|
|
||||||
* @return integer The decoded value
|
|
||||||
*/
|
|
||||||
public function decode($encoded)
|
|
||||||
{
|
|
||||||
$vlq = 0;
|
|
||||||
$i = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
$digit = $this->base64Decode($encoded[$i]);
|
|
||||||
$vlq |= ($digit & $this->mask) << ($i * $this->shift);
|
|
||||||
$i++;
|
|
||||||
} while ($digit & $this->continuationBit);
|
|
||||||
|
|
||||||
return $this->fromVLQSigned($vlq);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Right shift with zero fill.
|
|
||||||
*
|
|
||||||
* @param integer $a number to shift
|
|
||||||
* @param integer $b number of bits to shift
|
|
||||||
*
|
|
||||||
* @return integer
|
|
||||||
*/
|
|
||||||
public function zeroFill($a, $b)
|
|
||||||
{
|
|
||||||
return ($a >= 0) ? ($a >> $b) : ($a >> $b) & (PHP_INT_MAX >> ($b - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encode single 6-bit digit as base64.
|
|
||||||
*
|
|
||||||
* @param integer $number
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*
|
|
||||||
* @throws \Exception If the number is invalid
|
|
||||||
*/
|
|
||||||
public function base64Encode($number)
|
|
||||||
{
|
|
||||||
if ($number < 0 || $number > 63) {
|
|
||||||
throw new \Exception(sprintf('Invalid number "%s" given. Must be between 0 and 63.', $number));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->intToCharMap[$number];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decode single 6-bit digit from base64
|
|
||||||
*
|
|
||||||
* @param string $char
|
|
||||||
*
|
|
||||||
* @return integer
|
|
||||||
*
|
|
||||||
* @throws \Exception If the number is invalid
|
|
||||||
*/
|
|
||||||
public function base64Decode($char)
|
|
||||||
{
|
|
||||||
if (! array_key_exists($char, $this->charToIntMap)) {
|
|
||||||
throw new \Exception(sprintf('Invalid base 64 digit "%s" given.', $char));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->charToIntMap[$char];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -18,5 +18,5 @@ namespace ScssPhp\ScssPhp;
|
||||||
*/
|
*/
|
||||||
class Version
|
class Version
|
||||||
{
|
{
|
||||||
const VERSION = 'v1.0.2';
|
const VERSION = 'v1.0.6';
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,16 +5,11 @@ Downloaded from: https://github.com/scssphp/scssphp
|
||||||
|
|
||||||
Import procedure:
|
Import procedure:
|
||||||
|
|
||||||
- Copy all the files from the folder 'src' this directory.
|
- Delete everything from this directory except moodle_readme.txt (this file).
|
||||||
|
- Copy all the files from the folder 'src' to this directory.
|
||||||
- Copy the license file from the project root.
|
- Copy the license file from the project root.
|
||||||
- Review the local changes defined below, if any. Reapply
|
- Review the local changes defined below, if any. Reapply
|
||||||
them if needed. If already available upstream, please remove
|
them if needed. If already available upstream, please remove
|
||||||
them from the list.
|
them from the list.
|
||||||
|
|
||||||
Licensed under MIT, Copyright (c) 2015 Leaf Corcoran.
|
Licensed under MIT, Copyright (c) 2015 Leaf Corcoran.
|
||||||
|
|
||||||
Currenly using 1.0.2 plus these local changes:
|
|
||||||
|
|
||||||
- MDL-67114 : Added basic compatibility with php 7.4. This corresponds to
|
|
||||||
upstream commit https://github.com/scssphp/scssphp/commit/66675c1553b7e9d7c480d8aaedbf7c72374647cf
|
|
||||||
that is available in scssphp >= 1.0.4
|
|
||||||
|
|
|
@ -222,7 +222,7 @@
|
||||||
<location>scssphp</location>
|
<location>scssphp</location>
|
||||||
<name>scssphp</name>
|
<name>scssphp</name>
|
||||||
<license>MIT</license>
|
<license>MIT</license>
|
||||||
<version>1.0.2</version>
|
<version>1.0.6</version>
|
||||||
</library>
|
</library>
|
||||||
<library>
|
<library>
|
||||||
<location>spout</location>
|
<location>spout</location>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue