Merge branch 'MDL-67379-master' of git://github.com/rezaies/moodle

This commit is contained in:
Sara Arjona 2020-01-15 22:12:15 +01:00
commit 6e2c4af47d
13 changed files with 1412 additions and 717 deletions

View file

@ -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);
}
}

View file

@ -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

View file

@ -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 {
continue;
}
if ($child->type === Type::T_MEDIA || $child->type === Type::T_DIRECTIVE) {
$child->children = [];
$child->selectors = null;
}
}
}
}
return $isEmpty;
}
@ -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,

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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 ||

View file

@ -219,7 +219,7 @@ class Parser
* @api
*
* @param string $buffer
* @param string $out
* @param string|array $out
*
* @return boolean
*/
@ -246,7 +246,7 @@ class Parser
* @api
*
* @param string $buffer
* @param string $out
* @param string|array $out
*
* @return boolean
*/
@ -273,9 +273,9 @@ class Parser
* @api
*
* @param string $buffer
* @param string $out
* @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,6 +342,9 @@ 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);
@ -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);
@ -536,6 +547,12 @@ class Parser
if ($this->literal('@if', 3) && $this->valueList($cond) && $this->matchChar('{', false)) {
$if = $this->pushSpecialBlock(Type::T_IF, $s);
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 = [];
@ -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,7 +657,8 @@ 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->value = $supportQuery;
@ -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,6 +1093,7 @@ 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
@ -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,9 +1158,22 @@ class Parser
protected function appendComment($comment)
{
if (! $this->discardComments) {
if ($comment[0] === Type::T_COMMENT && is_string($comment[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;
}
/**
@ -1468,12 +1539,14 @@ class Parser
$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, ']' ]];
}
$this->discardComments = $discard;
return true;
}
$this->seek($s);
}
if ($this->value($lhs)) {
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 (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,57 +2154,18 @@ class Parser
*/
protected function color(&$out)
{
$color = [Type::T_COLOR];
$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 ($hasAlpha) {
if ($color[4] === 255) {
$color[4] = 1; // fully opaque
} else {
$color[4] = round($color[4] / 255, 3);
}
}
$out = $color;
if (in_array(strlen($m[2]), [3,4,6,8])) {
$out = [Type::T_KEYWORD, $m[0]];
return true;
}
$this->seek($s);
return false;
}
return false;
}
@ -2322,7 +2397,7 @@ class Parser
/**
* Parser interpolation
*
* @param array $out
* @param string|array $out
* @param boolean $lookWhite save information about whitespace before and after
*
* @return boolean
@ -2429,6 +2504,7 @@ class Parser
* Parse comma separated selector list
*
* @param array $out
* @param boolean $subSelector
*
* @return boolean
*/
@ -2464,6 +2540,7 @@ class Parser
* Parse whitespace separated selector list
*
* @param array $out
* @param boolean $subSelector
*
* @return boolean
*/
@ -2472,10 +2549,18 @@ class Parser
$selector = [];
for (;;) {
$s = $this->count;
if ($this->match('[>+~]+', $m, true)) {
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)) {
$selector[] = $part;
@ -2508,6 +2593,7 @@ class Parser
* }}
*
* @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;
}
@ -2847,11 +2950,8 @@ class Parser
array_pop($token[2]);
$node = end($token[2]);
$token = $this->flattenList($token);
$flags[] = $lastNode[1];
$lastNode = $node;
}
}
@ -2869,7 +2969,6 @@ class Parser
protected function stripOptionalFlag(&$selectors)
{
$optional = false;
$selector = end($selectors);
$part = end($selector);
@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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];
}
}

View file

@ -18,5 +18,5 @@ namespace ScssPhp\ScssPhp;
*/
class Version
{
const VERSION = 'v1.0.2';
const VERSION = 'v1.0.6';
}

View file

@ -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

View file

@ -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>