⬇️ N°4824 rollback scssphp/scssphp update (won't be done in this branch !)

This commit is contained in:
Pierre Goiffon
2022-05-02 09:15:48 +02:00
parent c4ae94fd4c
commit 0de15d040f
61 changed files with 2573 additions and 8636 deletions

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2015-2020 Leaf Corcoran
* @copyright 2015-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -16,26 +15,17 @@ namespace ScssPhp\ScssPhp\Base;
* Range
*
* @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/
class Range
{
/**
* @var float|int
*/
public $first;
/**
* @var float|int
*/
public $last;
/**
* Initialize range
*
* @param int|float $first
* @param int|float $last
* @param integer|float $first
* @param integer|float $last
*/
public function __construct($first, $last)
{
@@ -46,9 +36,9 @@ class Range
/**
* Test for inclusion in range
*
* @param int|float $value
* @param integer|float $value
*
* @return bool
* @return boolean
*/
public function includes($value)
{

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -16,18 +15,16 @@ namespace ScssPhp\ScssPhp;
* Block
*
* @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/
class Block
{
/**
* @var string|null
* @var string
*/
public $type;
/**
* @var Block|null
* @var \ScssPhp\ScssPhp\Block
*/
public $parent;
@@ -37,22 +34,22 @@ class Block
public $sourceName;
/**
* @var int
* @var integer
*/
public $sourceIndex;
/**
* @var int
* @var integer
*/
public $sourceLine;
/**
* @var int
* @var integer
*/
public $sourceColumn;
/**
* @var array|null
* @var array
*/
public $selectors;
@@ -67,7 +64,7 @@ class Block
public $children;
/**
* @var Block|null
* @var \ScssPhp\ScssPhp\Block
*/
public $selfParent;
}

View File

@@ -1,37 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Type;
/**
* @internal
*/
class AtRootBlock extends Block
{
/**
* @var array|null
*/
public $selector;
/**
* @var array|null
*/
public $with;
public function __construct()
{
$this->type = Type::T_AT_ROOT;
}
}

View File

@@ -1,45 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Compiler\Environment;
/**
* @internal
*/
class CallableBlock extends Block
{
/**
* @var string
*/
public $name;
/**
* @var array|null
*/
public $args;
/**
* @var Environment|null
*/
public $parentEnv;
/**
* @param string $type
*/
public function __construct($type)
{
$this->type = $type;
}
}

View File

@@ -1,38 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Compiler\Environment;
use ScssPhp\ScssPhp\Type;
/**
* @internal
*/
class ContentBlock extends Block
{
/**
* @var array|null
*/
public $child;
/**
* @var Environment|null
*/
public $scope;
public function __construct()
{
$this->type = Type::T_INCLUDE;
}
}

View File

@@ -1,37 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Type;
/**
* @internal
*/
class DirectiveBlock extends Block
{
/**
* @var string|array
*/
public $name;
/**
* @var string|array|null
*/
public $value;
public function __construct()
{
$this->type = Type::T_DIRECTIVE;
}
}

View File

@@ -1,37 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Type;
/**
* @internal
*/
class EachBlock extends Block
{
/**
* @var string[]
*/
public $vars = [];
/**
* @var array
*/
public $list;
public function __construct()
{
$this->type = Type::T_EACH;
}
}

View File

@@ -1,27 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Type;
/**
* @internal
*/
class ElseBlock extends Block
{
public function __construct()
{
$this->type = Type::T_ELSE;
}
}

View File

@@ -1,32 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Type;
/**
* @internal
*/
class ElseifBlock extends Block
{
/**
* @var array
*/
public $cond;
public function __construct()
{
$this->type = Type::T_ELSEIF;
}
}

View File

@@ -1,47 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Type;
/**
* @internal
*/
class ForBlock extends Block
{
/**
* @var string
*/
public $var;
/**
* @var array
*/
public $start;
/**
* @var array
*/
public $end;
/**
* @var bool
*/
public $until;
public function __construct()
{
$this->type = Type::T_FOR;
}
}

View File

@@ -1,37 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Type;
/**
* @internal
*/
class IfBlock extends Block
{
/**
* @var array
*/
public $cond;
/**
* @var array<ElseifBlock|ElseBlock>
*/
public $cases = [];
public function __construct()
{
$this->type = Type::T_IF;
}
}

View File

@@ -1,37 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Type;
/**
* @internal
*/
class MediaBlock extends Block
{
/**
* @var string|array|null
*/
public $value;
/**
* @var array|null
*/
public $queryList;
public function __construct()
{
$this->type = Type::T_MEDIA;
}
}

View File

@@ -1,37 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Type;
/**
* @internal
*/
class NestedPropertyBlock extends Block
{
/**
* @var bool
*/
public $hasValue;
/**
* @var array
*/
public $prefix;
public function __construct()
{
$this->type = Type::T_NESTED_PROPERTY;
}
}

View File

@@ -1,32 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Block;
use ScssPhp\ScssPhp\Type;
/**
* @internal
*/
class WhileBlock extends Block
{
/**
* @var array
*/
public $cond;
public function __construct()
{
$this->type = Type::T_WHILE;
}
}

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -13,7 +12,6 @@
namespace ScssPhp\ScssPhp;
use Exception;
use ScssPhp\ScssPhp\Version;
/**
* The scss cache manager.
@@ -24,60 +22,37 @@ use ScssPhp\ScssPhp\Version;
* taking in account options that affects the result
*
* The cache manager is agnostic about data format and only the operation is expected to be described by string
*
*/
/**
* SCSS cache
*
* @author Cedric Morin <cedric@yterium.com>
*
* @internal
* @author Cedric Morin
*/
class Cache
{
const CACHE_VERSION = 1;
/**
* directory used for storing data
*
* @var string|false
*/
// directory used for storing data
public static $cacheDir = false;
/**
* prefix for the storing data
*
* @var string
*/
// prefix for the storing data
public static $prefix = 'scssphp_';
/**
* force a refresh : 'once' for refreshing the first hit on a cache only, true to never use the cache in this hit
*
* @var bool|string
*/
// force a refresh : 'once' for refreshing the first hit on a cache only, true to never use the cache in this hit
public static $forceRefresh = false;
/**
* specifies the number of seconds after which data cached will be seen as 'garbage' and potentially cleaned up
*
* @var int
*/
// specifies the number of seconds after which data cached will be seen as 'garbage' and potentially cleaned up
public static $gcLifetime = 604800;
/**
* array of already refreshed cache if $forceRefresh==='once'
*
* @var array<string, bool>
*/
// array of already refreshed cache if $forceRefresh==='once'
protected static $refreshed = [];
/**
* Constructor
*
* @param array $options
*
* @phpstan-param array{cacheDir?: string, prefix?: string, forceRefresh?: string} $options
*/
public function __construct($options)
{
@@ -109,10 +84,10 @@ class Cache
* Get the cached result of $operation on $what,
* which is known as dependant from the content of $options
*
* @param string $operation parse, compile...
* @param mixed $what content key (e.g., filename to be treated)
* @param array $options any option that affect the operation result on the content
* @param int|null $lastModified last modified timestamp
* @param string $operation parse, compile...
* @param mixed $what content key (e.g., filename to be treated)
* @param array $options any option that affect the operation result on the content
* @param integer $lastModified last modified timestamp
*
* @return mixed
*
@@ -122,20 +97,18 @@ class Cache
{
$fileCache = self::$cacheDir . self::cacheName($operation, $what, $options);
if (
((self::$forceRefresh === false) || (self::$forceRefresh === 'once' &&
if (((self::$forceRefresh === false) || (self::$forceRefresh === 'once' &&
isset(self::$refreshed[$fileCache]))) && file_exists($fileCache)
) {
$cacheTime = filemtime($fileCache);
if (
(\is_null($lastModified) || $cacheTime > $lastModified) &&
if ((is_null($lastModified) || $cacheTime > $lastModified) &&
$cacheTime + self::$gcLifetime > time()
) {
$c = file_get_contents($fileCache);
$c = unserialize($c);
if (\is_array($c) && isset($c['value'])) {
if (is_array($c) && isset($c['value'])) {
return $c['value'];
}
}
@@ -152,8 +125,6 @@ class Cache
* @param mixed $what
* @param mixed $value
* @param array $options
*
* @return void
*/
public function setCache($operation, $what, $value, $options = [])
{
@@ -161,7 +132,6 @@ class Cache
$c = ['value' => $value];
$c = serialize($c);
file_put_contents($fileCache, $c);
if (self::$forceRefresh === 'once') {
@@ -183,7 +153,6 @@ class Cache
{
$t = [
'version' => self::CACHE_VERSION,
'scssphpVersion' => Version::VERSION,
'operation' => $operation,
'what' => $what,
'options' => $options
@@ -200,8 +169,6 @@ class Cache
/**
* Check that the cache dir exists and is writeable
*
* @return void
*
* @throws \Exception
*/
public static function checkCacheDir()
@@ -210,7 +177,9 @@ class Cache
self::$cacheDir = rtrim(self::$cacheDir, '/') . '/';
if (! is_dir(self::$cacheDir)) {
throw new Exception('Cache directory doesn\'t exist: ' . self::$cacheDir);
if (! mkdir(self::$cacheDir)) {
throw new Exception('Cache directory couldn\'t be created: ' . self::$cacheDir);
}
}
if (! is_writable(self::$cacheDir)) {
@@ -220,8 +189,6 @@ class Cache
/**
* Delete unused cached files
*
* @return void
*/
public static function cleanCache()
{

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -16,8 +15,6 @@ namespace ScssPhp\ScssPhp;
* CSS Colors
*
* @author Leaf Corcoran <leafot@gmail.com>
*
* @internal
*/
class Colors
{
@@ -26,13 +23,12 @@ class Colors
*
* @see http://www.w3.org/TR/css3-color
*
* @var array<string, string>
* @var array
*/
protected static $cssColors = [
'aliceblue' => '240,248,255',
'antiquewhite' => '250,235,215',
'aqua' => '0,255,255',
'cyan' => '0,255,255',
'aquamarine' => '127,255,212',
'azure' => '240,255,255',
'beige' => '245,245,220',
@@ -50,12 +46,13 @@ class Colors
'cornflowerblue' => '100,149,237',
'cornsilk' => '255,248,220',
'crimson' => '220,20,60',
'cyan' => '0,255,255',
'darkblue' => '0,0,139',
'darkcyan' => '0,139,139',
'darkgoldenrod' => '184,134,11',
'darkgray' => '169,169,169',
'darkgrey' => '169,169,169',
'darkgreen' => '0,100,0',
'darkgrey' => '169,169,169',
'darkkhaki' => '189,183,107',
'darkmagenta' => '139,0,139',
'darkolivegreen' => '85,107,47',
@@ -78,15 +75,14 @@ class Colors
'floralwhite' => '255,250,240',
'forestgreen' => '34,139,34',
'fuchsia' => '255,0,255',
'magenta' => '255,0,255',
'gainsboro' => '220,220,220',
'ghostwhite' => '248,248,255',
'gold' => '255,215,0',
'goldenrod' => '218,165,32',
'gray' => '128,128,128',
'grey' => '128,128,128',
'green' => '0,128,0',
'greenyellow' => '173,255,47',
'grey' => '128,128,128',
'honeydew' => '240,255,240',
'hotpink' => '255,105,180',
'indianred' => '205,92,92',
@@ -102,8 +98,8 @@ class Colors
'lightcyan' => '224,255,255',
'lightgoldenrodyellow' => '250,250,210',
'lightgray' => '211,211,211',
'lightgrey' => '211,211,211',
'lightgreen' => '144,238,144',
'lightgrey' => '211,211,211',
'lightpink' => '255,182,193',
'lightsalmon' => '255,160,122',
'lightseagreen' => '32,178,170',
@@ -115,6 +111,7 @@ class Colors
'lime' => '0,255,0',
'limegreen' => '50,205,50',
'linen' => '250,240,230',
'magenta' => '255,0,255',
'maroon' => '128,0,0',
'mediumaquamarine' => '102,205,170',
'mediumblue' => '0,0,205',
@@ -148,6 +145,7 @@ class Colors
'plum' => '221,160,221',
'powderblue' => '176,224,230',
'purple' => '128,0,128',
'rebeccapurple' => '102,51,153',
'red' => '255,0,0',
'rosybrown' => '188,143,143',
'royalblue' => '65,105,225',
@@ -169,6 +167,7 @@ class Colors
'teal' => '0,128,128',
'thistle' => '216,191,216',
'tomato' => '255,99,71',
'transparent' => '0,0,0,0',
'turquoise' => '64,224,208',
'violet' => '238,130,238',
'wheat' => '245,222,179',
@@ -176,8 +175,6 @@ class Colors
'whitesmoke' => '245,245,245',
'yellow' => '255,255,0',
'yellowgreen' => '154,205,50',
'rebeccapurple' => '102,51,153',
'transparent' => '0,0,0,0',
];
/**
@@ -185,11 +182,11 @@ class Colors
*
* @param string $colorName
*
* @return int[]|null
* @return array|null
*/
public static function colorNameToRGBa($colorName)
{
if (\is_string($colorName) && isset(static::$cssColors[$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
@@ -204,10 +201,10 @@ class Colors
/**
* Reverse conversion : from RGBA to a color name if possible
*
* @param int $r
* @param int $g
* @param int $b
* @param int|float $a
* @param integer $r
* @param integer $g
* @param integer $b
* @param integer $a
*
* @return string|null
*/
@@ -220,26 +217,28 @@ class Colors
}
if ($a < 1) {
# specific case we dont' revert according to spec
#if (! $a && ! $r && ! $g && ! $b) {
# return 'transparent';
#}
return null;
}
if (\is_null($reverseColorTable)) {
if (is_null($reverseColorTable)) {
$reverseColorTable = [];
foreach (static::$cssColors as $name => $rgb_str) {
$rgb_str = explode(',', $rgb_str);
if (
\count($rgb_str) == 3 &&
! isset($reverseColorTable[\intval($rgb_str[0])][\intval($rgb_str[1])][\intval($rgb_str[2])])
) {
$reverseColorTable[\intval($rgb_str[0])][\intval($rgb_str[1])][\intval($rgb_str[2])] = $name;
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)];
if (isset($reverseColorTable[intval($r)][intval($g)][intval($b)])) {
return $reverseColorTable[intval($r)][intval($g)][intval($b)];
}
return null;

View File

@@ -1,69 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp;
class CompilationResult
{
/**
* @var string
*/
private $css;
/**
* @var string|null
*/
private $sourceMap;
/**
* @var string[]
*/
private $includedFiles;
/**
* @param string $css
* @param string|null $sourceMap
* @param string[] $includedFiles
*/
public function __construct($css, $sourceMap, array $includedFiles)
{
$this->css = $css;
$this->sourceMap = $sourceMap;
$this->includedFiles = $includedFiles;
}
/**
* @return string
*/
public function getCss()
{
return $this->css;
}
/**
* @return string[]
*/
public function getIncludedFiles()
{
return $this->includedFiles;
}
/**
* The sourceMap content, if it was generated
*
* @return null|string
*/
public function getSourceMap()
{
return $this->sourceMap;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,77 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Compiler;
use ScssPhp\ScssPhp\CompilationResult;
/**
* @internal
*/
class CachedResult
{
/**
* @var CompilationResult
*/
private $result;
/**
* @var array<string, int>
*/
private $parsedFiles;
/**
* @var array
* @phpstan-var list<array{currentDir: string|null, path: string, filePath: string}>
*/
private $resolvedImports;
/**
* @param CompilationResult $result
* @param array<string, int> $parsedFiles
* @param array $resolvedImports
*
* @phpstan-param list<array{currentDir: string|null, path: string, filePath: string}> $resolvedImports
*/
public function __construct(CompilationResult $result, array $parsedFiles, array $resolvedImports)
{
$this->result = $result;
$this->parsedFiles = $parsedFiles;
$this->resolvedImports = $resolvedImports;
}
/**
* @return CompilationResult
*/
public function getResult()
{
return $this->result;
}
/**
* @return array<string, int>
*/
public function getParsedFiles()
{
return $this->parsedFiles;
}
/**
* @return array
*
* @phpstan-return list<array{currentDir: string|null, path: string, filePath: string}>
*/
public function getResolvedImports()
{
return $this->resolvedImports;
}
}

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -16,41 +15,19 @@ namespace ScssPhp\ScssPhp\Compiler;
* Compiler environment
*
* @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/
class Environment
{
/**
* @var \ScssPhp\ScssPhp\Block|null
* @var \ScssPhp\ScssPhp\Block
*/
public $block;
/**
* @var \ScssPhp\ScssPhp\Compiler\Environment|null
* @var \ScssPhp\ScssPhp\Compiler\Environment
*/
public $parent;
/**
* @var Environment|null
*/
public $declarationScopeParent;
/**
* @var Environment|null
*/
public $parentStore;
/**
* @var array|null
*/
public $selectors;
/**
* @var string|null
*/
public $marker;
/**
* @var array
*/
@@ -62,7 +39,7 @@ class Environment
public $storeUnreduced;
/**
* @var int
* @var integer
*/
public $depth;
}

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -16,9 +15,7 @@ namespace ScssPhp\ScssPhp\Exception;
* Compiler exception
*
* @author Oleksandr Savchenko <traveltino@gmail.com>
*
* @internal
*/
class CompilerException extends \Exception implements SassException
class CompilerException extends \Exception
{
}

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -16,43 +15,7 @@ namespace ScssPhp\ScssPhp\Exception;
* Parser Exception
*
* @author Oleksandr Savchenko <traveltino@gmail.com>
*
* @internal
*/
class ParserException extends \Exception implements SassException
class ParserException extends \Exception
{
/**
* @var array|null
* @phpstan-var array{string, int, int}|null
*/
private $sourcePosition;
/**
* Get source position
*
* @api
*
* @return array|null
* @phpstan-return array{string, int, int}|null
*/
public function getSourcePosition()
{
return $this->sourcePosition;
}
/**
* Set source position
*
* @api
*
* @param array $sourcePosition
*
* @return void
*
* @phpstan-param array{string, int, int} $sourcePosition
*/
public function setSourcePosition($sourcePosition)
{
$this->sourcePosition = $sourcePosition;
}
}

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -16,9 +15,7 @@ namespace ScssPhp\ScssPhp\Exception;
* Range exception
*
* @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/
class RangeException extends \Exception implements SassException
class RangeException extends \Exception
{
}

View File

@@ -1,7 +0,0 @@
<?php
namespace ScssPhp\ScssPhp\Exception;
interface SassException
{
}

View File

@@ -1,32 +0,0 @@
<?php
namespace ScssPhp\ScssPhp\Exception;
/**
* An exception thrown by SassScript.
*
* This class does not implement SassException on purpose, as it should
* never be returned to the outside code. The compilation will catch it
* and replace it with a SassException reporting the location of the
* error.
*/
class SassScriptException extends \Exception
{
/**
* Creates a SassScriptException with support for an argument name.
*
* This helper ensures a consistent handling of argument names in the
* error message, without duplicating it.
*
* @param string $message
* @param string|null $name The argument name, without $
*
* @return SassScriptException
*/
public static function forArgument($message, $name = null)
{
$varDisplay = !\is_null($name) ? "\${$name}: " : '';
return new self($varDisplay . $message);
}
}

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -12,15 +11,11 @@
namespace ScssPhp\ScssPhp\Exception;
@trigger_error(sprintf('The "%s" class is deprecated.', ServerException::class), E_USER_DEPRECATED);
/**
* Server Exception
*
* @author Anthon Pang <anthon.pang@gmail.com>
*
* @deprecated The Scssphp server should define its own exception instead.
*/
class ServerException extends \Exception implements SassException
class ServerException extends \Exception
{
}

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -19,13 +18,11 @@ use ScssPhp\ScssPhp\SourceMap\SourceMapGenerator;
* Base formatter
*
* @author Leaf Corcoran <leafot@gmail.com>
*
* @internal
*/
abstract class Formatter
{
/**
* @var int
* @var integer
*/
public $indentLevel;
@@ -60,7 +57,7 @@ abstract class Formatter
public $assignSeparator;
/**
* @var bool
* @var boolean
*/
public $keepSemicolons;
@@ -70,17 +67,17 @@ abstract class Formatter
protected $currentBlock;
/**
* @var int
* @var integer
*/
protected $currentLine;
/**
* @var int
* @var integer
*/
protected $currentColumn;
/**
* @var \ScssPhp\ScssPhp\SourceMap\SourceMapGenerator|null
* @var \ScssPhp\ScssPhp\SourceMap\SourceMapGenerator
*/
protected $sourceMapGenerator;
@@ -121,33 +118,16 @@ abstract class Formatter
return rtrim($name) . $this->assignSeparator . $value . ';';
}
/**
* Return custom property assignment
* differs in that you have to keep spaces in the value as is
*
* @api
*
* @param string $name
* @param mixed $value
*
* @return string
*/
public function customProperty($name, $value)
{
return rtrim($name) . trim($this->assignSeparator) . $value . ';';
}
/**
* Output lines inside a block
*
* @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block
*
* @return void
*/
protected function blockLines(OutputBlock $block)
{
$inner = $this->indentStr();
$glue = $this->break . $inner;
$glue = $this->break . $inner;
$this->write($inner . implode($glue, $block->lines));
@@ -160,13 +140,9 @@ abstract class Formatter
* Output block selectors
*
* @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block
*
* @return void
*/
protected function blockSelectors(OutputBlock $block)
{
assert(! empty($block->selectors));
$inner = $this->indentStr();
$this->write($inner
@@ -178,8 +154,6 @@ abstract class Formatter
* Output block children
*
* @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block
*
* @return void
*/
protected function blockChildren(OutputBlock $block)
{
@@ -192,8 +166,6 @@ abstract class Formatter
* Output non-empty block
*
* @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block
*
* @return void
*/
protected function block(OutputBlock $block)
{
@@ -239,7 +211,7 @@ abstract class Formatter
*
* @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block
*
* @return bool
* @return boolean
*/
protected function testEmptyChildren($block)
{
@@ -286,18 +258,9 @@ abstract class Formatter
ob_start();
try {
$this->block($block);
} catch (\Exception $e) {
ob_end_clean();
throw $e;
} catch (\Throwable $e) {
ob_end_clean();
throw $e;
}
$this->block($block);
$out = ob_get_clean();
assert($out !== false);
return $out;
}
@@ -306,8 +269,6 @@ abstract class Formatter
* Output content
*
* @param string $str
*
* @return void
*/
protected function write($str)
{
@@ -321,8 +282,7 @@ abstract class Formatter
* 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 &&
if (! $this->keepSemicolons &&
$str &&
(strpos($str, ';') !== false) &&
(substr($str, -1) === ';')
@@ -333,43 +293,22 @@ abstract class Formatter
}
if ($this->sourceMapGenerator) {
$this->sourceMapGenerator->addMapping(
$this->currentLine,
$this->currentColumn,
$this->currentBlock->sourceLine,
//columns from parser are off by one
$this->currentBlock->sourceColumn > 0 ? $this->currentBlock->sourceColumn - 1 : 0,
$this->currentBlock->sourceName
);
$lines = explode("\n", $str);
$lineCount = count($lines);
$this->currentLine += $lineCount-1;
$lastLine = array_pop($lines);
foreach ($lines as $line) {
// 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,
$this->currentBlock->sourceLine,
//columns from parser are off by one
$this->currentBlock->sourceColumn > 0 ? $this->currentBlock->sourceColumn - 1 : 0,
$this->currentBlock->sourceName
);
}
$this->currentLine++;
$this->currentColumn = 0;
}
if ($lastLine !== '') {
assert($this->currentBlock->sourceLine !== null);
assert($this->currentBlock->sourceName !== null);
$this->sourceMapGenerator->addMapping(
$this->currentLine,
$this->currentColumn,
$this->currentBlock->sourceLine,
//columns from parser are off by one
$this->currentBlock->sourceColumn > 0 ? $this->currentBlock->sourceColumn - 1 : 0,
$this->currentBlock->sourceName
);
}
$this->currentColumn += \strlen($lastLine);
$this->currentColumn = ($lineCount === 1 ? $this->currentColumn : 0) + strlen($lastLine);
}
echo $str;

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -18,10 +17,6 @@ use ScssPhp\ScssPhp\Formatter;
* Compact formatter
*
* @author Leaf Corcoran <leafot@gmail.com>
*
* @deprecated since 1.4.0. Use the Compressed formatter instead.
*
* @internal
*/
class Compact extends Formatter
{
@@ -30,8 +25,6 @@ class Compact extends Formatter
*/
public function __construct()
{
@trigger_error('The Compact formatter is deprecated since 1.4.0. Use the Compressed formatter instead.', E_USER_DEPRECATED);
$this->indentLevel = 0;
$this->indentChar = '';
$this->break = '';

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -13,13 +12,12 @@
namespace ScssPhp\ScssPhp\Formatter;
use ScssPhp\ScssPhp\Formatter;
use ScssPhp\ScssPhp\Formatter\OutputBlock;
/**
* Compressed formatter
*
* @author Leaf Corcoran <leafot@gmail.com>
*
* @internal
*/
class Compressed extends Formatter
{
@@ -50,6 +48,8 @@ class Compressed extends Formatter
foreach ($block->lines as $index => $line) {
if (substr($line, 0, 2) === '/*' && substr($line, 2, 1) !== '!') {
unset($block->lines[$index]);
} elseif (substr($line, 0, 3) === '/*!') {
$block->lines[$index] = '/*' . substr($line, 3);
}
}
@@ -67,8 +67,6 @@ class Compressed extends Formatter
*/
protected function blockSelectors(OutputBlock $block)
{
assert(! empty($block->selectors));
$inner = $this->indentStr();
$this->write(

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -13,15 +12,12 @@
namespace ScssPhp\ScssPhp\Formatter;
use ScssPhp\ScssPhp\Formatter;
use ScssPhp\ScssPhp\Formatter\OutputBlock;
/**
* Crunched formatter
*
* @author Anthon Pang <anthon.pang@gmail.com>
*
* @deprecated since 1.4.0. Use the Compressed formatter instead.
*
* @internal
*/
class Crunched extends Formatter
{
@@ -30,8 +26,6 @@ class Crunched extends Formatter
*/
public function __construct()
{
@trigger_error('The Crunched formatter is deprecated since 1.4.0. Use the Compressed formatter instead.', E_USER_DEPRECATED);
$this->indentLevel = 0;
$this->indentChar = ' ';
$this->break = '';
@@ -71,8 +65,6 @@ class Crunched extends Formatter
*/
protected function blockSelectors(OutputBlock $block)
{
assert(! empty($block->selectors));
$inner = $this->indentStr();
$this->write(

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -13,15 +12,12 @@
namespace ScssPhp\ScssPhp\Formatter;
use ScssPhp\ScssPhp\Formatter;
use ScssPhp\ScssPhp\Formatter\OutputBlock;
/**
* Debug formatter
*
* @author Anthon Pang <anthon.pang@gmail.com>
*
* @deprecated since 1.4.0.
*
* @internal
*/
class Debug extends Formatter
{
@@ -30,8 +26,6 @@ class Debug extends Formatter
*/
public function __construct()
{
@trigger_error('The Debug formatter is deprecated since 1.4.0.', E_USER_DEPRECATED);
$this->indentLevel = 0;
$this->indentChar = '';
$this->break = "\n";

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -13,13 +12,12 @@
namespace ScssPhp\ScssPhp\Formatter;
use ScssPhp\ScssPhp\Formatter;
use ScssPhp\ScssPhp\Formatter\OutputBlock;
/**
* Expanded formatter
*
* @author Leaf Corcoran <leafot@gmail.com>
*
* @internal
*/
class Expanded extends Formatter
{
@@ -57,9 +55,7 @@ class Expanded extends Formatter
foreach ($block->lines as $index => $line) {
if (substr($line, 0, 2) === '/*') {
$replacedLine = preg_replace('/\r\n?|\n|\f/', $this->break, $line);
assert($replacedLine !== null);
$block->lines[$index] = $replacedLine;
$block->lines[$index] = preg_replace('/[\r\n]+/', $glue, $line);
}
}

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -13,21 +12,18 @@
namespace ScssPhp\ScssPhp\Formatter;
use ScssPhp\ScssPhp\Formatter;
use ScssPhp\ScssPhp\Formatter\OutputBlock;
use ScssPhp\ScssPhp\Type;
/**
* Nested formatter
*
* @author Leaf Corcoran <leafot@gmail.com>
*
* @deprecated since 1.4.0. Use the Expanded formatter instead.
*
* @internal
*/
class Nested extends Formatter
{
/**
* @var int
* @var integer
*/
private $depth;
@@ -36,8 +32,6 @@ class Nested extends Formatter
*/
public function __construct()
{
@trigger_error('The Nested formatter is deprecated since 1.4.0. Use the Expanded formatter instead.', E_USER_DEPRECATED);
$this->indentLevel = 0;
$this->indentChar = ' ';
$this->break = "\n";
@@ -64,13 +58,12 @@ class Nested extends Formatter
protected function blockLines(OutputBlock $block)
{
$inner = $this->indentStr();
$glue = $this->break . $inner;
$glue = $this->break . $inner;
foreach ($block->lines as $index => $line) {
if (substr($line, 0, 2) === '/*') {
$replacedLine = preg_replace('/\r\n?|\n|\f/', $this->break, $line);
assert($replacedLine !== null);
$block->lines[$index] = $replacedLine;
$block->lines[$index] = preg_replace('/[\r\n]+/', $glue, $line);
}
}
@@ -97,7 +90,7 @@ class Nested extends Formatter
$previousHasSelector = false;
}
$isMediaOrDirective = \in_array($block->type, [Type::T_DIRECTIVE, Type::T_MEDIA]);
$isMediaOrDirective = in_array($block->type, [Type::T_DIRECTIVE, Type::T_MEDIA]);
$isSupport = ($block->type === Type::T_DIRECTIVE
&& $block->selectors && strpos(implode('', $block->selectors), '@supports') !== false);
@@ -105,8 +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;
@@ -127,12 +119,10 @@ class Nested extends Formatter
if ($block->depth > end($depths)) {
if (! $previousEmpty || $this->depth < 1) {
$this->depth++;
$depths[] = $block->depth;
} else {
// keep the current depth unchanged but take the block depth as a new reference for following blocks
array_pop($depths);
$depths[] = $block->depth;
}
}
@@ -223,7 +213,7 @@ class Nested extends Formatter
*
* @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block
*
* @return bool
* @return boolean
*/
private function hasFlatChild($block)
{

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -16,53 +15,51 @@ namespace ScssPhp\ScssPhp\Formatter;
* Output block
*
* @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/
class OutputBlock
{
/**
* @var string|null
* @var string
*/
public $type;
/**
* @var int
* @var integer
*/
public $depth;
/**
* @var array|null
* @var array
*/
public $selectors;
/**
* @var string[]
* @var array
*/
public $lines;
/**
* @var OutputBlock[]
* @var array
*/
public $children;
/**
* @var OutputBlock|null
* @var \ScssPhp\ScssPhp\Formatter\OutputBlock
*/
public $parent;
/**
* @var string|null
* @var string
*/
public $sourceName;
/**
* @var int|null
* @var integer
*/
public $sourceLine;
/**
* @var int|null
* @var integer
*/
public $sourceColumn;
}

View File

@@ -1,48 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Logger;
/**
* Interface implemented by loggers for warnings and debug messages.
*
* The official Sass implementation recommends that loggers report the
* messages immediately rather than waiting for the end of the
* compilation, to provide a better debugging experience when the
* compilation does not end (error or infinite loop after the warning
* for instance).
*/
interface LoggerInterface
{
/**
* Emits a warning with the given message.
*
* If $deprecation is true, it indicates that this is a deprecation
* warning. Implementations should surface all this information to
* the end user.
*
* @param string $message
* @param bool $deprecation
*
* @return void
*/
public function warn($message, $deprecation = false);
/**
* Emits a debugging message.
*
* @param string $message
*
* @return void
*/
public function debug($message);
}

View File

@@ -1,27 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Logger;
/**
* A logger that silently ignores all messages.
*/
class QuietLogger implements LoggerInterface
{
public function warn($message, $deprecation = false)
{
}
public function debug($message)
{
}
}

View File

@@ -1,60 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\Logger;
/**
* A logger that prints to a PHP stream (for instance stderr)
*/
class StreamLogger implements LoggerInterface
{
private $stream;
private $closeOnDestruct;
/**
* @param resource $stream A stream resource
* @param bool $closeOnDestruct If true, takes ownership of the stream and close it on destruct to avoid leaks.
*/
public function __construct($stream, $closeOnDestruct = false)
{
$this->stream = $stream;
$this->closeOnDestruct = $closeOnDestruct;
}
/**
* @internal
*/
public function __destruct()
{
if ($this->closeOnDestruct) {
fclose($this->stream);
}
}
/**
* @inheritDoc
*/
public function warn($message, $deprecation = false)
{
$prefix = ($deprecation ? 'DEPRECATION ' : '') . 'WARNING: ';
fwrite($this->stream, $prefix . $message . "\n\n");
}
/**
* @inheritDoc
*/
public function debug($message)
{
fwrite($this->stream, $message . "\n");
}
}

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -16,8 +15,6 @@ namespace ScssPhp\ScssPhp;
* Base node
*
* @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/
abstract class Node
{
@@ -27,17 +24,17 @@ abstract class Node
public $type;
/**
* @var int
* @var integer
*/
public $sourceIndex;
/**
* @var int|null
* @var integer
*/
public $sourceLine;
/**
* @var int|null
* @var integer
*/
public $sourceColumn;
}

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -12,13 +11,9 @@
namespace ScssPhp\ScssPhp\Node;
use ScssPhp\ScssPhp\Base\Range;
use ScssPhp\ScssPhp\Compiler;
use ScssPhp\ScssPhp\Exception\RangeException;
use ScssPhp\ScssPhp\Exception\SassScriptException;
use ScssPhp\ScssPhp\Node;
use ScssPhp\ScssPhp\Type;
use ScssPhp\ScssPhp\Util;
/**
* Dimension + optional units
@@ -30,26 +25,20 @@ use ScssPhp\ScssPhp\Util;
* }}
*
* @author Anthon Pang <anthon.pang@gmail.com>
*
* @template-implements \ArrayAccess<int, mixed>
*/
class Number extends Node implements \ArrayAccess
{
const PRECISION = 10;
/**
* @var int
* @deprecated use {Number::PRECISION} instead to read the precision. Configuring it is not supported anymore.
* @var integer
*/
public static $precision = self::PRECISION;
static public $precision = 10;
/**
* @see http://www.w3.org/TR/2012/WD-css3-values-20120308/
*
* @var array
* @phpstan-var array<string, array<string, float|int>>
*/
protected static $unitTable = [
static protected $unitTable = [
'in' => [
'in' => 1,
'pc' => 6,
@@ -75,93 +64,91 @@ class Number extends Node implements \ArrayAccess
],
'dpi' => [
'dpi' => 1,
'dpcm' => 1 / 2.54,
'dppx' => 1 / 96,
'dpcm' => 2.54,
'dppx' => 96,
],
];
/**
* @var int|float
* @var integer|float
*/
private $dimension;
public $dimension;
/**
* @var string[]
* @phpstan-var list<string>
* @var array
*/
private $numeratorUnits;
/**
* @var string[]
* @phpstan-var list<string>
*/
private $denominatorUnits;
public $units;
/**
* Initialize number
*
* @param int|float $dimension
* @param string[]|string $numeratorUnits
* @param string[] $denominatorUnits
*
* @phpstan-param list<string>|string $numeratorUnits
* @phpstan-param list<string> $denominatorUnits
* @param mixed $dimension
* @param mixed $initialUnit
*/
public function __construct($dimension, $numeratorUnits, array $denominatorUnits = [])
public function __construct($dimension, $initialUnit)
{
if (is_string($numeratorUnits)) {
$numeratorUnits = $numeratorUnits ? [$numeratorUnits] : [];
} elseif (isset($numeratorUnits['numerator_units'], $numeratorUnits['denominator_units'])) {
// TODO get rid of this once `$number[2]` is not used anymore
$denominatorUnits = $numeratorUnits['denominator_units'];
$numeratorUnits = $numeratorUnits['numerator_units'];
$this->type = Type::T_NUMBER;
$this->dimension = $dimension;
$this->units = is_array($initialUnit)
? $initialUnit
: ($initialUnit ? [$initialUnit => 1]
: []);
}
/**
* Coerce number to target units
*
* @param array $units
*
* @return \ScssPhp\ScssPhp\Node\Number
*/
public function coerce($units)
{
if ($this->unitless()) {
return new Number($this->dimension, $units);
}
$this->dimension = $dimension;
$this->numeratorUnits = $numeratorUnits;
$this->denominatorUnits = $denominatorUnits;
$dimension = $this->dimension;
foreach (static::$unitTable['in'] as $unit => $conv) {
$from = isset($this->units[$unit]) ? $this->units[$unit] : 0;
$to = isset($units[$unit]) ? $units[$unit] : 0;
$factor = pow($conv, $from - $to);
$dimension /= $factor;
}
return new Number($dimension, $units);
}
/**
* @return float|int
* Normalize number
*
* @return \ScssPhp\ScssPhp\Node\Number
*/
public function getDimension()
public function normalize()
{
return $this->dimension;
$dimension = $this->dimension;
$units = [];
$this->normalizeUnits($dimension, $units, 'in');
return new Number($dimension, $units);
}
/**
* @return string[]
* {@inheritdoc}
*/
public function getNumeratorUnits()
{
return $this->numeratorUnits;
}
/**
* @return string[]
*/
public function getDenominatorUnits()
{
return $this->denominatorUnits;
}
/**
* @return bool
*/
#[\ReturnTypeWillChange]
public function offsetExists($offset)
{
if ($offset === -3) {
return ! \is_null($this->sourceColumn);
return ! is_null($this->sourceColumn);
}
if ($offset === -2) {
return ! \is_null($this->sourceLine);
return ! is_null($this->sourceLine);
}
if (
$offset === -1 ||
if ($offset === -1 ||
$offset === 0 ||
$offset === 1 ||
$offset === 2
@@ -173,9 +160,8 @@ class Number extends Node implements \ArrayAccess
}
/**
* @return mixed
* {@inheritdoc}
*/
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
switch ($offset) {
@@ -189,54 +175,60 @@ class Number extends Node implements \ArrayAccess
return $this->sourceIndex;
case 0:
return Type::T_NUMBER;
return $this->type;
case 1:
return $this->dimension;
case 2:
return array('numerator_units' => $this->numeratorUnits, 'denominator_units' => $this->denominatorUnits);
return $this->units;
}
}
/**
* @return void
* {@inheritdoc}
*/
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
throw new \BadMethodCallException('Number is immutable');
if ($offset === 1) {
$this->dimension = $value;
} elseif ($offset === 2) {
$this->units = $value;
} elseif ($offset == -1) {
$this->sourceIndex = $value;
} elseif ($offset == -2) {
$this->sourceLine = $value;
} elseif ($offset == -3) {
$this->sourceColumn = $value;
}
}
/**
* @return void
* {@inheritdoc}
*/
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
throw new \BadMethodCallException('Number is immutable');
if ($offset === 1) {
$this->dimension = null;
} elseif ($offset === 2) {
$this->units = null;
} elseif ($offset === -1) {
$this->sourceIndex = null;
} elseif ($offset === -2) {
$this->sourceLine = null;
} elseif ($offset === -3) {
$this->sourceColumn = null;
}
}
/**
* Returns true if the number is unitless
*
* @return bool
* @return boolean
*/
public function unitless()
{
return \count($this->numeratorUnits) === 0 && \count($this->denominatorUnits) === 0;
}
/**
* Checks whether the number has exactly this unit
*
* @param string $unit
*
* @return bool
*/
public function hasUnit($unit)
{
return \count($this->numeratorUnits) === 1 && \count($this->denominatorUnits) === 0 && $this->numeratorUnits[0] === $unit;
return ! array_sum($this->units);
}
/**
@@ -246,289 +238,22 @@ class Number extends Node implements \ArrayAccess
*/
public function unitStr()
{
if ($this->unitless()) {
return '';
}
$numerators = [];
$denominators = [];
return self::getUnitString($this->numeratorUnits, $this->denominatorUnits);
}
/**
* @param float|int $min
* @param float|int $max
* @param string|null $name
*
* @return float|int
* @throws SassScriptException
*/
public function valueInRange($min, $max, $name = null)
{
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);
}
}
/**
* @param string|null $varName
*
* @return void
*/
public function assertNoUnits($varName = null)
{
if ($this->unitless()) {
return;
}
throw SassScriptException::forArgument(sprintf('Expected %s to have no units.', $this), $varName);
}
/**
* @param string $unit
* @param string|null $varName
*
* @return void
*/
public function assertUnit($unit, $varName = null)
{
if ($this->hasUnit($unit)) {
return;
}
throw SassScriptException::forArgument(sprintf('Expected %s to have unit "%s".', $this, $unit), $varName);
}
/**
* @param Number $other
*
* @return void
*/
public function assertSameUnitOrUnitless(Number $other)
{
if ($other->unitless()) {
return;
}
if ($this->numeratorUnits === $other->numeratorUnits && $this->denominatorUnits === $other->denominatorUnits) {
return;
}
throw new SassScriptException(sprintf(
'Incompatible units %s and %s.',
self::getUnitString($this->numeratorUnits, $this->denominatorUnits),
self::getUnitString($other->numeratorUnits, $other->denominatorUnits)
));
}
/**
* Returns a copy of this number, converted to the units represented by $newNumeratorUnits and $newDenominatorUnits.
*
* This does not throw an error if this number is unitless and
* $newNumeratorUnits/$newDenominatorUnits are not empty, or vice versa. Instead,
* it treats all unitless numbers as convertible to and from all units without
* changing the value.
*
* @param string[] $newNumeratorUnits
* @param string[] $newDenominatorUnits
*
* @return Number
*
* @phpstan-param list<string> $newNumeratorUnits
* @phpstan-param list<string> $newDenominatorUnits
*
* @throws SassScriptException if this number's units are not compatible with $newNumeratorUnits and $newDenominatorUnits
*/
public function coerce(array $newNumeratorUnits, array $newDenominatorUnits)
{
return new Number($this->valueInUnits($newNumeratorUnits, $newDenominatorUnits), $newNumeratorUnits, $newDenominatorUnits);
}
/**
* @param Number $other
*
* @return bool
*/
public function isComparableTo(Number $other)
{
if ($this->unitless() || $other->unitless()) {
return true;
}
try {
$this->greaterThan($other);
return true;
} catch (SassScriptException $e) {
return false;
}
}
/**
* @param Number $other
*
* @return bool
*/
public function lessThan(Number $other)
{
return $this->coerceUnits($other, function ($num1, $num2) {
return $num1 < $num2;
});
}
/**
* @param Number $other
*
* @return bool
*/
public function lessThanOrEqual(Number $other)
{
return $this->coerceUnits($other, function ($num1, $num2) {
return $num1 <= $num2;
});
}
/**
* @param Number $other
*
* @return bool
*/
public function greaterThan(Number $other)
{
return $this->coerceUnits($other, function ($num1, $num2) {
return $num1 > $num2;
});
}
/**
* @param Number $other
*
* @return bool
*/
public function greaterThanOrEqual(Number $other)
{
return $this->coerceUnits($other, function ($num1, $num2) {
return $num1 >= $num2;
});
}
/**
* @param Number $other
*
* @return Number
*/
public function plus(Number $other)
{
return $this->coerceNumber($other, function ($num1, $num2) {
return $num1 + $num2;
});
}
/**
* @param Number $other
*
* @return Number
*/
public function minus(Number $other)
{
return $this->coerceNumber($other, function ($num1, $num2) {
return $num1 - $num2;
});
}
/**
* @return Number
*/
public function unaryMinus()
{
return new Number(-$this->dimension, $this->numeratorUnits, $this->denominatorUnits);
}
/**
* @param Number $other
*
* @return Number
*/
public function modulo(Number $other)
{
return $this->coerceNumber($other, function ($num1, $num2) {
if ($num2 == 0) {
return NAN;
foreach ($this->units as $unit => $unitSize) {
if ($unitSize > 0) {
$numerators = array_pad($numerators, count($numerators) + $unitSize, $unit);
continue;
}
$result = fmod($num1, $num2);
if ($result == 0) {
return 0;
if ($unitSize < 0) {
$denominators = array_pad($denominators, count($denominators) + $unitSize, $unit);
continue;
}
if ($num2 < 0 xor $num1 < 0) {
$result += $num2;
}
return $result;
});
}
/**
* @param Number $other
*
* @return Number
*/
public function times(Number $other)
{
return $this->multiplyUnits($this->dimension * $other->dimension, $this->numeratorUnits, $this->denominatorUnits, $other->numeratorUnits, $other->denominatorUnits);
}
/**
* @param Number $other
*
* @return Number
*/
public function dividedBy(Number $other)
{
if ($other->dimension == 0) {
if ($this->dimension == 0) {
$value = NAN;
} elseif ($this->dimension > 0) {
$value = INF;
} else {
$value = -INF;
}
} else {
$value = $this->dimension / $other->dimension;
}
return $this->multiplyUnits($value, $this->numeratorUnits, $this->denominatorUnits, $other->denominatorUnits, $other->numeratorUnits);
}
/**
* @param Number $other
*
* @return bool
*/
public function equals(Number $other)
{
// Unitless numbers are convertable to unit numbers, but not equal, so we special-case unitless here.
if ($this->unitless() !== $other->unitless()) {
return false;
}
// In Sass, neither NaN nor Infinity are equal to themselves, while PHP defines INF==INF
if (is_nan($this->dimension) || is_nan($other->dimension) || !is_finite($this->dimension) || !is_finite($other->dimension)) {
return false;
}
if ($this->unitless()) {
return round($this->dimension, self::PRECISION) == round($other->dimension, self::PRECISION);
}
try {
return $this->coerceUnits($other, function ($num1, $num2) {
return round($num1,self::PRECISION) == round($num2, self::PRECISION);
});
} catch (SassScriptException $e) {
return false;
}
return implode('*', $numerators) . (count($denominators) ? '/' . implode('*', $denominators) : '');
}
/**
@@ -540,31 +265,35 @@ class Number extends Node implements \ArrayAccess
*/
public function output(Compiler $compiler = null)
{
$dimension = round($this->dimension, self::PRECISION);
$dimension = round($this->dimension, static::$precision);
if (is_nan($dimension)) {
return 'NaN';
$units = array_filter($this->units, function ($unitSize) {
return $unitSize;
});
if (count($units) > 1 && array_sum($units) === 0) {
$dimension = $this->dimension;
$units = [];
$this->normalizeUnits($dimension, $units, 'in');
$dimension = round($dimension, static::$precision);
$units = array_filter($units, function ($unitSize) {
return $unitSize;
});
}
if ($dimension === INF) {
return 'Infinity';
$unitSize = array_sum($units);
if ($compiler && ($unitSize > 1 || $unitSize < 0 || count($units) > 1)) {
$compiler->throwError((string) $dimension . $this->unitStr() . " isn't a valid CSS value.");
}
if ($dimension === -INF) {
return '-Infinity';
}
reset($units);
$unit = key($units);
$dimension = number_format($dimension, static::$precision, '.', '');
if ($compiler) {
$unit = $this->unitStr();
} elseif (isset($this->numeratorUnits[0])) {
$unit = $this->numeratorUnits[0];
} else {
$unit = '';
}
$dimension = number_format($dimension, self::PRECISION, '.', '');
return rtrim(rtrim($dimension, '0'), '.') . $unit;
return (static::$precision ? rtrim(rtrim($dimension, '0'), '.') : $dimension) . $unit;
}
/**
@@ -576,229 +305,26 @@ class Number extends Node implements \ArrayAccess
}
/**
* @param Number $other
* @param callable $operation
* Normalize units
*
* @return Number
*
* @phpstan-param callable(int|float, int|float): (int|float) $operation
* @param integer|float $dimension
* @param array $units
* @param string $baseUnit
*/
private function coerceNumber(Number $other, $operation)
private function normalizeUnits(&$dimension, &$units, $baseUnit = 'in')
{
$result = $this->coerceUnits($other, $operation);
$dimension = $this->dimension;
$units = [];
if (!$this->unitless()) {
return new Number($result, $this->numeratorUnits, $this->denominatorUnits);
}
foreach ($this->units as $unit => $exp) {
if (isset(static::$unitTable[$baseUnit][$unit])) {
$factor = pow(static::$unitTable[$baseUnit][$unit], $exp);
return new Number($result, $other->numeratorUnits, $other->denominatorUnits);
}
/**
* @param Number $other
* @param callable $operation
*
* @return mixed
*
* @phpstan-template T
* @phpstan-param callable(int|float, int|float): T $operation
* @phpstan-return T
*/
private function coerceUnits(Number $other, $operation)
{
if (!$this->unitless()) {
$num1 = $this->dimension;
$num2 = $other->valueInUnits($this->numeratorUnits, $this->denominatorUnits);
} else {
$num1 = $this->valueInUnits($other->numeratorUnits, $other->denominatorUnits);
$num2 = $other->dimension;
}
return \call_user_func($operation, $num1, $num2);
}
/**
* @param string[] $numeratorUnits
* @param string[] $denominatorUnits
*
* @return int|float
*
* @phpstan-param list<string> $numeratorUnits
* @phpstan-param list<string> $denominatorUnits
*
* @throws SassScriptException if this number's units are not compatible with $numeratorUnits and $denominatorUnits
*/
private function valueInUnits(array $numeratorUnits, array $denominatorUnits)
{
if (
$this->unitless()
|| (\count($numeratorUnits) === 0 && \count($denominatorUnits) === 0)
|| ($this->numeratorUnits === $numeratorUnits && $this->denominatorUnits === $denominatorUnits)
) {
return $this->dimension;
}
$value = $this->dimension;
$oldNumerators = $this->numeratorUnits;
foreach ($numeratorUnits as $newNumerator) {
foreach ($oldNumerators as $key => $oldNumerator) {
$conversionFactor = self::getConversionFactor($newNumerator, $oldNumerator);
if (\is_null($conversionFactor)) {
continue;
}
$value *= $conversionFactor;
unset($oldNumerators[$key]);
continue 2;
$unit = $baseUnit;
$dimension /= $factor;
}
throw new SassScriptException(sprintf(
'Incompatible units %s and %s.',
self::getUnitString($this->numeratorUnits, $this->denominatorUnits),
self::getUnitString($numeratorUnits, $denominatorUnits)
));
$units[$unit] = $exp + (isset($units[$unit]) ? $units[$unit] : 0);
}
$oldDenominators = $this->denominatorUnits;
foreach ($denominatorUnits as $newDenominator) {
foreach ($oldDenominators as $key => $oldDenominator) {
$conversionFactor = self::getConversionFactor($newDenominator, $oldDenominator);
if (\is_null($conversionFactor)) {
continue;
}
$value /= $conversionFactor;
unset($oldDenominators[$key]);
continue 2;
}
throw new SassScriptException(sprintf(
'Incompatible units %s and %s.',
self::getUnitString($this->numeratorUnits, $this->denominatorUnits),
self::getUnitString($numeratorUnits, $denominatorUnits)
));
}
if (\count($oldNumerators) || \count($oldDenominators)) {
throw new SassScriptException(sprintf(
'Incompatible units %s and %s.',
self::getUnitString($this->numeratorUnits, $this->denominatorUnits),
self::getUnitString($numeratorUnits, $denominatorUnits)
));
}
return $value;
}
/**
* @param int|float $value
* @param string[] $numerators1
* @param string[] $denominators1
* @param string[] $numerators2
* @param string[] $denominators2
*
* @return Number
*
* @phpstan-param list<string> $numerators1
* @phpstan-param list<string> $denominators1
* @phpstan-param list<string> $numerators2
* @phpstan-param list<string> $denominators2
*/
private function multiplyUnits($value, array $numerators1, array $denominators1, array $numerators2, array $denominators2)
{
$newNumerators = array();
foreach ($numerators1 as $numerator) {
foreach ($denominators2 as $key => $denominator) {
$conversionFactor = self::getConversionFactor($numerator, $denominator);
if (\is_null($conversionFactor)) {
continue;
}
$value /= $conversionFactor;
unset($denominators2[$key]);
continue 2;
}
$newNumerators[] = $numerator;
}
foreach ($numerators2 as $numerator) {
foreach ($denominators1 as $key => $denominator) {
$conversionFactor = self::getConversionFactor($numerator, $denominator);
if (\is_null($conversionFactor)) {
continue;
}
$value /= $conversionFactor;
unset($denominators1[$key]);
continue 2;
}
$newNumerators[] = $numerator;
}
$newDenominators = array_values(array_merge($denominators1, $denominators2));
return new Number($value, $newNumerators, $newDenominators);
}
/**
* Returns the number of [unit1]s per [unit2].
*
* Equivalently, `1unit1 * conversionFactor(unit1, unit2) = 1unit2`.
*
* @param string $unit1
* @param string $unit2
*
* @return float|int|null
*/
private static function getConversionFactor($unit1, $unit2)
{
if ($unit1 === $unit2) {
return 1;
}
foreach (static::$unitTable as $unitVariants) {
if (isset($unitVariants[$unit1]) && isset($unitVariants[$unit2])) {
return $unitVariants[$unit1] / $unitVariants[$unit2];
}
}
return null;
}
/**
* Returns unit(s) as the product of numerator units divided by the product of denominator units
*
* @param string[] $numerators
* @param string[] $denominators
*
* @phpstan-param list<string> $numerators
* @phpstan-param list<string> $denominators
*
* @return string
*/
private static function getUnitString(array $numerators, array $denominators)
{
if (!\count($numerators)) {
if (\count($denominators) === 0) {
return 'no units';
}
if (\count($denominators) === 1) {
return $denominators[0] . '^-1';
}
return '(' . implode('*', $denominators) . ')^-1';
}
return implode('*', $numerators) . (\count($denominators) ? '/' . implode('*', $denominators) : '');
}
}

View File

@@ -1,9 +0,0 @@
<?php
namespace ScssPhp\ScssPhp;
final class OutputStyle
{
const EXPANDED = 'expanded';
const COMPRESSED = 'compressed';
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -16,13 +15,11 @@ namespace ScssPhp\ScssPhp\SourceMap;
* Base 64 Encode/Decode
*
* @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/
class Base64
{
/**
* @var array<int, string>
* @var array
*/
private static $encodingMap = [
0 => 'A',
@@ -92,7 +89,7 @@ class Base64
];
/**
* @var array<string|int, int>
* @var array
*/
private static $decodingMap = [
'A' => 0,
@@ -164,7 +161,7 @@ class Base64
/**
* Convert to base64
*
* @param int $value
* @param integer $value
*
* @return string
*/
@@ -178,7 +175,7 @@ class Base64
*
* @param string $value
*
* @return int
* @return integer
*/
public static function decode($value)
{

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -12,6 +11,8 @@
namespace ScssPhp\ScssPhp\SourceMap;
use ScssPhp\ScssPhp\SourceMap\Base64;
/**
* Base 64 VLQ
*
@@ -34,8 +35,6 @@ namespace ScssPhp\ScssPhp\SourceMap;
*
* @author John Lenz <johnlenz@google.com>
* @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/
class Base64VLQ
{
@@ -51,7 +50,7 @@ class Base64VLQ
/**
* Returns the VLQ encoded value.
*
* @param int $value
* @param integer $value
*
* @return string
*/
@@ -62,9 +61,7 @@ class Base64VLQ
do {
$digit = $vlq & self::VLQ_BASE_MASK;
//$vlq >>>= self::VLQ_BASE_SHIFT; // unsigned right shift
$vlq = (($vlq >> 1) & PHP_INT_MAX) >> (self::VLQ_BASE_SHIFT - 1);
$vlq >>= self::VLQ_BASE_SHIFT;
if ($vlq > 0) {
$digit |= self::VLQ_CONTINUATION_BIT;
@@ -80,9 +77,9 @@ class Base64VLQ
* Decodes VLQValue.
*
* @param string $str
* @param int $index
* @param integer $index
*
* @return int
* @return integer
*/
public static function decode($str, &$index)
{
@@ -107,9 +104,9 @@ class Base64VLQ
* 1 becomes 2 (10 binary), -1 becomes 3 (11 binary)
* 2 becomes 4 (100 binary), -2 becomes 5 (101 binary)
*
* @param int $value
* @param integer $value
*
* @return int
* @return integer
*/
private static function toVLQSigned($value)
{
@@ -126,16 +123,14 @@ class Base64VLQ
* 2 (10 binary) becomes 1, 3 (11 binary) becomes -1
* 4 (100 binary) becomes 2, 5 (101 binary) becomes -2
*
* @param int $value
* @param integer $value
*
* @return int
* @return integer
*/
private static function fromVLQSigned($value)
{
$negate = ($value & 1) === 1;
//$value >>>= 1; // unsigned right shift
$value = ($value >> 1) & PHP_INT_MAX;
$value = ($value >> 1) & ~(1<<(8 * PHP_INT_SIZE - 1)); // unsigned right shift
if (! $negate) {
return $value;

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -21,8 +20,6 @@ use ScssPhp\ScssPhp\Exception\CompilerException;
*
* @author Josh Schmidt <oyejorge@gmail.com>
* @author Nicolas FRANÇOIS <nicolas.francois@frog-labs.com>
*
* @internal
*/
class SourceMapGenerator
{
@@ -35,7 +32,6 @@ class SourceMapGenerator
* Array of default options
*
* @var array
* @phpstan-var array{sourceRoot: string, sourceMapFilename: string|null, sourceMapURL: string|null, sourceMapWriteTo: string|null, outputSourceFiles: bool, sourceMapRootpath: string, sourceMapBasepath: string}
*/
protected $defaultOptions = [
// an optional source root, useful for relocating source files
@@ -73,7 +69,6 @@ class SourceMapGenerator
* Array of mappings
*
* @var array
* @phpstan-var list<array{generated_line: int, generated_column: int, original_line: int, original_column: int, source_file: string}>
*/
protected $mappings = [];
@@ -87,40 +82,30 @@ class SourceMapGenerator
/**
* File to content map
*
* @var array<string, string>
* @var array
*/
protected $sources = [];
/**
* @var array<string, int>
*/
protected $sourceKeys = [];
/**
* @var array
* @phpstan-var array{sourceRoot: string, sourceMapFilename: string|null, sourceMapURL: string|null, sourceMapWriteTo: string|null, outputSourceFiles: bool, sourceMapRootpath: string, sourceMapBasepath: string}
*/
private $options;
/**
* @phpstan-param array{sourceRoot?: string, sourceMapFilename?: string|null, sourceMapURL?: string|null, sourceMapWriteTo?: string|null, outputSourceFiles?: bool, sourceMapRootpath?: string, sourceMapBasepath?: string} $options
*/
public function __construct(array $options = [])
{
$this->options = array_replace($this->defaultOptions, $options);
$this->options = array_merge($this->defaultOptions, $options);
$this->encoder = new Base64VLQ();
}
/**
* Adds a mapping
*
* @param int $generatedLine The line number in generated file
* @param int $generatedColumn The column number in generated file
* @param int $originalLine The line number in original file
* @param int $originalColumn The column number in original file
* @param string $sourceFile The original source file
*
* @return void
* @param integer $generatedLine The line number in generated file
* @param integer $generatedColumn The column number in generated file
* @param integer $originalLine The line number in original file
* @param integer $originalColumn The column number in original file
* @param string $sourceFile The original source file
*/
public function addMapping($generatedLine, $generatedColumn, $originalLine, $originalColumn, $sourceFile)
{
@@ -140,16 +125,14 @@ class SourceMapGenerator
*
* @param string $content The content to write
*
* @return string|null
* @return string
*
* @throws \ScssPhp\ScssPhp\Exception\CompilerException If the file could not be saved
* @deprecated
*/
public function saveMap($content)
{
$file = $this->options['sourceMapWriteTo'];
assert($file !== null);
$dir = \dirname($file);
$dir = dirname($file);
// directory does not exist
if (! is_dir($dir)) {
@@ -170,16 +153,14 @@ class SourceMapGenerator
/**
* Generates the JSON source map
*
* @param string $prefix A prefix added in the output file, which needs to shift mappings
*
* @return string
*
* @see https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit#
*/
public function generateJson($prefix = '')
public function generateJson()
{
$sourceMap = [];
$mappings = $this->generateMappings($prefix);
$mappings = $this->generateMappings();
// File version (always the first entry in the object) and must be a positive integer.
$sourceMap['version'] = self::VERSION;
@@ -202,7 +183,7 @@ class SourceMapGenerator
// A list of original sources used by the 'mappings' entry.
$sourceMap['sources'] = [];
foreach ($this->sources as $sourceFilename) {
foreach ($this->sources as $sourceUri => $sourceFilename) {
$sourceMap['sources'][] = $this->normalizeFilename($sourceFilename);
}
@@ -220,25 +201,17 @@ class SourceMapGenerator
}
// less.js compat fixes
if (\count($sourceMap['sources']) && empty($sourceMap['sourceRoot'])) {
if (count($sourceMap['sources']) && empty($sourceMap['sourceRoot'])) {
unset($sourceMap['sourceRoot']);
}
$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;
return json_encode($sourceMap, JSON_UNESCAPED_SLASHES);
}
/**
* Returns the sources contents
*
* @return string[]|null
* @return array|null
*/
protected function getSourcesContent()
{
@@ -258,21 +231,14 @@ class SourceMapGenerator
/**
* Generates the mappings string
*
* @param string $prefix A prefix added in the output file, which needs to shift mappings
*
* @return string
*/
public function generateMappings($prefix = '')
public function generateMappings()
{
if (! \count($this->mappings)) {
if (! count($this->mappings)) {
return '';
}
$prefixLines = substr_count($prefix, "\n");
$lastPrefixNewLine = strrpos($prefix, "\n");
$lastPrefixLineStart = false === $lastPrefixNewLine ? 0 : $lastPrefixNewLine + 1;
$prefixColumn = strlen($prefix) - $lastPrefixLineStart;
$this->sourceKeys = array_flip(array_keys($this->sources));
// group mappings by generated line number.
@@ -283,16 +249,9 @@ class SourceMapGenerator
}
ksort($groupedMap);
$lastGeneratedLine = $lastOriginalIndex = $lastOriginalLine = $lastOriginalColumn = 0;
foreach ($groupedMap as $lineNumber => $lineMap) {
if ($lineNumber > 1) {
// The prefix only impacts the column for the first line of the original output
$prefixColumn = 0;
}
$lineNumber += $prefixLines;
while (++$lastGeneratedLine < $lineNumber) {
$groupedMapEncoded[] = ';';
}
@@ -301,10 +260,8 @@ class SourceMapGenerator
$lastGeneratedColumn = 0;
foreach ($lineMap as $m) {
$generatedColumn = $m['generated_column'] + $prefixColumn;
$mapEncoded = $this->encoder->encode($generatedColumn - $lastGeneratedColumn);
$lastGeneratedColumn = $generatedColumn;
$mapEncoded = $this->encoder->encode($m['generated_column'] - $lastGeneratedColumn);
$lastGeneratedColumn = $m['generated_column'];
// find the index
if ($m['source_file']) {
@@ -335,7 +292,7 @@ class SourceMapGenerator
*
* @param string $filename
*
* @return int|false
* @return integer|false
*/
protected function findFileIndex($filename)
{
@@ -356,8 +313,8 @@ class SourceMapGenerator
$basePath = $this->options['sourceMapBasepath'];
// "Trim" the 'sourceMapBasepath' from the output filename.
if (\strlen($basePath) && strpos($filename, $basePath) === 0) {
$filename = substr($filename, \strlen($basePath));
if (strlen($basePath) && strpos($filename, $basePath) === 0) {
$filename = substr($filename, strlen($basePath));
}
// Remove extra leading path separators.
@@ -371,8 +328,8 @@ class SourceMapGenerator
/**
* Fix windows paths
*
* @param string $path
* @param bool $addEndSlash
* @param string $path
* @param boolean $addEndSlash
*
* @return string
*/

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -19,190 +18,52 @@ namespace ScssPhp\ScssPhp;
*/
class Type
{
/**
* @internal
*/
const T_ASSIGN = 'assign';
/**
* @internal
*/
const T_AT_ROOT = 'at-root';
/**
* @internal
*/
const T_BLOCK = 'block';
/**
* @deprecated
* @internal
*/
const T_BREAK = 'break';
/**
* @internal
*/
const T_CHARSET = 'charset';
const T_COLOR = 'color';
/**
* @internal
*/
const T_COMMENT = 'comment';
/**
* @deprecated
* @internal
*/
const T_CONTINUE = 'continue';
/**
* @deprecated
* @internal
*/
const T_CONTROL = 'control';
/**
* @internal
*/
const T_CUSTOM_PROPERTY = 'custom';
/**
* @internal
*/
const T_DEBUG = 'debug';
/**
* @internal
*/
const T_DIRECTIVE = 'directive';
/**
* @internal
*/
const T_EACH = 'each';
/**
* @internal
*/
const T_ELSE = 'else';
/**
* @internal
*/
const T_ELSEIF = 'elseif';
/**
* @internal
*/
const T_ERROR = 'error';
/**
* @internal
*/
const T_EXPRESSION = 'exp';
/**
* @internal
*/
const T_EXTEND = 'extend';
/**
* @internal
*/
const T_FOR = 'for';
const T_FUNCTION = 'function';
/**
* @internal
*/
const T_FUNCTION_REFERENCE = 'function-reference';
/**
* @internal
*/
const T_FUNCTION_CALL = 'fncall';
/**
* @internal
*/
const T_HSL = 'hsl';
/**
* @internal
*/
const T_HWB = 'hwb';
/**
* @internal
*/
const T_IF = 'if';
/**
* @internal
*/
const T_IMPORT = 'import';
/**
* @internal
*/
const T_INCLUDE = 'include';
/**
* @internal
*/
const T_INTERPOLATE = 'interpolate';
/**
* @internal
*/
const T_INTERPOLATED = 'interpolated';
/**
* @internal
*/
const T_KEYWORD = 'keyword';
const T_LIST = 'list';
const T_MAP = 'map';
/**
* @internal
*/
const T_MEDIA = 'media';
/**
* @internal
*/
const T_MEDIA_EXPRESSION = 'mediaExp';
/**
* @internal
*/
const T_MEDIA_TYPE = 'mediaType';
/**
* @internal
*/
const T_MEDIA_VALUE = 'mediaValue';
/**
* @internal
*/
const T_MIXIN = 'mixin';
/**
* @internal
*/
const T_MIXIN_CONTENT = 'mixin_content';
/**
* @internal
*/
const T_NESTED_PROPERTY = 'nestedprop';
/**
* @internal
*/
const T_NOT = 'not';
const T_NULL = 'null';
const T_NUMBER = 'number';
/**
* @internal
*/
const T_RETURN = 'return';
/**
* @internal
*/
const T_ROOT = 'root';
/**
* @internal
*/
const T_SCSSPHP_IMPORT_ONCE = 'scssphp-import-once';
/**
* @internal
*/
const T_SELF = 'self';
const T_STRING = 'string';
/**
* @internal
*/
const T_UNARY = 'unary';
/**
* @internal
*/
const T_VARIABLE = 'var';
/**
* @internal
*/
const T_WARN = 'warn';
/**
* @internal
*/
const T_WHILE = 'while';
}

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -14,14 +13,11 @@ namespace ScssPhp\ScssPhp;
use ScssPhp\ScssPhp\Base\Range;
use ScssPhp\ScssPhp\Exception\RangeException;
use ScssPhp\ScssPhp\Node\Number;
/**
* Utility functions
* Utilty functions
*
* @author Anthon Pang <anthon.pang@gmail.com>
*
* @internal
*/
class Util
{
@@ -29,10 +25,10 @@ class Util
* Asserts that `value` falls within `range` (inclusive), leaving
* room for slight floating-point errors.
*
* @param string $name The name of the value. Used in the error message.
* @param Range $range Range of values.
* @param array|Number $value The value to check.
* @param string $unit The unit of the value. Used in error reporting.
* @param string $name The name of the value. Used in the error message.
* @param \ScssPhp\ScssPhp\Base\Range $range Range of values.
* @param array $value The value to check.
* @param string $unit The unit of the value. Used in error reporting.
*
* @return mixed `value` adjusted to fall within range, if it was outside by a floating-point margin.
*
@@ -43,10 +39,6 @@ class Util
$val = $value[1];
$grace = new Range(-0.00001, 0.00001);
if (! \is_numeric($val)) {
throw new RangeException("$name {$val} is not a number.");
}
if ($range->includes($val)) {
return $val;
}
@@ -75,110 +67,4 @@ class Util
return strtr(rawurlencode($string), $revert);
}
/**
* mb_chr() wrapper
*
* @param int $code
*
* @return string
*/
public static function mbChr($code)
{
// Use the native implementation if available, but not on PHP 7.2 as mb_chr(0) is buggy there
if (\PHP_VERSION_ID > 70300 && \function_exists('mb_chr')) {
return mb_chr($code, 'UTF-8');
}
if (0x80 > $code %= 0x200000) {
$s = \chr($code);
} elseif (0x800 > $code) {
$s = \chr(0xC0 | $code >> 6) . \chr(0x80 | $code & 0x3F);
} elseif (0x10000 > $code) {
$s = \chr(0xE0 | $code >> 12) . \chr(0x80 | $code >> 6 & 0x3F) . \chr(0x80 | $code & 0x3F);
} else {
$s = \chr(0xF0 | $code >> 18) . \chr(0x80 | $code >> 12 & 0x3F)
. \chr(0x80 | $code >> 6 & 0x3F) . \chr(0x80 | $code & 0x3F);
}
return $s;
}
/**
* mb_strlen() wrapper
*
* @param string $string
* @return int
*/
public static function mbStrlen($string)
{
// Use the native implementation if available.
if (\function_exists('mb_strlen')) {
return mb_strlen($string, 'UTF-8');
}
if (\function_exists('iconv_strlen')) {
return (int) @iconv_strlen($string, 'UTF-8');
}
throw new \LogicException('Either mbstring (recommended) or iconv is necessary to use Scssphp.');
}
/**
* mb_substr() wrapper
* @param string $string
* @param int $start
* @param null|int $length
* @return string
*/
public static function mbSubstr($string, $start, $length = null)
{
// Use the native implementation if available.
if (\function_exists('mb_substr')) {
return mb_substr($string, $start, $length, 'UTF-8');
}
if (\function_exists('iconv_substr')) {
if ($start < 0) {
$start = static::mbStrlen($string) + $start;
if ($start < 0) {
$start = 0;
}
}
if (null === $length) {
$length = 2147483647;
} elseif ($length < 0) {
$length = static::mbStrlen($string) + $length - $start;
if ($length < 0) {
return '';
}
}
return (string)iconv_substr($string, $start, $length, 'UTF-8');
}
throw new \LogicException('Either mbstring (recommended) or iconv is necessary to use Scssphp.');
}
/**
* mb_strpos wrapper
* @param string $haystack
* @param string $needle
* @param int $offset
*
* @return int|false
*/
public static function mbStrpos($haystack, $needle, $offset = 0)
{
if (\function_exists('mb_strpos')) {
return mb_strpos($haystack, $needle, $offset, 'UTF-8');
}
if (\function_exists('iconv_strpos')) {
return iconv_strpos($haystack, $needle, $offset, 'UTF-8');
}
throw new \LogicException('Either mbstring (recommended) or iconv is necessary to use Scssphp.');
}
}

View File

@@ -1,77 +0,0 @@
<?php
namespace ScssPhp\ScssPhp\Util;
/**
* @internal
*/
class Path
{
/**
* @param string $path
*
* @return bool
*/
public static function isAbsolute($path)
{
if ($path === '') {
return false;
}
if ($path[0] === '/') {
return true;
}
if (\DIRECTORY_SEPARATOR !== '\\') {
return false;
}
if ($path[0] === '\\') {
return true;
}
if (\strlen($path) < 3) {
return false;
}
if ($path[1] !== ':') {
return false;
}
if ($path[2] !== '/' && $path[2] !== '\\') {
return false;
}
if (!preg_match('/^[A-Za-z]$/', $path[0])) {
return false;
}
return true;
}
/**
* @param string $part1
* @param string $part2
*
* @return string
*/
public static function join($part1, $part2)
{
if ($part1 === '' || self::isAbsolute($part2)) {
return $part2;
}
if ($part2 === '') {
return $part1;
}
$last = $part1[\strlen($part1) - 1];
$separator = \DIRECTORY_SEPARATOR;
if ($last === '/' || $last === \DIRECTORY_SEPARATOR) {
$separator = '';
}
return $part1 . $separator . $part2;
}
}

View File

@@ -1,95 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp;
use ScssPhp\ScssPhp\Node\Number;
final class ValueConverter
{
// Prevent instantiating it
private function __construct()
{
}
/**
* Parses a value from a Scss source string.
*
* The returned value is guaranteed to be supported by the
* Compiler methods for registering custom variables. No other
* guarantee about it is provided. It should be considered
* opaque values by the caller.
*
* @param string $source
*
* @return mixed
*/
public static function parseValue($source)
{
$parser = new Parser(__CLASS__);
if (!$parser->parseValue($source, $value)) {
throw new \InvalidArgumentException(sprintf('Invalid value source "%s".', $source));
}
return $value;
}
/**
* Converts a PHP value to a Sass value
*
* The returned value is guaranteed to be supported by the
* Compiler methods for registering custom variables. No other
* guarantee about it is provided. It should be considered
* opaque values by the caller.
*
* @param mixed $value
*
* @return mixed
*/
public static function fromPhp($value)
{
if ($value instanceof Number) {
return $value;
}
if (is_array($value) && isset($value[0]) && \in_array($value[0], [Type::T_NULL, Type::T_COLOR, Type::T_KEYWORD, Type::T_LIST, Type::T_MAP, Type::T_STRING])) {
return $value;
}
if ($value === null) {
return Compiler::$null;
}
if ($value === true) {
return Compiler::$true;
}
if ($value === false) {
return Compiler::$false;
}
if ($value === '') {
return Compiler::$emptyString;
}
if (\is_int($value) || \is_float($value)) {
return new Number($value, '');
}
if (\is_string($value)) {
return [Type::T_STRING, '"', [$value]];
}
throw new \InvalidArgumentException(sprintf('Cannot convert the value of type "%s" to a Sass value.', gettype($value)));
}
}

View File

@@ -1,9 +1,8 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
* @copyright 2012-2019 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
@@ -19,5 +18,5 @@ namespace ScssPhp\ScssPhp;
*/
class Version
{
const VERSION = '1.10.2';
const VERSION = 'v1.0.6';
}

View File

@@ -1,84 +0,0 @@
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp;
final class Warn
{
/**
* @var callable|null
* @phpstan-var (callable(string, bool): void)|null
*/
private static $callback;
/**
* Prints a warning message associated with the current `@import` or function call.
*
* This may only be called within a custom function or importer callback.
*
* @param string $message
*
* @return void
*/
public static function warning($message)
{
self::reportWarning($message, false);
}
/**
* Prints a deprecation warning message associated with the current `@import` or function call.
*
* This may only be called within a custom function or importer callback.
*
* @param string $message
*
* @return void
*/
public static function deprecation($message)
{
self::reportWarning($message, true);
}
/**
* @param callable|null $callback
*
* @return callable|null The previous warn callback
*
* @phpstan-param (callable(string, bool): void)|null $callback
*
* @phpstan-return (callable(string, bool): void)|null
*
* @internal
*/
public static function setCallback(callable $callback = null)
{
$previousCallback = self::$callback;
self::$callback = $callback;
return $previousCallback;
}
/**
* @param string $message
* @param bool $deprecation
*
* @return void
*/
private static function reportWarning($message, $deprecation)
{
if (self::$callback === null) {
throw new \BadMethodCallException('The warning Reporter may only be called within a custom function or importer callback.');
}
\call_user_func(self::$callback, $message, $deprecation);
}
}