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)
|
||||
{
|
||||
// check $cacheDir
|
||||
if (isset($options['cache_dir'])) {
|
||||
self::$cacheDir = $options['cache_dir'];
|
||||
if (isset($options['cacheDir'])) {
|
||||
self::$cacheDir = $options['cacheDir'];
|
||||
}
|
||||
|
||||
if (empty(self::$cacheDir)) {
|
||||
throw new Exception('cache_dir not set');
|
||||
throw new Exception('cacheDir not set');
|
||||
}
|
||||
|
||||
if (isset($options['prefix'])) {
|
||||
|
@ -74,7 +74,7 @@ class Cache
|
|||
}
|
||||
|
||||
if (isset($options['forceRefresh'])) {
|
||||
self::$forceRefresh = $options['force_refresh'];
|
||||
self::$forceRefresh = $options['forceRefresh'];
|
||||
}
|
||||
|
||||
self::checkCacheDir();
|
||||
|
@ -97,7 +97,7 @@ class Cache
|
|||
{
|
||||
$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)
|
||||
) {
|
||||
$cacheTime = filemtime($fileCache);
|
||||
|
@ -176,13 +176,13 @@ class Cache
|
|||
self::$cacheDir = str_replace('\\', '/', self::$cacheDir);
|
||||
self::$cacheDir = rtrim(self::$cacheDir, '/') . '/';
|
||||
|
||||
if (! file_exists(self::$cacheDir)) {
|
||||
if (! is_dir(self::$cacheDir)) {
|
||||
if (! mkdir(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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ class Colors
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $cssColors = [
|
||||
protected static $cssColors = [
|
||||
'aliceblue' => '240,248,255',
|
||||
'antiquewhite' => '250,235,215',
|
||||
'aqua' => '0,255,255',
|
||||
|
@ -176,4 +176,71 @@ class Colors
|
|||
'yellow' => '255,255,0',
|
||||
'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;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $strippedSemicolon;
|
||||
|
||||
/**
|
||||
* Initialize formatter
|
||||
*
|
||||
|
@ -113,24 +118,6 @@ abstract class Formatter
|
|||
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
|
||||
*
|
||||
|
@ -207,6 +194,10 @@ abstract class Formatter
|
|||
if (! empty($block->selectors)) {
|
||||
$this->indentLevel--;
|
||||
|
||||
if (! $this->keepSemicolons) {
|
||||
$this->strippedSemicolon = '';
|
||||
}
|
||||
|
||||
if (empty($block->children)) {
|
||||
$this->write($this->break);
|
||||
}
|
||||
|
@ -217,8 +208,10 @@ abstract class Formatter
|
|||
|
||||
/**
|
||||
* Test and clean safely empty children
|
||||
*
|
||||
* @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block
|
||||
* @return bool
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
protected function testEmptyChildren($block)
|
||||
{
|
||||
|
@ -228,14 +221,16 @@ abstract class Formatter
|
|||
foreach ($block->children as $k => &$child) {
|
||||
if (! $this->testEmptyChildren($child)) {
|
||||
$isEmpty = false;
|
||||
} else {
|
||||
if ($child->type === Type::T_MEDIA || $child->type === Type::T_DIRECTIVE) {
|
||||
$child->children = [];
|
||||
$child->selectors = null;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($child->type === Type::T_MEDIA || $child->type === Type::T_DIRECTIVE) {
|
||||
$child->children = [];
|
||||
$child->selectors = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $isEmpty;
|
||||
}
|
||||
|
||||
|
@ -254,8 +249,8 @@ abstract class Formatter
|
|||
$this->sourceMapGenerator = null;
|
||||
|
||||
if ($sourceMapGenerator) {
|
||||
$this->currentLine = 1;
|
||||
$this->currentColumn = 0;
|
||||
$this->currentLine = 1;
|
||||
$this->currentColumn = 0;
|
||||
$this->sourceMapGenerator = $sourceMapGenerator;
|
||||
}
|
||||
|
||||
|
@ -271,10 +266,32 @@ abstract class Formatter
|
|||
}
|
||||
|
||||
/**
|
||||
* Output content
|
||||
*
|
||||
* @param string $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) {
|
||||
$this->sourceMapGenerator->addMapping(
|
||||
$this->currentLine,
|
||||
|
|
|
@ -55,7 +55,7 @@ class Expanded extends Formatter
|
|||
|
||||
foreach ($block->lines as $index => $line) {
|
||||
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) {
|
||||
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));
|
||||
}
|
||||
|
||||
protected function hasFlatChild($block)
|
||||
{
|
||||
foreach ($block->children as $child) {
|
||||
if (empty($child->selectors)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -109,7 +98,7 @@ class Nested extends Formatter
|
|||
array_pop($depths);
|
||||
$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)
|
||||
) {
|
||||
$downLevel = $this->break;
|
||||
|
@ -170,15 +159,18 @@ class Nested extends Formatter
|
|||
}
|
||||
|
||||
$this->blockLines($block);
|
||||
|
||||
$closeBlock = $this->break;
|
||||
}
|
||||
|
||||
if (! empty($block->children)) {
|
||||
if ($this->depth>0 && ($isMediaOrDirective || ! $this->hasFlatChild($block))) {
|
||||
if ($this->depth > 0 && ($isMediaOrDirective || ! $this->hasFlatChild($block))) {
|
||||
array_pop($depths);
|
||||
|
||||
$this->depth--;
|
||||
$this->blockChildren($block);
|
||||
$this->depth++;
|
||||
|
||||
$depths[] = $block->depth;
|
||||
} else {
|
||||
$this->blockChildren($block);
|
||||
|
@ -193,13 +185,19 @@ class Nested extends Formatter
|
|||
if (! empty($block->selectors)) {
|
||||
$this->indentLevel--;
|
||||
|
||||
if (! $this->keepSemicolons) {
|
||||
$this->strippedSemicolon = '';
|
||||
}
|
||||
|
||||
$this->write($this->close);
|
||||
|
||||
$closeBlock = $this->break;
|
||||
|
||||
if ($this->depth > 1 && ! empty($block->children)) {
|
||||
array_pop($depths);
|
||||
$this->depth--;
|
||||
}
|
||||
|
||||
if (! $isMediaOrDirective) {
|
||||
$previousHasSelector = true;
|
||||
}
|
||||
|
@ -209,4 +207,22 @@ class Nested extends Formatter
|
|||
$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)
|
||||
{
|
||||
if ($offset === -3) {
|
||||
return $this->sourceColumn !== null;
|
||||
return ! is_null($this->sourceColumn);
|
||||
}
|
||||
|
||||
if ($offset === -2) {
|
||||
return $this->sourceLine !== null;
|
||||
return ! is_null($this->sourceLine);
|
||||
}
|
||||
|
||||
if ($offset === -1 ||
|
||||
|
|
|
@ -218,8 +218,8 @@ class Parser
|
|||
*
|
||||
* @api
|
||||
*
|
||||
* @param string $buffer
|
||||
* @param string $out
|
||||
* @param string $buffer
|
||||
* @param string|array $out
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
|
@ -245,8 +245,8 @@ class Parser
|
|||
*
|
||||
* @api
|
||||
*
|
||||
* @param string $buffer
|
||||
* @param string $out
|
||||
* @param string $buffer
|
||||
* @param string|array $out
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
|
@ -272,10 +272,10 @@ class Parser
|
|||
*
|
||||
* @api
|
||||
*
|
||||
* @param string $buffer
|
||||
* @param string $out
|
||||
* @param string $buffer
|
||||
* @param string|array $out
|
||||
*
|
||||
* @return array
|
||||
* @return boolean
|
||||
*/
|
||||
public function parseMediaQueryList($buffer, &$out)
|
||||
{
|
||||
|
@ -287,7 +287,6 @@ class Parser
|
|||
|
||||
$this->saveEncoding();
|
||||
|
||||
|
||||
$isMediaQuery = $this->mediaQueryList($out);
|
||||
|
||||
$this->restoreEncoding();
|
||||
|
@ -343,11 +342,14 @@ class Parser
|
|||
if ($this->literal('@at-root', 8) &&
|
||||
($this->selectors($selector) || true) &&
|
||||
($this->map($with) || true) &&
|
||||
(($this->matchChar('(')
|
||||
&& $this->interpolation($with)
|
||||
&& $this->matchChar(')')) || true) &&
|
||||
$this->matchChar('{', false)
|
||||
) {
|
||||
$atRoot = $this->pushSpecialBlock(Type::T_AT_ROOT, $s);
|
||||
$atRoot->selector = $selector;
|
||||
$atRoot->with = $with;
|
||||
$atRoot->with = $with;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -383,9 +385,18 @@ class Parser
|
|||
($this->argValues($argValues) || true) &&
|
||||
$this->matchChar(')') || true) &&
|
||||
($this->end() ||
|
||||
($this->literal('using', 5) &&
|
||||
$this->argumentDef($argUsing) &&
|
||||
($this->end() || $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)) {
|
||||
$include = $this->pushSpecialBlock(Type::T_INCLUDE, $s);
|
||||
|
@ -524,9 +535,9 @@ class Parser
|
|||
$this->matchChar('{', false)
|
||||
) {
|
||||
$for = $this->pushSpecialBlock(Type::T_FOR, $s);
|
||||
$for->var = $varName[1];
|
||||
$for->var = $varName[1];
|
||||
$for->start = $start;
|
||||
$for->end = $end;
|
||||
$for->end = $end;
|
||||
$for->until = isset($forUntil);
|
||||
|
||||
return true;
|
||||
|
@ -536,7 +547,13 @@ class Parser
|
|||
|
||||
if ($this->literal('@if', 3) && $this->valueList($cond) && $this->matchChar('{', false)) {
|
||||
$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 = [];
|
||||
|
||||
return true;
|
||||
|
@ -577,8 +594,15 @@ class Parser
|
|||
|
||||
$this->seek($s);
|
||||
|
||||
if ($this->literal('@content', 8) && $this->end()) {
|
||||
$this->append([Type::T_MIXIN_CONTENT], $s);
|
||||
#if ($this->literal('@content', 8))
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -633,9 +657,10 @@ class Parser
|
|||
|
||||
if ($this->literal('@supports', 9) &&
|
||||
($t1=$this->supportsQuery($supportQuery)) &&
|
||||
($t2=$this->matchChar('{', false)) ) {
|
||||
($t2=$this->matchChar('{', false))
|
||||
) {
|
||||
$directive = $this->pushSpecialBlock(Type::T_DIRECTIVE, $s);
|
||||
$directive->name = 'supports';
|
||||
$directive->name = 'supports';
|
||||
$directive->value = $supportQuery;
|
||||
|
||||
return true;
|
||||
|
@ -665,6 +690,19 @@ class Parser
|
|||
|
||||
$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;
|
||||
}
|
||||
|
||||
|
@ -709,7 +747,7 @@ class Parser
|
|||
|
||||
if ($this->eatWhiteDefault) {
|
||||
$this->whitespace();
|
||||
$this->append(null); // collect comments at the begining if needed
|
||||
$this->append(null); // collect comments at the beginning if needed
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -751,7 +789,7 @@ class Parser
|
|||
if ($this->matchChar('}', false)) {
|
||||
$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) {
|
||||
$this->append(null); // collect comments before next statement if needed
|
||||
}
|
||||
|
@ -823,7 +861,7 @@ class Parser
|
|||
|
||||
$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) {
|
||||
$this->whitespace();
|
||||
|
||||
|
@ -1055,16 +1093,17 @@ class Parser
|
|||
if (isset($m[1]) && empty($this->commentsSeen[$this->count])) {
|
||||
// comment that are kept in the output CSS
|
||||
$comment = [];
|
||||
$startCommentCount = $this->count;
|
||||
$endCommentCount = $this->count + strlen($m[1]);
|
||||
|
||||
// find interpolations in comment
|
||||
$p = strpos($this->buffer, '#{', $this->count);
|
||||
|
||||
while ($p !== false && $p < $endCommentCount) {
|
||||
$c = substr($this->buffer, $this->count, $p - $this->count);
|
||||
$comment[] = $c;
|
||||
$c = substr($this->buffer, $this->count, $p - $this->count);
|
||||
$comment[] = $c;
|
||||
$this->count = $p;
|
||||
$out = null;
|
||||
$out = null;
|
||||
|
||||
if ($this->interpolation($out)) {
|
||||
// keep right spaces in the following string part
|
||||
|
@ -1076,7 +1115,7 @@ class Parser
|
|||
$out[3] = '';
|
||||
}
|
||||
|
||||
$comment[] = $out;
|
||||
$comment[] = [Type::T_COMMENT, substr($this->buffer, $p, $this->count - $p), $out];
|
||||
} else {
|
||||
$comment[] = substr($this->buffer, $this->count, 2);
|
||||
|
||||
|
@ -1094,10 +1133,11 @@ class Parser
|
|||
$this->appendComment([Type::T_COMMENT, $c]);
|
||||
} else {
|
||||
$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;
|
||||
} else {
|
||||
// comment that are ignored and not kept in the output css
|
||||
|
@ -1118,8 +1158,21 @@ class Parser
|
|||
protected function appendComment($comment)
|
||||
{
|
||||
if (! $this->discardComments) {
|
||||
if ($comment[0] === Type::T_COMMENT && is_string($comment[1])) {
|
||||
$comment[1] = substr(preg_replace(['/^\s+/m', '/^(.)/m'], ['', ' \1'], $comment[1]), 1);
|
||||
if ($comment[0] === Type::T_COMMENT) {
|
||||
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;
|
||||
|
@ -1135,7 +1188,7 @@ class Parser
|
|||
protected function append($statement, $pos = null)
|
||||
{
|
||||
if (! is_null($statement)) {
|
||||
if ($pos !== null) {
|
||||
if (! is_null($pos)) {
|
||||
list($line, $column) = $this->getSourcePosition($pos);
|
||||
|
||||
$statement[static::SOURCE_LINE] = $line;
|
||||
|
@ -1247,12 +1300,14 @@ class Parser
|
|||
$s = $this->count;
|
||||
|
||||
$not = false;
|
||||
|
||||
if (($this->literal('not', 3) && ($not = true) || true) &&
|
||||
$this->matchChar('(') &&
|
||||
($this->expression($property)) &&
|
||||
$this->literal(': ', 2) &&
|
||||
$this->valueList($value) &&
|
||||
$this->matchChar(')')) {
|
||||
$this->matchChar(')')
|
||||
) {
|
||||
$support = [Type::T_STRING, '', [[Type::T_KEYWORD, ($not ? 'not ' : '') . '(']]];
|
||||
$support[2][] = $property;
|
||||
$support[2][] = [Type::T_KEYWORD, ': '];
|
||||
|
@ -1267,7 +1322,8 @@ class Parser
|
|||
|
||||
if ($this->matchChar('(') &&
|
||||
$this->supportsQuery($subQuery) &&
|
||||
$this->matchChar(')')) {
|
||||
$this->matchChar(')')
|
||||
) {
|
||||
$parts[] = [Type::T_STRING, '', [[Type::T_KEYWORD, '('], $subQuery, [Type::T_KEYWORD, ')']]];
|
||||
$s = $this->count;
|
||||
} else {
|
||||
|
@ -1275,7 +1331,8 @@ class Parser
|
|||
}
|
||||
|
||||
if ($this->literal('not', 3) &&
|
||||
$this->supportsQuery($subQuery)) {
|
||||
$this->supportsQuery($subQuery)
|
||||
) {
|
||||
$parts[] = [Type::T_STRING, '', [[Type::T_KEYWORD, 'not '], $subQuery]];
|
||||
$s = $this->count;
|
||||
} else {
|
||||
|
@ -1284,12 +1341,15 @@ class Parser
|
|||
|
||||
if ($this->literal('selector(', 9) &&
|
||||
$this->selector($selector) &&
|
||||
$this->matchChar(')')) {
|
||||
$this->matchChar(')')
|
||||
) {
|
||||
$support = [Type::T_STRING, '', [[Type::T_KEYWORD, 'selector(']]];
|
||||
|
||||
$selectorList = [Type::T_LIST, '', []];
|
||||
|
||||
foreach ($selector as $sc) {
|
||||
$compound = [Type::T_STRING, '', []];
|
||||
|
||||
foreach ($sc as $scp) {
|
||||
if (is_array($scp)) {
|
||||
$compound[2][] = $scp;
|
||||
|
@ -1297,6 +1357,7 @@ class Parser
|
|||
$compound[2][] = [Type::T_KEYWORD, $scp];
|
||||
}
|
||||
}
|
||||
|
||||
$selectorList[2][] = $compound;
|
||||
}
|
||||
$support[2][] = $selectorList;
|
||||
|
@ -1317,6 +1378,7 @@ class Parser
|
|||
if ($this->literal('and', 3) &&
|
||||
$this->genericList($expressions, 'supportsQuery', ' and', false)) {
|
||||
array_unshift($expressions[2], [Type::T_STRING, '', $parts]);
|
||||
|
||||
$parts = [$expressions];
|
||||
$s = $this->count;
|
||||
} else {
|
||||
|
@ -1326,6 +1388,7 @@ class Parser
|
|||
if ($this->literal('or', 2) &&
|
||||
$this->genericList($expressions, 'supportsQuery', ' or', false)) {
|
||||
array_unshift($expressions[2], [Type::T_STRING, '', $parts]);
|
||||
|
||||
$parts = [$expressions];
|
||||
$s = $this->count;
|
||||
} else {
|
||||
|
@ -1336,7 +1399,9 @@ class Parser
|
|||
if ($this->eatWhiteDefault) {
|
||||
$this->whitespace();
|
||||
}
|
||||
|
||||
$out = [Type::T_STRING, '', $parts];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1408,6 +1473,7 @@ class Parser
|
|||
|
||||
if (! $this->variable($keyword) || ! $this->matchChar(':')) {
|
||||
$this->seek($s);
|
||||
|
||||
$keyword = null;
|
||||
}
|
||||
|
||||
|
@ -1436,7 +1502,12 @@ class Parser
|
|||
*/
|
||||
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)
|
||||
{
|
||||
$s = $this->count;
|
||||
$s = $this->count;
|
||||
$items = [];
|
||||
$value = null;
|
||||
|
||||
while ($this->$parseItem($value)) {
|
||||
$trailing_delim = false;
|
||||
$items[] = $value;
|
||||
|
||||
if ($delim) {
|
||||
if (! $this->literal($delim, strlen($delim))) {
|
||||
break;
|
||||
}
|
||||
$trailing_delim = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1483,6 +1556,9 @@ class Parser
|
|||
return false;
|
||||
}
|
||||
|
||||
if ($trailing_delim) {
|
||||
$items[] = [Type::T_NULL];
|
||||
}
|
||||
if ($flatten && count($items) === 1) {
|
||||
$out = $items[0];
|
||||
} else {
|
||||
|
@ -1496,41 +1572,58 @@ class Parser
|
|||
* Parse expression
|
||||
*
|
||||
* @param array $out
|
||||
* @param bool $listOnly
|
||||
* @param bool $lookForExp
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
protected function expression(&$out)
|
||||
protected function expression(&$out, $listOnly = false, $lookForExp = true)
|
||||
{
|
||||
$s = $this->count;
|
||||
$discard = $this->discardComments;
|
||||
$this->discardComments = true;
|
||||
$allowedTypes = ($listOnly ? [Type::T_LIST] : [Type::T_LIST, Type::T_MAP]);
|
||||
|
||||
if ($this->matchChar('(')) {
|
||||
if ($this->parenExpression($out, $s, ")")) {
|
||||
$this->discardComments = $discard;
|
||||
return true;
|
||||
}
|
||||
|
||||
$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, ']' ]];
|
||||
if ($this->enclosedExpression($lhs, $s, ")", $allowedTypes)) {
|
||||
if ($lookForExp) {
|
||||
$out = $this->expHelper($lhs, 0);
|
||||
} else {
|
||||
$out = $lhs;
|
||||
}
|
||||
|
||||
$this->discardComments = $discard;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->seek($s);
|
||||
}
|
||||
|
||||
if ($this->value($lhs)) {
|
||||
$out = $this->expHelper($lhs, 0);
|
||||
if (in_array(Type::T_LIST, $allowedTypes) && $this->matchChar('[')) {
|
||||
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;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1548,15 +1641,35 @@ class Parser
|
|||
*
|
||||
* @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, '', []];
|
||||
|
||||
switch ($closingParen) {
|
||||
case ")":
|
||||
$out['enclosing'] = 'parent'; // parenthesis list
|
||||
break;
|
||||
case "]":
|
||||
$out['enclosing'] = 'bracket'; // bracketed list
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1600,7 +1713,7 @@ class Parser
|
|||
break;
|
||||
}
|
||||
|
||||
if (! $this->value($rhs)) {
|
||||
if (! $this->value($rhs) && ! $this->expression($rhs, true, false)) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1655,7 +1768,7 @@ class Parser
|
|||
|
||||
$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];
|
||||
|
||||
if ($this->matchChar(')')) {
|
||||
|
@ -1751,6 +1864,7 @@ class Parser
|
|||
// unicode range with wildcards
|
||||
if ($this->literal('U+', 2) && $this->match('([0-9A-F]+\?*)(-([0-9A-F]+))?', $m, false)) {
|
||||
$out = [Type::T_KEYWORD, 'U+' . $m[0]];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2040,55 +2154,16 @@ class Parser
|
|||
*/
|
||||
protected function color(&$out)
|
||||
{
|
||||
$color = [Type::T_COLOR];
|
||||
$s = $this->count;
|
||||
$s = $this->count;
|
||||
|
||||
if ($this->match('(#([0-9a-f]+))', $m)) {
|
||||
$nofValues = strlen($m[2]);
|
||||
$hasAlpha = $nofValues === 4 || $nofValues === 8;
|
||||
$channels = $hasAlpha ? [4, 3, 2, 1] : [3, 2, 1];
|
||||
|
||||
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 (in_array(strlen($m[2]), [3,4,6,8])) {
|
||||
$out = [Type::T_KEYWORD, $m[0]];
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($hasAlpha) {
|
||||
if ($color[4] === 255) {
|
||||
$color[4] = 1; // fully opaque
|
||||
} else {
|
||||
$color[4] = round($color[4] / 255, 3);
|
||||
}
|
||||
}
|
||||
|
||||
$out = $color;
|
||||
|
||||
return true;
|
||||
$this->seek($s);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -2322,8 +2397,8 @@ class Parser
|
|||
/**
|
||||
* Parser interpolation
|
||||
*
|
||||
* @param array $out
|
||||
* @param boolean $lookWhite save information about whitespace before and after
|
||||
* @param string|array $out
|
||||
* @param boolean $lookWhite save information about whitespace before and after
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
|
@ -2428,7 +2503,8 @@ class Parser
|
|||
/**
|
||||
* Parse comma separated selector list
|
||||
*
|
||||
* @param array $out
|
||||
* @param array $out
|
||||
* @param boolean $subSelector
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
|
@ -2463,7 +2539,8 @@ class Parser
|
|||
/**
|
||||
* Parse whitespace separated selector list
|
||||
*
|
||||
* @param array $out
|
||||
* @param array $out
|
||||
* @param boolean $subSelector
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
|
@ -2472,9 +2549,17 @@ class Parser
|
|||
$selector = [];
|
||||
|
||||
for (;;) {
|
||||
$s = $this->count;
|
||||
|
||||
if ($this->match('[>+~]+', $m, true)) {
|
||||
$selector[] = [$m[0]];
|
||||
continue;
|
||||
if ($subSelector && is_string($subSelector) && strpos($subSelector, 'nth-') === 0 &&
|
||||
$m[0] === '+' && $this->match("(\d+|n\b)", $counter)
|
||||
) {
|
||||
$this->seek($s);
|
||||
} else {
|
||||
$selector[] = [$m[0]];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->selectorSingle($part, $subSelector)) {
|
||||
|
@ -2507,7 +2592,8 @@ class Parser
|
|||
* div[yes=no]#something.hello.world:nth-child(-2n+1)%placeholder
|
||||
* }}
|
||||
*
|
||||
* @param array $out
|
||||
* @param array $out
|
||||
* @param boolean $subSelector
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
|
@ -2606,10 +2692,13 @@ class Parser
|
|||
$ss = $this->count;
|
||||
|
||||
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('(') &&
|
||||
($this->selectors($subs, true) || true) &&
|
||||
if ($this->matchChar('(', true) &&
|
||||
($this->selectors($subs, reset($nameParts)) || true) &&
|
||||
$this->matchChar(')')
|
||||
) {
|
||||
$parts[] = '(';
|
||||
|
@ -2619,10 +2708,12 @@ class Parser
|
|||
foreach ($ps as &$p) {
|
||||
$parts[] = $p;
|
||||
}
|
||||
|
||||
if (count($sub) && reset($sub)) {
|
||||
$parts[] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
if (count($subs) && reset($subs)) {
|
||||
$parts[] = ', ';
|
||||
}
|
||||
|
@ -2655,6 +2746,17 @@ class Parser
|
|||
|
||||
$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
|
||||
if ($char === '[' &&
|
||||
$this->matchChar('[') &&
|
||||
|
@ -2769,7 +2871,7 @@ class Parser
|
|||
/**
|
||||
* Parse a placeholder
|
||||
*
|
||||
* @param string $placeholder
|
||||
* @param string|array $placeholder
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
|
@ -2785,6 +2887,7 @@ class Parser
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->interpolation($placeholder)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -2846,12 +2949,9 @@ class Parser
|
|||
while ($lastNode[0] === Type::T_KEYWORD && in_array($lastNode[1], ['!default', '!global'])) {
|
||||
array_pop($token[2]);
|
||||
|
||||
$node = end($token[2]);
|
||||
|
||||
$token = $this->flattenList($token);
|
||||
|
||||
$flags[] = $lastNode[1];
|
||||
|
||||
$node = end($token[2]);
|
||||
$token = $this->flattenList($token);
|
||||
$flags[] = $lastNode[1];
|
||||
$lastNode = $node;
|
||||
}
|
||||
}
|
||||
|
@ -2869,9 +2969,8 @@ class Parser
|
|||
protected function stripOptionalFlag(&$selectors)
|
||||
{
|
||||
$optional = false;
|
||||
|
||||
$selector = end($selectors);
|
||||
$part = end($selector);
|
||||
$part = end($selector);
|
||||
|
||||
if ($part === ['!optional']) {
|
||||
array_pop($selectors[count($selectors) - 1]);
|
||||
|
@ -2915,6 +3014,8 @@ class Parser
|
|||
$validChars = $allowNewline ? '.' : "[^\n]";
|
||||
}
|
||||
|
||||
$m = null;
|
||||
|
||||
if (! $this->match('(' . $validChars . '*?)' . $this->pregQuote($what), $m, ! $until)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -3014,9 +3115,10 @@ class Parser
|
|||
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();
|
||||
|
||||
mb_internal_encoding('iso-8859-1');
|
||||
|
@ -3028,7 +3130,7 @@ class Parser
|
|||
*/
|
||||
private function restoreEncoding()
|
||||
{
|
||||
if ($this->encoding) {
|
||||
if (extension_loaded('mbstring') && $this->encoding) {
|
||||
mb_internal_encoding($this->encoding);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -130,8 +130,17 @@ class Base64VLQ
|
|||
private static function fromVLQSigned($value)
|
||||
{
|
||||
$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
|
||||
{
|
||||
const VERSION = 'v1.0.2';
|
||||
const VERSION = 'v1.0.6';
|
||||
}
|
||||
|
|
|
@ -5,16 +5,11 @@ Downloaded from: https://github.com/scssphp/scssphp
|
|||
|
||||
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.
|
||||
- Review the local changes defined below, if any. Reapply
|
||||
them if needed. If already available upstream, please remove
|
||||
them from the list.
|
||||
|
||||
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>
|
||||
<name>scssphp</name>
|
||||
<license>MIT</license>
|
||||
<version>1.0.2</version>
|
||||
<version>1.0.6</version>
|
||||
</library>
|
||||
<library>
|
||||
<location>spout</location>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue