mirror of
https://github.com/moodle/moodle.git
synced 2025-01-17 13:38:32 +01:00
MDL-75476 scssphp: Updated from 1.10.0 to 1.11.0
This commit is contained in:
parent
c6211a68b4
commit
5247ff3da0
@ -166,7 +166,7 @@ class Compiler
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* @phpstan-var array<string, array{0: callable, 1: array|null}>
|
||||
* @phpstan-var array<string, array{0: callable, 1: string[]|null}>
|
||||
*/
|
||||
protected $userFunctions = [];
|
||||
/**
|
||||
@ -211,9 +211,15 @@ class Compiler
|
||||
private $charset = true;
|
||||
|
||||
/**
|
||||
* @var string|\ScssPhp\ScssPhp\Formatter
|
||||
* @var Formatter
|
||||
*/
|
||||
protected $formatter = Expanded::class;
|
||||
protected $formatter;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @phpstan-var class-string<Formatter>
|
||||
*/
|
||||
private $configuredFormatter = Expanded::class;
|
||||
|
||||
/**
|
||||
* @var Environment
|
||||
@ -381,7 +387,7 @@ class Compiler
|
||||
'encoding' => $this->encoding,
|
||||
'sourceMap' => serialize($this->sourceMap),
|
||||
'sourceMapOptions' => $this->sourceMapOptions,
|
||||
'formatter' => $this->formatter,
|
||||
'formatter' => $this->configuredFormatter,
|
||||
'legacyImportPath' => $this->legacyCwdImportPath,
|
||||
];
|
||||
|
||||
@ -502,7 +508,7 @@ class Compiler
|
||||
$tree = $this->parser->parse($source);
|
||||
$this->parser = null;
|
||||
|
||||
$this->formatter = new $this->formatter();
|
||||
$this->formatter = new $this->configuredFormatter();
|
||||
$this->rootBlock = null;
|
||||
$this->rootEnv = $this->pushEnv($tree);
|
||||
|
||||
@ -529,6 +535,7 @@ class Compiler
|
||||
$sourceMapGenerator = new SourceMapGenerator($this->sourceMapOptions);
|
||||
}
|
||||
}
|
||||
assert($this->scope !== null);
|
||||
|
||||
$out = $this->formatter->format($this->scope, $sourceMapGenerator);
|
||||
|
||||
@ -542,6 +549,7 @@ class Compiler
|
||||
$sourceMap = null;
|
||||
|
||||
if (! empty($out) && $this->sourceMap && $this->sourceMap !== self::SOURCE_MAP_NONE) {
|
||||
assert($sourceMapGenerator !== null);
|
||||
$sourceMap = $sourceMapGenerator->generateJson($prefix);
|
||||
$sourceMapUrl = null;
|
||||
|
||||
@ -671,7 +679,7 @@ class Compiler
|
||||
/**
|
||||
* Push extends
|
||||
*
|
||||
* @param array $target
|
||||
* @param string[] $target
|
||||
* @param array $origin
|
||||
* @param array|null $block
|
||||
*
|
||||
@ -714,9 +722,9 @@ class Compiler
|
||||
$out->sourceLine = $this->env->block->sourceLine;
|
||||
$out->sourceColumn = $this->env->block->sourceColumn;
|
||||
} else {
|
||||
$out->sourceName = null;
|
||||
$out->sourceLine = null;
|
||||
$out->sourceColumn = null;
|
||||
$out->sourceName = isset($this->sourceNames[$this->sourceIndex]) ? $this->sourceNames[$this->sourceIndex] : '(stdin)';
|
||||
$out->sourceLine = $this->sourceLine;
|
||||
$out->sourceColumn = $this->sourceColumn;
|
||||
}
|
||||
|
||||
return $out;
|
||||
@ -734,6 +742,7 @@ class Compiler
|
||||
$this->rootBlock = $this->scope = $this->makeOutputBlock(Type::T_ROOT);
|
||||
|
||||
$this->compileChildrenNoReturn($rootBlock->children, $this->scope);
|
||||
assert($this->scope !== null);
|
||||
$this->flattenSelectors($this->scope);
|
||||
$this->missingSelectors();
|
||||
}
|
||||
@ -815,6 +824,7 @@ class Compiler
|
||||
}
|
||||
|
||||
if ($placeholderSelector && 0 === \count($block->selectors) && null !== $parentKey) {
|
||||
assert($block->parent !== null);
|
||||
unset($block->parent->children[$parentKey]);
|
||||
|
||||
return;
|
||||
@ -1287,6 +1297,7 @@ class Compiler
|
||||
$mediaQueries = $this->compileMediaQuery($this->multiplyMedia($this->env));
|
||||
|
||||
if (! empty($mediaQueries)) {
|
||||
assert($this->scope !== null);
|
||||
$previousScope = $this->scope;
|
||||
$parentScope = $this->mediaParent($this->scope);
|
||||
|
||||
@ -1452,7 +1463,7 @@ class Compiler
|
||||
|
||||
if (
|
||||
! $selfParent->selectors &&
|
||||
isset($block->parent) && $block->parent &&
|
||||
isset($block->parent) &&
|
||||
isset($block->parent->selectors) && $block->parent->selectors
|
||||
) {
|
||||
$selfParent = $block->parent;
|
||||
@ -1460,13 +1471,15 @@ class Compiler
|
||||
|
||||
$this->env = $this->filterWithWithout($envs, $with, $without);
|
||||
|
||||
assert($this->scope !== null);
|
||||
$saveScope = $this->scope;
|
||||
$this->scope = $this->filterScopeWithWithout($saveScope, $with, $without);
|
||||
|
||||
// propagate selfParent to the children where they still can be useful
|
||||
$this->compileChildrenNoReturn($block->children, $this->scope, $selfParent);
|
||||
|
||||
$this->scope = $this->completeScope($this->scope, $saveScope);
|
||||
assert($this->scope !== null);
|
||||
$this->completeScope($this->scope, $saveScope);
|
||||
$this->scope = $saveScope;
|
||||
$this->env = $this->extractEnv($envs);
|
||||
|
||||
@ -1490,6 +1503,7 @@ class Compiler
|
||||
if ($scope->type === Type::T_ROOT) {
|
||||
return $scope;
|
||||
}
|
||||
assert($this->rootBlock !== null);
|
||||
|
||||
// start from the root
|
||||
while ($scope->parent && $scope->parent->type !== Type::T_ROOT) {
|
||||
@ -1557,7 +1571,7 @@ class Compiler
|
||||
*/
|
||||
protected function completeScope($scope, $previousScope)
|
||||
{
|
||||
if (! $scope->type && (! $scope->selectors || ! \count($scope->selectors)) && \count($scope->lines)) {
|
||||
if (! $scope->type && ! $scope->selectors && \count($scope->lines)) {
|
||||
$scope->selectors = $this->findScopeSelectors($previousScope, $scope->depth);
|
||||
}
|
||||
|
||||
@ -1768,10 +1782,12 @@ class Compiler
|
||||
|
||||
$this->scope = $this->makeOutputBlock($block->type, $selectors);
|
||||
$this->scope->depth = 1;
|
||||
assert($this->scope->parent !== null);
|
||||
$this->scope->parent->children[] = $this->scope;
|
||||
|
||||
$this->compileChildrenNoReturn($block->children, $this->scope);
|
||||
|
||||
assert($this->scope !== null);
|
||||
$this->scope = $this->scope->parent;
|
||||
$this->env = $this->extractEnv($envs);
|
||||
|
||||
@ -1829,6 +1845,7 @@ class Compiler
|
||||
$this->pushEnv($block);
|
||||
|
||||
$this->scope = $this->makeOutputBlock($block->type, $selectors);
|
||||
assert($this->scope->parent !== null);
|
||||
$this->scope->parent->children[] = $this->scope;
|
||||
|
||||
// wrap assign children in a block
|
||||
@ -1862,6 +1879,7 @@ class Compiler
|
||||
|
||||
$this->compileChildrenNoReturn($block->children, $this->scope);
|
||||
|
||||
assert($this->scope !== null);
|
||||
$this->scope = $this->scope->parent;
|
||||
|
||||
$this->popEnv();
|
||||
@ -1890,10 +1908,12 @@ class Compiler
|
||||
protected function compileBlock(Block $block)
|
||||
{
|
||||
$env = $this->pushEnv($block);
|
||||
assert($block->selectors !== null);
|
||||
$env->selectors = $this->evalSelectors($block->selectors);
|
||||
|
||||
$out = $this->makeOutputBlock(null);
|
||||
|
||||
assert($this->scope !== null);
|
||||
$this->scope->children[] = $out;
|
||||
|
||||
if (\count($block->children)) {
|
||||
@ -1911,6 +1931,7 @@ class Compiler
|
||||
|
||||
// and revert for the following children of the same block
|
||||
if ($selfParentSelectors) {
|
||||
assert($block->selfParent !== null);
|
||||
$block->selfParent->selectors = $selfParentSelectors;
|
||||
}
|
||||
}
|
||||
@ -1966,6 +1987,7 @@ class Compiler
|
||||
$out = $this->makeOutputBlock(Type::T_COMMENT);
|
||||
$out->lines[] = $this->compileCommentValue($block, true);
|
||||
|
||||
assert($this->scope !== null);
|
||||
$this->scope->children[] = $out;
|
||||
}
|
||||
|
||||
@ -1980,7 +2002,11 @@ class Compiler
|
||||
{
|
||||
$this->shouldEvaluate = false;
|
||||
|
||||
$selectors = array_map([$this, 'evalSelector'], $selectors);
|
||||
$evaluatedSelectors = [];
|
||||
foreach ($selectors as $selector) {
|
||||
$evaluatedSelectors[] = $this->evalSelector($selector);
|
||||
}
|
||||
$selectors = $evaluatedSelectors;
|
||||
|
||||
// after evaluating interpolates, we might need a second pass
|
||||
if ($this->shouldEvaluate) {
|
||||
@ -2008,6 +2034,8 @@ class Compiler
|
||||
* @param array $selector
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @phpstan-impure
|
||||
*/
|
||||
protected function evalSelector($selector)
|
||||
{
|
||||
@ -2020,6 +2048,8 @@ class Compiler
|
||||
* @param array $part
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @phpstan-impure
|
||||
*/
|
||||
protected function evalSelectorPart($part)
|
||||
{
|
||||
@ -2033,8 +2063,8 @@ class Compiler
|
||||
}
|
||||
} elseif (
|
||||
\is_string($p) && \strlen($p) >= 2 &&
|
||||
($first = $p[0]) && ($first === '"' || $first === "'") &&
|
||||
substr($p, -1) === $first
|
||||
($p[0] === '"' || $p[0] === "'") &&
|
||||
substr($p, -1) === $p[0]
|
||||
) {
|
||||
$p = substr($p, 1, -1);
|
||||
}
|
||||
@ -2320,9 +2350,9 @@ class Compiler
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile children and throw exception if unexpected `@return`
|
||||
* Compile children and throw exception if unexpected at-return
|
||||
*
|
||||
* @param array $stms
|
||||
* @param array[] $stms
|
||||
* @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out
|
||||
* @param \ScssPhp\ScssPhp\Block $selfParent
|
||||
* @param string $traceName
|
||||
@ -2337,13 +2367,13 @@ class Compiler
|
||||
|
||||
foreach ($stms as $stm) {
|
||||
if ($selfParent && isset($stm[1]) && \is_object($stm[1]) && $stm[1] instanceof Block) {
|
||||
$oldSelfParent = $stm[1]->selfParent;
|
||||
$stm[1]->selfParent = $selfParent;
|
||||
$ret = $this->compileChild($stm, $out);
|
||||
$stm[1]->selfParent = null;
|
||||
$stm[1]->selfParent = $oldSelfParent;
|
||||
} elseif ($selfParent && \in_array($stm[0], [Type::T_INCLUDE, Type::T_EXTEND])) {
|
||||
$stm['selfParent'] = $selfParent;
|
||||
$ret = $this->compileChild($stm, $out);
|
||||
unset($stm['selfParent']);
|
||||
} else {
|
||||
$ret = $this->compileChild($stm, $out);
|
||||
}
|
||||
@ -2401,7 +2431,7 @@ class Compiler
|
||||
$queryString = $this->compileMediaQuery([$queryList[$kql]]);
|
||||
$queryString = reset($queryString);
|
||||
|
||||
if (strpos($queryString, '@media ') === 0) {
|
||||
if ($queryString !== false && strpos($queryString, '@media ') === 0) {
|
||||
$queryString = substr($queryString, 7);
|
||||
$queries = [];
|
||||
|
||||
@ -2857,7 +2887,7 @@ class Compiler
|
||||
$this->sourceIndex = isset($child[Parser::SOURCE_INDEX]) ? $child[Parser::SOURCE_INDEX] : null;
|
||||
$this->sourceLine = isset($child[Parser::SOURCE_LINE]) ? $child[Parser::SOURCE_LINE] : -1;
|
||||
$this->sourceColumn = isset($child[Parser::SOURCE_COLUMN]) ? $child[Parser::SOURCE_COLUMN] : -1;
|
||||
} elseif (\is_array($child) && isset($child[1]->sourceLine)) {
|
||||
} elseif (\is_array($child) && isset($child[1]->sourceLine) && $child[1] instanceof Block) {
|
||||
$this->sourceIndex = $child[1]->sourceIndex;
|
||||
$this->sourceLine = $child[1]->sourceLine;
|
||||
$this->sourceColumn = $child[1]->sourceColumn;
|
||||
@ -3093,6 +3123,7 @@ class Compiler
|
||||
if (! $selectors && isset($child['selfParent'])) {
|
||||
$selectors = $this->multiplySelectors($this->env, $child['selfParent']);
|
||||
}
|
||||
assert($selectors !== null);
|
||||
|
||||
if (\count($result) > 1) {
|
||||
$replacement = implode(', ', $result);
|
||||
@ -3255,7 +3286,7 @@ EOL;
|
||||
// and assign this fake parent to childs
|
||||
$selfParent = null;
|
||||
|
||||
if (isset($child['selfParent']) && isset($child['selfParent']->selectors)) {
|
||||
if (isset($child['selfParent']) && $child['selfParent'] instanceof Block && isset($child['selfParent']->selectors)) {
|
||||
$selfParent = $child['selfParent'];
|
||||
} else {
|
||||
$parentSelectors = $this->multiplySelectors($this->env);
|
||||
@ -3265,7 +3296,7 @@ EOL;
|
||||
$parent->selectors = $parentSelectors;
|
||||
|
||||
foreach ($mixin->children as $k => $child) {
|
||||
if (isset($child[1]) && \is_object($child[1]) && $child[1] instanceof Block) {
|
||||
if (isset($child[1]) && $child[1] instanceof Block) {
|
||||
$mixin->children[$k][1]->parent = $parent;
|
||||
}
|
||||
}
|
||||
@ -3371,6 +3402,8 @@ EOL;
|
||||
default:
|
||||
throw $this->error("unknown child type: $child[0]");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3505,32 +3538,24 @@ EOL;
|
||||
$ucLType = ucfirst($ltype);
|
||||
$ucRType = ucfirst($rtype);
|
||||
|
||||
$shouldEval = $inParens || $inExp;
|
||||
|
||||
// this tries:
|
||||
// 1. op[op name][left type][right type]
|
||||
// 2. op[left type][right type] (passing the op as first arg
|
||||
// 2. op[left type][right type] (passing the op as first arg)
|
||||
// 3. op[op name]
|
||||
$fn = "op${ucOpName}${ucLType}${ucRType}";
|
||||
if (\is_callable([$this, $fn = "op{$ucOpName}{$ucLType}{$ucRType}"])) {
|
||||
$out = $this->$fn($left, $right, $shouldEval);
|
||||
} elseif (\is_callable([$this, $fn = "op{$ucLType}{$ucRType}"])) {
|
||||
$out = $this->$fn($op, $left, $right, $shouldEval);
|
||||
} elseif (\is_callable([$this, $fn = "op{$ucOpName}"])) {
|
||||
$out = $this->$fn($left, $right, $shouldEval);
|
||||
} else {
|
||||
$out = null;
|
||||
}
|
||||
|
||||
if (
|
||||
\is_callable([$this, $fn]) ||
|
||||
(($fn = "op${ucLType}${ucRType}") &&
|
||||
\is_callable([$this, $fn]) &&
|
||||
$passOp = true) ||
|
||||
(($fn = "op${ucOpName}") &&
|
||||
\is_callable([$this, $fn]) &&
|
||||
$genOp = true)
|
||||
) {
|
||||
$shouldEval = $inParens || $inExp;
|
||||
|
||||
if (isset($passOp)) {
|
||||
$out = $this->$fn($op, $left, $right, $shouldEval);
|
||||
} else {
|
||||
$out = $this->$fn($left, $right, $shouldEval);
|
||||
}
|
||||
|
||||
if (isset($out)) {
|
||||
return $out;
|
||||
}
|
||||
if (isset($out)) {
|
||||
return $out;
|
||||
}
|
||||
|
||||
return $this->expToString($value);
|
||||
@ -3867,11 +3892,12 @@ EOL;
|
||||
|
||||
// Special functions overriding a CSS function are case-insensitive. We normalize them as lowercase
|
||||
// to avoid the deprecation warning about the wrong case being used.
|
||||
if ($lowercasedName === 'min' || $lowercasedName === 'max') {
|
||||
if ($lowercasedName === 'min' || $lowercasedName === 'max' || $lowercasedName === 'rgb' || $lowercasedName === 'rgba' || $lowercasedName === 'hsl' || $lowercasedName === 'hsla') {
|
||||
$normalizedName = $lowercasedName;
|
||||
}
|
||||
|
||||
if (($f = $this->getBuiltinFunction($normalizedName)) && \is_callable($f)) {
|
||||
/** @var string $libName */
|
||||
$libName = $f[1];
|
||||
$prototype = isset(static::$$libName) ? static::$$libName : null;
|
||||
|
||||
@ -5517,11 +5543,11 @@ EOL;
|
||||
{
|
||||
switch ($style) {
|
||||
case OutputStyle::EXPANDED:
|
||||
$this->formatter = Expanded::class;
|
||||
$this->configuredFormatter = Expanded::class;
|
||||
break;
|
||||
|
||||
case OutputStyle::COMPRESSED:
|
||||
$this->formatter = Compressed::class;
|
||||
$this->configuredFormatter = Compressed::class;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -5539,6 +5565,8 @@ EOL;
|
||||
* @return void
|
||||
*
|
||||
* @deprecated Use {@see setOutputStyle} instead.
|
||||
*
|
||||
* @phpstan-param class-string<Formatter> $formatterName
|
||||
*/
|
||||
public function setFormatter($formatterName)
|
||||
{
|
||||
@ -5547,7 +5575,7 @@ EOL;
|
||||
}
|
||||
@trigger_error('The method "setFormatter" is deprecated. Use "setOutputStyle" instead.', E_USER_DEPRECATED);
|
||||
|
||||
$this->formatter = $formatterName;
|
||||
$this->configuredFormatter = $formatterName;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -5688,6 +5716,10 @@ EOL;
|
||||
// see if tree is cached
|
||||
$realPath = realpath($path);
|
||||
|
||||
if ($realPath === false) {
|
||||
$realPath = $path;
|
||||
}
|
||||
|
||||
if (substr($path, -5) === '.sass') {
|
||||
$this->sourceIndex = \count($this->sourceNames);
|
||||
$this->sourceNames[] = $path;
|
||||
@ -6031,6 +6063,8 @@ EOL;
|
||||
*
|
||||
* @param string $msg Message with optional sprintf()-style vararg parameters
|
||||
*
|
||||
* @return never
|
||||
*
|
||||
* @throws \ScssPhp\ScssPhp\Exception\CompilerException
|
||||
*
|
||||
* @deprecated use "error" and throw the exception in the caller instead.
|
||||
@ -6050,7 +6084,8 @@ EOL;
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param string $msg Message with optional sprintf()-style vararg parameters
|
||||
* @param string $msg Message with optional sprintf()-style vararg parameters
|
||||
* @param bool|float|int|string|null ...$args
|
||||
*
|
||||
* @return CompilerException
|
||||
*/
|
||||
@ -6168,6 +6203,8 @@ EOL;
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function handleImportLoop($name)
|
||||
@ -6362,6 +6399,9 @@ EOL;
|
||||
if (\in_array($functionName, ['libRgb', 'libRgba', 'libHsl', 'libHsla'])) {
|
||||
// notation 100 127 255 / 0 is in fact a simple list of 4 values
|
||||
foreach ($args as $k => $arg) {
|
||||
if (!isset($arg[1])) {
|
||||
continue; // This happens when using a trailing comma
|
||||
}
|
||||
if ($arg[1][0] === Type::T_LIST && \count($arg[1][2]) === 3) {
|
||||
$args[$k][1][2] = $this->extractSlashAlphaInColorFunction($arg[1][2]);
|
||||
}
|
||||
@ -6794,7 +6834,7 @@ EOL;
|
||||
$prototype = ['arguments' => [], 'rest_argument' => null];
|
||||
$originalRestArgumentName = null;
|
||||
|
||||
foreach ($argDef as $i => $arg) {
|
||||
foreach ($argDef as $arg) {
|
||||
list($name, $default, $isVariable) = $arg;
|
||||
$normalizedName = str_replace('_', '-', $name);
|
||||
|
||||
@ -7262,6 +7302,8 @@ EOL;
|
||||
protected function coerceString($value)
|
||||
{
|
||||
if ($value[0] === Type::T_STRING) {
|
||||
assert(\is_array($value));
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
@ -7365,6 +7407,7 @@ EOL;
|
||||
if ($value[0] !== Type::T_LIST) {
|
||||
throw $this->error('expecting list, %s received', $value[0]);
|
||||
}
|
||||
assert(\is_array($value));
|
||||
|
||||
return $value;
|
||||
}
|
||||
@ -7534,7 +7577,7 @@ EOL;
|
||||
$h = 60 * ($green - $blue) / $d;
|
||||
} elseif ($green == $max) {
|
||||
$h = 60 * ($blue - $red) / $d + 120;
|
||||
} elseif ($blue == $max) {
|
||||
} else {
|
||||
$h = 60 * ($red - $green) / $d + 240;
|
||||
}
|
||||
}
|
||||
@ -7613,9 +7656,9 @@ EOL;
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param int $hue H from 0 to 360
|
||||
* @param int $whiteness W from 0 to 100
|
||||
* @param int $blackness B from 0 to 100
|
||||
* @param int|float $hue H from 0 to 360
|
||||
* @param int|float $whiteness W from 0 to 100
|
||||
* @param int|float $blackness B from 0 to 100
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
@ -7666,7 +7709,7 @@ EOL;
|
||||
$h = 60 * ($green - $blue) / $d;
|
||||
} elseif ($green == $max) {
|
||||
$h = 60 * ($blue - $red) / $d + 120;
|
||||
} elseif ($blue == $max) {
|
||||
} else {
|
||||
$h = 60 * ($red - $green) / $d + 240;
|
||||
}
|
||||
}
|
||||
@ -7790,6 +7833,14 @@ EOL;
|
||||
['channels'],
|
||||
['red', 'green', 'blue'],
|
||||
['red', 'green', 'blue', 'alpha'] ];
|
||||
|
||||
/**
|
||||
* @param array $args
|
||||
* @param array $kwargs
|
||||
* @param string $funcName
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function libRgb($args, $kwargs, $funcName = 'rgb')
|
||||
{
|
||||
switch (\count($args)) {
|
||||
@ -7872,14 +7923,7 @@ EOL;
|
||||
$scale = $operation === 'scale';
|
||||
$change = $operation === 'change';
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param float|int $max
|
||||
* @param bool $checkPercent
|
||||
* @param bool $assertPercent
|
||||
*
|
||||
* @return float|int|null
|
||||
*/
|
||||
/** @phpstan-var callable(string, float|int, bool=, bool=): (float|int|null) $getParam */
|
||||
$getParam = function ($name, $max, $checkPercent = false, $assertPercent = false) use (&$kwargs, $scale, $change) {
|
||||
if (!isset($kwargs[$name])) {
|
||||
return null;
|
||||
@ -7903,7 +7947,11 @@ EOL;
|
||||
$max = 100;
|
||||
}
|
||||
|
||||
return $number->valueInRange($change ? 0 : -$max, $max, $name);
|
||||
if ($scale || $assertPercent) {
|
||||
return $number->valueInRange($change ? 0 : -$max, $max, $name);
|
||||
}
|
||||
|
||||
return $number->valueInRangeWithUnit($change ? 0 : -$max, $max, $name, $checkPercent ? '%' : '');
|
||||
};
|
||||
|
||||
$alpha = $getParam('alpha', 1);
|
||||
@ -7938,7 +7986,6 @@ EOL;
|
||||
$hasRgb = $red !== null || $green !== null || $blue !== null;
|
||||
$hasSL = $saturation !== null || $lightness !== null;
|
||||
$hasWB = $whiteness !== null || $blackness !== null;
|
||||
$found = false;
|
||||
|
||||
if ($hasRgb && ($hasSL || $hasWB || $hue !== null)) {
|
||||
throw new SassScriptException(sprintf('RGB parameters may not be passed along with %s parameters.', $hasWB ? 'HWB' : 'HSL'));
|
||||
@ -8159,6 +8206,14 @@ EOL;
|
||||
['hue', 'saturation'],
|
||||
['hue', 'saturation', 'lightness'],
|
||||
['hue', 'saturation', 'lightness', 'alpha'] ];
|
||||
|
||||
/**
|
||||
* @param array $args
|
||||
* @param array $kwargs
|
||||
* @param string $funcName
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
protected function libHsl($args, $kwargs, $funcName = 'hsl')
|
||||
{
|
||||
$args_to_check = $args;
|
||||
@ -8183,7 +8238,7 @@ EOL;
|
||||
throw new SassScriptException('Missing argument $lightness.');
|
||||
}
|
||||
|
||||
foreach ($kwargs as $k => $arg) {
|
||||
foreach ($kwargs as $arg) {
|
||||
if (in_array($arg[0], [Type::T_FUNCTION_CALL, Type::T_FUNCTION]) && in_array($arg[1], ['min', 'max'])) {
|
||||
return null;
|
||||
}
|
||||
@ -8531,7 +8586,7 @@ EOL;
|
||||
$color = $this->assertColor($args[0], 'color');
|
||||
$amount = $this->assertNumber($args[1], 'amount');
|
||||
|
||||
$color[4] = (isset($color[4]) ? $color[4] : 1) + $amount->valueInRange(0, 1, 'amount');
|
||||
$color[4] = (isset($color[4]) ? $color[4] : 1) + $amount->valueInRangeWithUnit(0, 1, 'amount', '');
|
||||
$color[4] = min(1, max(0, $color[4]));
|
||||
|
||||
return $color;
|
||||
@ -8550,7 +8605,7 @@ EOL;
|
||||
$color = $this->assertColor($args[0], 'color');
|
||||
$amount = $this->assertNumber($args[1], 'amount');
|
||||
|
||||
$color[4] = (isset($color[4]) ? $color[4] : 1) - $amount->valueInRange(0, 1, 'amount');
|
||||
$color[4] = (isset($color[4]) ? $color[4] : 1) - $amount->valueInRangeWithUnit(0, 1, 'amount', '');
|
||||
$color[4] = min(1, max(0, $color[4]));
|
||||
|
||||
return $color;
|
||||
@ -8718,7 +8773,7 @@ will be an error in future versions of Sass.\n on line $line of $fname";
|
||||
protected function libNth($args)
|
||||
{
|
||||
$list = $this->coerceList($args[0], ',', false);
|
||||
$n = $this->assertNumber($args[1])->getDimension();
|
||||
$n = $this->assertInteger($args[1]);
|
||||
|
||||
if ($n > 0) {
|
||||
$n--;
|
||||
@ -8733,7 +8788,7 @@ will be an error in future versions of Sass.\n on line $line of $fname";
|
||||
protected function libSetNth($args)
|
||||
{
|
||||
$list = $this->coerceList($args[0]);
|
||||
$n = $this->assertNumber($args[1])->getDimension();
|
||||
$n = $this->assertInteger($args[1]);
|
||||
|
||||
if ($n > 0) {
|
||||
$n--;
|
||||
@ -9350,7 +9405,7 @@ will be an error in future versions of Sass.\n on line $line of $fname";
|
||||
$index = $index - 1;
|
||||
}
|
||||
if ($index < 0) {
|
||||
$index = Util::mbStrlen($stringContent) + 1 + $index;
|
||||
$index = max(Util::mbStrlen($stringContent) + 1 + $index, 0);
|
||||
}
|
||||
|
||||
$string[2] = [
|
||||
@ -9538,7 +9593,25 @@ will be an error in future versions of Sass.\n on line $line of $fname";
|
||||
protected function libRandom($args)
|
||||
{
|
||||
if (isset($args[0]) && $args[0] !== static::$null) {
|
||||
$n = $this->assertInteger($args[0], 'limit');
|
||||
$limit = $this->assertNumber($args[0], 'limit');
|
||||
|
||||
if ($limit->hasUnits()) {
|
||||
$unitString = $limit->unitStr();
|
||||
$message = <<<TXT
|
||||
random() will no longer ignore \$limit units ($limit) in a future release.
|
||||
|
||||
Recommendation: random(\$limit / 1$unitString) * 1$unitString
|
||||
|
||||
To preserve current behavior: random(\$limit / 1$unitString)
|
||||
|
||||
More info: https://sass-lang.com/d/random-with-units
|
||||
|
||||
TXT;
|
||||
|
||||
Warn::deprecation($this->addLocationToMessage($message));
|
||||
}
|
||||
|
||||
$n = $this->assertInteger($limit, 'limit');
|
||||
|
||||
if ($n < 1) {
|
||||
throw new SassScriptException("\$limit: Must be greater than 0, was $n.");
|
||||
@ -10003,6 +10076,8 @@ will be an error in future versions of Sass.\n on line $line of $fname";
|
||||
$selectorsMap[] = $this->getSelectorArg($arg, 'selector', true);
|
||||
}
|
||||
|
||||
assert(!empty($selectorsMap));
|
||||
|
||||
$envs = [];
|
||||
|
||||
foreach ($selectorsMap as $selectors) {
|
||||
|
@ -22,7 +22,8 @@ namespace ScssPhp\ScssPhp\Exception;
|
||||
class ParserException extends \Exception implements SassException
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
* @var array|null
|
||||
* @phpstan-var array{string, int, int}|null
|
||||
*/
|
||||
private $sourcePosition;
|
||||
|
||||
@ -30,6 +31,9 @@ class ParserException extends \Exception implements SassException
|
||||
* Get source position
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @return array|null
|
||||
* @phpstan-return array{string, int, int}|null
|
||||
*/
|
||||
public function getSourcePosition()
|
||||
{
|
||||
@ -42,6 +46,10 @@ class ParserException extends \Exception implements SassException
|
||||
* @api
|
||||
*
|
||||
* @param array $sourcePosition
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @phpstan-param array{string, int, int} $sourcePosition
|
||||
*/
|
||||
public function setSourcePosition($sourcePosition)
|
||||
{
|
||||
|
@ -286,9 +286,18 @@ abstract class Formatter
|
||||
|
||||
ob_start();
|
||||
|
||||
$this->block($block);
|
||||
try {
|
||||
$this->block($block);
|
||||
} catch (\Exception $e) {
|
||||
ob_end_clean();
|
||||
throw $e;
|
||||
} catch (\Throwable $e) {
|
||||
ob_end_clean();
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$out = ob_get_clean();
|
||||
assert($out !== false);
|
||||
|
||||
return $out;
|
||||
}
|
||||
@ -331,6 +340,8 @@ abstract class Formatter
|
||||
// If the written line starts is empty, adding a mapping would add it for
|
||||
// a non-existent column as we are at the end of the line
|
||||
if ($line !== '') {
|
||||
assert($this->currentBlock->sourceLine !== null);
|
||||
assert($this->currentBlock->sourceName !== null);
|
||||
$this->sourceMapGenerator->addMapping(
|
||||
$this->currentLine,
|
||||
$this->currentColumn,
|
||||
@ -346,6 +357,8 @@ abstract class Formatter
|
||||
}
|
||||
|
||||
if ($lastLine !== '') {
|
||||
assert($this->currentBlock->sourceLine !== null);
|
||||
assert($this->currentBlock->sourceName !== null);
|
||||
$this->sourceMapGenerator->addMapping(
|
||||
$this->currentLine,
|
||||
$this->currentColumn,
|
||||
|
@ -57,7 +57,9 @@ class Expanded extends Formatter
|
||||
|
||||
foreach ($block->lines as $index => $line) {
|
||||
if (substr($line, 0, 2) === '/*') {
|
||||
$block->lines[$index] = preg_replace('/\r\n?|\n|\f/', $this->break, $line);
|
||||
$replacedLine = preg_replace('/\r\n?|\n|\f/', $this->break, $line);
|
||||
assert($replacedLine !== null);
|
||||
$block->lines[$index] = $replacedLine;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,9 @@ class Nested extends Formatter
|
||||
|
||||
foreach ($block->lines as $index => $line) {
|
||||
if (substr($line, 0, 2) === '/*') {
|
||||
$block->lines[$index] = preg_replace('/\r\n?|\n|\f/', $this->break, $line);
|
||||
$replacedLine = preg_replace('/\r\n?|\n|\f/', $this->break, $line);
|
||||
assert($replacedLine !== null);
|
||||
$block->lines[$index] = $replacedLine;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ namespace ScssPhp\ScssPhp\Formatter;
|
||||
class OutputBlock
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
* @var string|null
|
||||
*/
|
||||
public $type;
|
||||
|
||||
|
@ -14,6 +14,8 @@ namespace ScssPhp\ScssPhp\Logger;
|
||||
|
||||
/**
|
||||
* A logger that silently ignores all messages.
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class QuietLogger implements LoggerInterface
|
||||
{
|
||||
|
@ -14,6 +14,8 @@ namespace ScssPhp\ScssPhp\Logger;
|
||||
|
||||
/**
|
||||
* A logger that prints to a PHP stream (for instance stderr)
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class StreamLogger implements LoggerInterface
|
||||
{
|
||||
|
@ -227,6 +227,16 @@ class Number extends Node implements \ArrayAccess
|
||||
return \count($this->numeratorUnits) === 0 && \count($this->denominatorUnits) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the number has any units
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasUnits()
|
||||
{
|
||||
return !$this->unitless();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the number has exactly this unit
|
||||
*
|
||||
@ -266,7 +276,27 @@ class Number extends Node implements \ArrayAccess
|
||||
try {
|
||||
return Util::checkRange('', new Range($min, $max), $this);
|
||||
} catch (RangeException $e) {
|
||||
throw SassScriptException::forArgument(sprintf('Expected %s to be within %s%s and %s%3$s', $this, $min, $this->unitStr(), $max), $name);
|
||||
throw SassScriptException::forArgument(sprintf('Expected %s to be within %s%s and %s%3$s.', $this, $min, $this->unitStr(), $max), $name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float|int $min
|
||||
* @param float|int $max
|
||||
* @param string $name
|
||||
* @param string $unit
|
||||
*
|
||||
* @return float|int
|
||||
* @throws SassScriptException
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function valueInRangeWithUnit($min, $max, $name, $unit)
|
||||
{
|
||||
try {
|
||||
return Util::checkRange('', new Range($min, $max), $this);
|
||||
} catch (RangeException $e) {
|
||||
throw SassScriptException::forArgument(sprintf('Expected %s to be within %s%s and %s%3$s.', $this, $min, $unit, $max), $name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ use ScssPhp\ScssPhp\Block\WhileBlock;
|
||||
use ScssPhp\ScssPhp\Exception\ParserException;
|
||||
use ScssPhp\ScssPhp\Logger\LoggerInterface;
|
||||
use ScssPhp\ScssPhp\Logger\QuietLogger;
|
||||
use ScssPhp\ScssPhp\Node\Number;
|
||||
|
||||
/**
|
||||
* Parser
|
||||
@ -85,10 +86,6 @@ class Parser
|
||||
* @var array<int, int>
|
||||
*/
|
||||
private $sourcePositions;
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
private $charset;
|
||||
/**
|
||||
* The current offset in the buffer
|
||||
*
|
||||
@ -147,11 +144,9 @@ class Parser
|
||||
{
|
||||
$this->sourceName = $sourceName ?: '(stdin)';
|
||||
$this->sourceIndex = $sourceIndex;
|
||||
$this->charset = null;
|
||||
$this->utf8 = ! $encoding || strtolower($encoding) === 'utf-8';
|
||||
$this->patternModifiers = $this->utf8 ? 'Aisu' : 'Ais';
|
||||
$this->commentsSeen = [];
|
||||
$this->commentsSeen = [];
|
||||
$this->allowVars = true;
|
||||
$this->cssOnly = $cssOnly;
|
||||
$this->logger = $logger ?: new QuietLogger();
|
||||
@ -255,7 +250,6 @@ class Parser
|
||||
if ($this->cache) {
|
||||
$cacheKey = $this->sourceName . ':' . md5($buffer);
|
||||
$parseOptions = [
|
||||
'charset' => $this->charset,
|
||||
'utf8' => $this->utf8,
|
||||
];
|
||||
$v = $this->cache->getCache('parse', $cacheKey, $parseOptions);
|
||||
@ -296,11 +290,8 @@ class Parser
|
||||
throw $this->parseError('unclosed block');
|
||||
}
|
||||
|
||||
if ($this->charset) {
|
||||
array_unshift($this->env->children, $this->charset);
|
||||
}
|
||||
|
||||
$this->restoreEncoding();
|
||||
assert($this->env !== null);
|
||||
|
||||
if ($this->cache) {
|
||||
$this->cache->setCache('parse', $cacheKey, $this->env, $parseOptions);
|
||||
@ -380,8 +371,8 @@ class Parser
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @param string $buffer
|
||||
* @param string|array $out
|
||||
* @param string $buffer
|
||||
* @param array $out
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
@ -827,18 +818,6 @@ class Parser
|
||||
$this->valueList($charset) &&
|
||||
$this->end()
|
||||
) {
|
||||
if (! isset($this->charset)) {
|
||||
$statement = [Type::T_CHARSET, $charset];
|
||||
|
||||
list($line, $column) = $this->getSourcePosition($s);
|
||||
|
||||
$statement[static::SOURCE_LINE] = $line;
|
||||
$statement[static::SOURCE_COLUMN] = $column;
|
||||
$statement[static::SOURCE_INDEX] = $this->sourceIndex;
|
||||
|
||||
$this->charset = $statement;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1074,6 +1053,8 @@ class Parser
|
||||
$block = $this->popBlock();
|
||||
|
||||
if (! isset($block->type) || $block->type !== Type::T_IF) {
|
||||
assert($this->env !== null);
|
||||
|
||||
if ($this->env->parent) {
|
||||
$this->append(null); // collect comments before next statement if needed
|
||||
}
|
||||
@ -1093,6 +1074,7 @@ class Parser
|
||||
// collect comments just after the block closing if needed
|
||||
if ($this->eatWhiteDefault) {
|
||||
$this->whitespace();
|
||||
assert($this->env !== null);
|
||||
|
||||
if ($this->env->comments) {
|
||||
$this->append(null);
|
||||
@ -1161,6 +1143,7 @@ class Parser
|
||||
// collect comments at the beginning of a block if needed
|
||||
if ($this->eatWhiteDefault) {
|
||||
$this->whitespace();
|
||||
assert($this->env !== null);
|
||||
|
||||
if ($this->env->comments) {
|
||||
$this->append(null);
|
||||
@ -1195,6 +1178,7 @@ class Parser
|
||||
*/
|
||||
protected function popBlock()
|
||||
{
|
||||
assert($this->env !== null);
|
||||
|
||||
// collect comments ending just before of a block closing
|
||||
if ($this->env->comments) {
|
||||
@ -1245,6 +1229,8 @@ class Parser
|
||||
* Seek to position in input stream (or return current position in input stream)
|
||||
*
|
||||
* @param int $where
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function seek($where)
|
||||
{
|
||||
@ -1257,6 +1243,8 @@ class Parser
|
||||
* @param array|false $parsed
|
||||
* @param int $startPos
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws ParserException
|
||||
*/
|
||||
protected function assertPlainCssValid($parsed, $startPos = null)
|
||||
@ -1288,7 +1276,7 @@ class Parser
|
||||
* @param array $parsed
|
||||
* @param bool $allowExpression
|
||||
*
|
||||
* @return bool|array
|
||||
* @return array|false
|
||||
*/
|
||||
protected function isPlainCssValidElement($parsed, $allowExpression = false)
|
||||
{
|
||||
@ -1468,6 +1456,8 @@ class Parser
|
||||
* @param string $delim Delimiter
|
||||
*
|
||||
* @return bool True if match; false otherwise
|
||||
*
|
||||
* @phpstan-impure
|
||||
*/
|
||||
protected function matchString(&$m, $delim)
|
||||
{
|
||||
@ -1508,6 +1498,8 @@ class Parser
|
||||
* @param bool $eatWhitespace
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @phpstan-impure
|
||||
*/
|
||||
protected function match($regex, &$out, $eatWhitespace = null)
|
||||
{
|
||||
@ -1537,6 +1529,8 @@ class Parser
|
||||
* @param bool $eatWhitespace
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @phpstan-impure
|
||||
*/
|
||||
protected function matchChar($char, $eatWhitespace = null)
|
||||
{
|
||||
@ -1565,6 +1559,8 @@ class Parser
|
||||
* @param bool $eatWhitespace
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @phpstan-impure
|
||||
*/
|
||||
protected function literal($what, $len, $eatWhitespace = null)
|
||||
{
|
||||
@ -1589,6 +1585,8 @@ class Parser
|
||||
* Match some whitespace
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @phpstan-impure
|
||||
*/
|
||||
protected function whitespace()
|
||||
{
|
||||
@ -1640,20 +1638,20 @@ class Parser
|
||||
|
||||
if (! $comment) {
|
||||
// single part static comment
|
||||
$this->appendComment([Type::T_COMMENT, $c]);
|
||||
$commentStatement = [Type::T_COMMENT, $c];
|
||||
} else {
|
||||
$comment[] = $c;
|
||||
$staticComment = substr($this->buffer, $startCommentCount, $endCommentCount - $startCommentCount);
|
||||
$commentStatement = [Type::T_COMMENT, $staticComment, [Type::T_STRING, '', $comment]];
|
||||
|
||||
list($line, $column) = $this->getSourcePosition($startCommentCount);
|
||||
$commentStatement[self::SOURCE_LINE] = $line;
|
||||
$commentStatement[self::SOURCE_COLUMN] = $column;
|
||||
$commentStatement[self::SOURCE_INDEX] = $this->sourceIndex;
|
||||
|
||||
$this->appendComment($commentStatement);
|
||||
}
|
||||
|
||||
list($line, $column) = $this->getSourcePosition($startCommentCount);
|
||||
$commentStatement[self::SOURCE_LINE] = $line;
|
||||
$commentStatement[self::SOURCE_COLUMN] = $column;
|
||||
$commentStatement[self::SOURCE_INDEX] = $this->sourceIndex;
|
||||
|
||||
$this->appendComment($commentStatement);
|
||||
|
||||
$this->commentsSeen[$startCommentCount] = true;
|
||||
$this->count = $endCommentCount;
|
||||
} else {
|
||||
@ -1675,9 +1673,13 @@ class Parser
|
||||
* Append comment to current block
|
||||
*
|
||||
* @param array $comment
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function appendComment($comment)
|
||||
{
|
||||
assert($this->env !== null);
|
||||
|
||||
if (! $this->discardComments) {
|
||||
$this->env->comments[] = $comment;
|
||||
}
|
||||
@ -1688,9 +1690,13 @@ class Parser
|
||||
*
|
||||
* @param array|null $statement
|
||||
* @param int $pos
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function append($statement, $pos = null)
|
||||
{
|
||||
assert($this->env !== null);
|
||||
|
||||
if (! \is_null($statement)) {
|
||||
! $this->cssOnly || ($statement = $this->assertPlainCssValid($statement, $pos));
|
||||
|
||||
@ -1720,11 +1726,15 @@ class Parser
|
||||
*/
|
||||
protected function last()
|
||||
{
|
||||
assert($this->env !== null);
|
||||
|
||||
$i = \count($this->env->children) - 1;
|
||||
|
||||
if (isset($this->env->children[$i])) {
|
||||
return $this->env->children[$i];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2069,10 +2079,12 @@ class Parser
|
||||
/**
|
||||
* Parse directive value list that considers $vars as keyword
|
||||
*
|
||||
* @param array $out
|
||||
* @param bool|string $endChar
|
||||
* @param array $out
|
||||
* @param string|false $endChar
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @phpstan-impure
|
||||
*/
|
||||
protected function directiveValue(&$out, $endChar = false)
|
||||
{
|
||||
@ -2211,6 +2223,7 @@ class Parser
|
||||
{
|
||||
$s = $this->count;
|
||||
$items = [];
|
||||
/** @var array|Number|null $value */
|
||||
$value = null;
|
||||
|
||||
while ($this->$parseItem($value)) {
|
||||
@ -2224,9 +2237,12 @@ class Parser
|
||||
|
||||
$trailing_delim = true;
|
||||
} else {
|
||||
assert(\is_array($value) || $value instanceof Number);
|
||||
// if no delim watch that a keyword didn't eat the single/double quote
|
||||
// from the following starting string
|
||||
if ($value[0] === Type::T_KEYWORD) {
|
||||
assert(\is_array($value));
|
||||
/** @var string $word */
|
||||
$word = $value[1];
|
||||
|
||||
$last_char = substr($word, -1);
|
||||
@ -2251,8 +2267,10 @@ class Parser
|
||||
$this->count--;
|
||||
}
|
||||
|
||||
/** @var array|Number|null $nextValue */
|
||||
$nextValue = null;
|
||||
if ($this->$parseItem($nextValue)) {
|
||||
assert(\is_array($nextValue) || $nextValue instanceof Number);
|
||||
if ($nextValue[0] === Type::T_KEYWORD && $nextValue[1] === $last_char) {
|
||||
// bad try, forget it
|
||||
$this->seek($currentCount);
|
||||
@ -2306,6 +2324,8 @@ class Parser
|
||||
* @param bool $lookForExp
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @phpstan-impure
|
||||
*/
|
||||
protected function expression(&$out, $listOnly = false, $lookForExp = true)
|
||||
{
|
||||
@ -2366,12 +2386,14 @@ class Parser
|
||||
/**
|
||||
* Parse expression specifically checking for lists in parenthesis or brackets
|
||||
*
|
||||
* @param array $out
|
||||
* @param int $s
|
||||
* @param string $closingParen
|
||||
* @param array $allowedTypes
|
||||
* @param array $out
|
||||
* @param int $s
|
||||
* @param string $closingParen
|
||||
* @param string[] $allowedTypes
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @phpstan-param array<Type::*> $allowedTypes
|
||||
*/
|
||||
protected function enclosedExpression(&$out, $s, $closingParen = ')', $allowedTypes = [Type::T_LIST, Type::T_MAP])
|
||||
{
|
||||
@ -2439,7 +2461,7 @@ class Parser
|
||||
$whiteBefore = isset($this->buffer[$this->count - 1]) &&
|
||||
ctype_space($this->buffer[$this->count - 1]);
|
||||
|
||||
while ($this->match($operators, $m, false) && static::$precedence[$m[1]] >= $minP) {
|
||||
while ($this->match($operators, $m, false) && static::$precedence[strtolower($m[1])] >= $minP) {
|
||||
$whiteAfter = isset($this->buffer[$this->count]) &&
|
||||
ctype_space($this->buffer[$this->count]);
|
||||
$varAfter = isset($this->buffer[$this->count]) &&
|
||||
@ -2463,7 +2485,7 @@ class Parser
|
||||
}
|
||||
|
||||
// consume higher-precedence operators on the right-hand side
|
||||
$rhs = $this->expHelper($rhs, static::$precedence[$op] + 1);
|
||||
$rhs = $this->expHelper($rhs, static::$precedence[strtolower($op)] + 1);
|
||||
|
||||
$lhs = [Type::T_EXPRESSION, $op, $lhs, $rhs, $this->inParens, $whiteBefore, $whiteAfter];
|
||||
|
||||
@ -2782,6 +2804,10 @@ class Parser
|
||||
$this->argValues($args) &&
|
||||
$this->matchChar(')')
|
||||
) {
|
||||
if (strtolower($name) === 'var' && \count($args) === 2 && $args[1][0] === Type::T_NULL) {
|
||||
$args[1] = [null, [Type::T_STRING, '', [' ']], false];
|
||||
}
|
||||
|
||||
$func = [Type::T_FUNCTION_CALL, $name, $args];
|
||||
|
||||
return true;
|
||||
@ -4016,7 +4042,7 @@ class Parser
|
||||
*
|
||||
* @param array $value
|
||||
*
|
||||
* @return array
|
||||
* @return string[]
|
||||
*/
|
||||
protected function stripAssignmentFlags(&$value)
|
||||
{
|
||||
@ -4043,7 +4069,7 @@ class Parser
|
||||
*
|
||||
* @param array $selectors
|
||||
*
|
||||
* @return string
|
||||
* @return bool
|
||||
*/
|
||||
protected function stripOptionalFlag(&$selectors)
|
||||
{
|
||||
@ -4092,6 +4118,8 @@ class Parser
|
||||
* Extract line numbers from buffer
|
||||
*
|
||||
* @param string $buffer
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function extractLineNumbers($buffer)
|
||||
{
|
||||
@ -4116,6 +4144,7 @@ class Parser
|
||||
* @param int $pos
|
||||
*
|
||||
* @return array
|
||||
* @phpstan-return array{int, int}
|
||||
*/
|
||||
private function getSourcePosition($pos)
|
||||
{
|
||||
|
@ -107,7 +107,7 @@ class SourceMapGenerator
|
||||
*/
|
||||
public function __construct(array $options = [])
|
||||
{
|
||||
$this->options = array_merge($this->defaultOptions, $options);
|
||||
$this->options = array_replace($this->defaultOptions, $options);
|
||||
$this->encoder = new Base64VLQ();
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ class SourceMapGenerator
|
||||
*
|
||||
* @param string $content The content to write
|
||||
*
|
||||
* @return string
|
||||
* @return string|null
|
||||
*
|
||||
* @throws \ScssPhp\ScssPhp\Exception\CompilerException If the file could not be saved
|
||||
* @deprecated
|
||||
@ -148,6 +148,7 @@ class SourceMapGenerator
|
||||
public function saveMap($content)
|
||||
{
|
||||
$file = $this->options['sourceMapWriteTo'];
|
||||
assert($file !== null);
|
||||
$dir = \dirname($file);
|
||||
|
||||
// directory does not exist
|
||||
@ -201,7 +202,7 @@ class SourceMapGenerator
|
||||
// A list of original sources used by the 'mappings' entry.
|
||||
$sourceMap['sources'] = [];
|
||||
|
||||
foreach ($this->sources as $sourceUri => $sourceFilename) {
|
||||
foreach ($this->sources as $sourceFilename) {
|
||||
$sourceMap['sources'][] = $this->normalizeFilename($sourceFilename);
|
||||
}
|
||||
|
||||
@ -223,7 +224,15 @@ class SourceMapGenerator
|
||||
unset($sourceMap['sourceRoot']);
|
||||
}
|
||||
|
||||
return json_encode($sourceMap, JSON_UNESCAPED_SLASHES);
|
||||
$jsonSourceMap = json_encode($sourceMap, JSON_UNESCAPED_SLASHES);
|
||||
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
throw new \RuntimeException(json_last_error_msg());
|
||||
}
|
||||
|
||||
assert($jsonSourceMap !== false);
|
||||
|
||||
return $jsonSourceMap;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -19,5 +19,5 @@ namespace ScssPhp\ScssPhp;
|
||||
*/
|
||||
class Version
|
||||
{
|
||||
const VERSION = '1.10.0';
|
||||
const VERSION = '1.11.0';
|
||||
}
|
||||
|
@ -366,7 +366,7 @@ All rights reserved.</copyright>
|
||||
<location>scssphp</location>
|
||||
<name>scssphp</name>
|
||||
<description>scssphp is a compiler for SCSS written in PHP.</description>
|
||||
<version>1.10.0</version>
|
||||
<version>1.11.0</version>
|
||||
<license>MIT</license>
|
||||
<repository>https://github.com/scssphp/scssphp/</repository>
|
||||
<copyrights>
|
||||
|
Loading…
x
Reference in New Issue
Block a user