From a070856a488e19df6b65e83b1ac5c71e37c19d83 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Sun, 13 Dec 2015 01:24:06 -0500 Subject: [PATCH 001/329] fixes #304 - implement @extend !optional --- src/Compiler.php | 41 +++++++++++++++++++++++++----- src/Parser.php | 29 +++++++++++++++++++-- tests/ExceptionTest.php | 8 ++++++ tests/inputs/extends.scss | 4 +++ tests/outputs_numbered/extends.css | 1 + 5 files changed, 75 insertions(+), 8 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index a08f1ba6..5e6c11d5 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -238,17 +238,18 @@ protected function isSelfExtend($target, $origin) /** * Push extends * - * @param array $target - * @param array $origin + * @param array $target + * @param array $origin + * @param \stdClass $block */ - protected function pushExtends($target, $origin) + protected function pushExtends($target, $origin, $block) { if ($this->isSelfExtend($target, $origin)) { return; } $i = count($this->extends); - $this->extends[] = array($target, $origin); + $this->extends[] = array($target, $origin, $block); foreach ($target as $part) { if (isset($this->extendsMap[$part])) { @@ -291,6 +292,32 @@ protected function compileRoot(Block $rootBlock) $this->compileChildrenNoReturn($rootBlock->children, $this->scope); $this->flattenSelectors($this->scope); + $this->missingSelectors(); + } + + /** + * Report missing selectors + */ + protected function missingSelectors() + { + foreach ($this->extends as $extend) { + if (isset($extend[3])) { + continue; + } + + list($target, $origin, $block) = $extend; + + // ignore if !optional + if ($block[2]) { + continue; + } + + $target = implode(' ', $target); + $origin = $this->collapseSelectors($origin); + + $this->sourceLine = $block[Parser::SOURCE_LINE]; + $this->throwError("\"$origin\" failed to @extend \"$target\". The selector \"$target\" was not found."); + } } /** @@ -451,13 +478,15 @@ protected function matchExtendsSingle($rawSingle, &$outOrigin) $found = false; foreach ($counts as $idx => $count) { - list($target, $origin) = $this->extends[$idx]; + list($target, $origin, $block) = $this->extends[$idx]; // check count if ($count !== count($target)) { continue; } + $this->extends[$idx][3] = true; + $rem = array_diff($single, $target); foreach ($origin as $j => $new) { @@ -1504,7 +1533,7 @@ protected function compileChild($child, OutputBlock $out) // only use the first one $result = current($result); - $this->pushExtends($result, $out->selectors); + $this->pushExtends($result, $out->selectors, $child); } } break; diff --git a/src/Parser.php b/src/Parser.php index 7bf6c8f3..b543f182 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -349,10 +349,12 @@ protected function parseChunk() $this->seek($s); if ($this->literal('@extend') && - $this->selectors($selector) && + $this->selectors($selectors) && $this->end() ) { - $this->append(array(Type::T_EXTEND, $selector), $s); + // check for '!flag' + $optional = $this->stripOptionalFlag($selectors); + $this->append(array(Type::T_EXTEND, $selectors, $optional), $s); return true; } @@ -2326,6 +2328,29 @@ protected function stripAssignmentFlag(&$value) return false; } + /** + * Strip optional flag from selector list + * + * @param array $selectors + * + * @return string + */ + protected function stripOptionalFlag(&$selectors) + { + $optional = false; + + $selector = end($selectors); + $part = end($selector); + + if ($part === array('!optional')) { + array_pop($selectors[count($selectors) - 1]); + + $optional = true; + } + + return $optional; + } + /** * Turn list of length 1 into value type * diff --git a/tests/ExceptionTest.php b/tests/ExceptionTest.php index 4406c523..f5fa17a5 100644 --- a/tests/ExceptionTest.php +++ b/tests/ExceptionTest.php @@ -131,6 +131,14 @@ public function provideScss() , 'isn\'t a valid CSS value' ), + array(<<<'END_OF_SCSS' +a.important { + @extend .notice; +} +END_OF_SCSS + , + 'was not found' + ), ); } diff --git a/tests/inputs/extends.scss b/tests/inputs/extends.scss index 315f25ea..9da03502 100644 --- a/tests/inputs/extends.scss +++ b/tests/inputs/extends.scss @@ -281,3 +281,7 @@ $var: ".selector1, .selector2"; } } } + +a.important { + @extend .notice !optional; +} diff --git a/tests/outputs_numbered/extends.css b/tests/outputs_numbered/extends.css index 935d1033..5d76d9d3 100644 --- a/tests/outputs_numbered/extends.css +++ b/tests/outputs_numbered/extends.css @@ -200,3 +200,4 @@ body .to-extend, body .test { /* line 278, inputs/extends.scss */ .main .block__element--modifier { font-weight: bold; } +/* line 285, inputs/extends.scss */ From adfc2cf537e3fbe07d1d48fcf184c13460e1f218 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Sun, 13 Dec 2015 02:30:32 -0500 Subject: [PATCH 002/329] fixes #301 - implement keywords() --- src/Compiler.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Compiler.php b/src/Compiler.php index 5e6c11d5..2eac200b 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -4687,6 +4687,22 @@ protected function libMapMerge($args) return array(Type::T_MAP, array_merge($map1[1], $map2[1]), array_merge($map1[2], $map2[2])); } + protected static $libKeywords = array('args'); + protected function libKeywords($args) + { + $this->assertList($args[0]); + + $keys = array(); + $values = array(); + + foreach ($args[0][2] as $name => $arg) { + $keys[] = array(Type::T_KEYWORD, $name); + $values[] = $arg; + } + + return array(Type::T_MAP, $keys, $values); + } + protected function listSeparatorForJoin($list1, $sep) { if (! isset($sep)) { From fc8c73b7955b22b40792d716d42c8daa5b43a777 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Sun, 13 Dec 2015 03:03:38 -0500 Subject: [PATCH 003/329] Bump version to v0.6.1 --- src/Version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Version.php b/src/Version.php index a47062b1..ef096e94 100644 --- a/src/Version.php +++ b/src/Version.php @@ -18,5 +18,5 @@ */ class Version { - const VERSION = 'v0.6.0'; + const VERSION = 'v0.6.1'; } From 317a7b31b49ae442cb70706456d36a5eef45d38b Mon Sep 17 00:00:00 2001 From: Marat Tanalin Date: Mon, 14 Dec 2015 01:10:30 +0300 Subject: [PATCH 004/329] Added `rebeccapurple` named color It is supported by all current major browsers. Some details: * https://drafts.csswg.org/css-color/#valdef-color-rebeccapurple * http://codepen.io/trezy/post/honoring-a-great-man --- src/Colors.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Colors.php b/src/Colors.php index 0227fbe0..d1a75949 100644 --- a/src/Colors.php +++ b/src/Colors.php @@ -145,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', From d27d49229c17b42f4d9b055d41984b62df9fcbb3 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Sun, 13 Dec 2015 20:03:25 -0500 Subject: [PATCH 005/329] phpcs tweak --- src/Colors.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Colors.php b/src/Colors.php index d1a75949..e3936a5f 100644 --- a/src/Colors.php +++ b/src/Colors.php @@ -174,6 +174,6 @@ class Colors 'white' => '255,255,255', 'whitesmoke' => '245,245,245', 'yellow' => '255,255,0', - 'yellowgreen' => '154,205,50' + 'yellowgreen' => '154,205,50', ); } From 3eaa3f8df021f3dcbe19f814540c941308a9668f Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Sun, 13 Dec 2015 20:43:36 -0500 Subject: [PATCH 006/329] fixes #303 - implement inspect($value) built-in --- src/Compiler.php | 11 +++++++++++ tests/inputs/functions.scss | 14 ++++++++++++++ tests/outputs/functions.css | 13 +++++++++++++ tests/outputs_numbered/functions.css | 13 +++++++++++++ 4 files changed, 51 insertions(+) diff --git a/src/Compiler.php b/src/Compiler.php index 2eac200b..57ec4d65 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -4999,6 +4999,7 @@ protected function libCounter($args) return array(Type::T_STRING, '', array('counter(' . implode(',', $list) . ')')); } + protected static $libRandom = array('limit'); protected function libRandom($args) { if (isset($args[0])) { @@ -5028,4 +5029,14 @@ protected function libUniqueId() return array(Type::T_STRING, '', array('u' . str_pad(base_convert($id, 10, 36), 8, '0', STR_PAD_LEFT))); } + + protected static $libInspect = array('value'); + protected function libInspect($args) + { + if ($args[0] === self::$null) { + return array(Type::T_KEYWORD, 'null'); + } + + return $args[0]; + } } diff --git a/tests/inputs/functions.scss b/tests/inputs/functions.scss index 4886a6e5..bcceaffd 100644 --- a/tests/inputs/functions.scss +++ b/tests/inputs/functions.scss @@ -114,3 +114,17 @@ $str: 'global'; @include test-mixin; display: $str; } + +.test-inspect { + n: inspect(null); + b1: inspect(true); + b2: inspect(false); + n1: inspect(0); + s1: inspect(''); + s2: inspect('hello'); + l1: inspect(1 2); + l2: inspect((3 4)); + l3: inspect((5,6)); + l4: inspect((a: 1, b: 2)); + l5: inspect($value: (a: 1, b: 2)); +} diff --git a/tests/outputs/functions.css b/tests/outputs/functions.css index 9604accb..252e3909 100644 --- a/tests/outputs/functions.css +++ b/tests/outputs/functions.css @@ -32,3 +32,16 @@ p { display: 'test-mixin'; display: 'test-mixin'; display: 'global'; } + +.test-inspect { + n: null; + b1: true; + b2: false; + n1: 0; + s1: ''; + s2: 'hello'; + l1: 1 2; + l2: 3 4; + l3: 5, 6; + l4: (a: 1, b: 2); + l5: (a: 1, b: 2); } diff --git a/tests/outputs_numbered/functions.css b/tests/outputs_numbered/functions.css index 4949511a..9b525e8d 100644 --- a/tests/outputs_numbered/functions.css +++ b/tests/outputs_numbered/functions.css @@ -34,3 +34,16 @@ p { display: 'test-mixin'; display: 'test-mixin'; display: 'global'; } +/* line 118, inputs/functions.scss */ +.test-inspect { + n: null; + b1: true; + b2: false; + n1: 0; + s1: ''; + s2: 'hello'; + l1: 1 2; + l2: 3 4; + l3: 5, 6; + l4: (a: 1, b: 2); + l5: (a: 1, b: 2); } From 493e05a95431e0cbb3ed6cbca65e07e6e443e19e Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Tue, 15 Dec 2015 13:41:21 -0500 Subject: [PATCH 007/329] support unicode characters in scss indentifers --- src/Parser.php | 10 +++++----- tests/inputs/variables.scss | 7 +++++++ tests/outputs/variables.css | 3 +++ tests/outputs_numbered/variables.css | 3 +++ 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/Parser.php b/src/Parser.php index b543f182..a0986136 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -85,7 +85,7 @@ public function __construct($sourceName, $sourceIndex = 0) $commentMultiRight = '\*\/'; self::$commentPattern = $commentMultiLeft . '.*?' . $commentMultiRight; - self::$whitePattern = '/' . $commentSingle . '[^\n]*\s*|(' . self::$commentPattern . ')\s*|\s+/Ais'; + self::$whitePattern = '/' . $commentSingle . '[^\n]*\s*|(' . self::$commentPattern . ')\s*|\s+/AisuS'; } } @@ -762,7 +762,7 @@ protected function peek($regex, &$out, $from = null) $from = $this->count; } - $r = '/' . $regex . '/Ais'; + $r = '/' . $regex . '/Aisu'; $result = preg_match($r, $this->buffer, $out, null, $from); return $result; @@ -842,7 +842,7 @@ protected function match($regex, &$out, $eatWhitespace = null) $eatWhitespace = $this->eatWhiteDefault; } - $r = '/' . $regex . '/Ais'; + $r = '/' . $regex . '/Aisu'; if (preg_match($r, $this->buffer, $out, null, $this->count)) { $this->count += strlen($out[0]); @@ -2235,7 +2235,7 @@ protected function variable(&$out) protected function keyword(&$word, $eatWhitespace = null) { if ($this->match( - '(([\w_\-\*!"\']|[\\\\].)([\w\-_"\']|[\\\\].)*)', + '(([\pL\w_\-\*!"\']|[\\\\].)([\pL\w\-_"\']|[\\\\].)*)', $m, $eatWhitespace )) { @@ -2256,7 +2256,7 @@ protected function keyword(&$word, $eatWhitespace = null) */ protected function placeholder(&$placeholder) { - if ($this->match('([\w\-_]+|#[{][$][\w\-_]+[}])', $m)) { + if ($this->match('([\pL\w\-_]+|#[{][$][\pL\w\-_]+[}])', $m)) { $placeholder = $m[1]; return true; diff --git a/tests/inputs/variables.scss b/tests/inputs/variables.scss index 367416fc..53149e6e 100644 --- a/tests/inputs/variables.scss +++ b/tests/inputs/variables.scss @@ -73,3 +73,10 @@ A { @include example; color: $color; } + +$коммент : #000; + +body +{ + color: $коммент ; +} diff --git a/tests/outputs/variables.css b/tests/outputs/variables.css index 693ee6ef..ed3e6b21 100644 --- a/tests/outputs/variables.css +++ b/tests/outputs/variables.css @@ -31,3 +31,6 @@ body { A { color: green; } + +body { + color: #000; } diff --git a/tests/outputs_numbered/variables.css b/tests/outputs_numbered/variables.css index f341c52f..206fa249 100644 --- a/tests/outputs_numbered/variables.css +++ b/tests/outputs_numbered/variables.css @@ -34,3 +34,6 @@ body { /* line 71, inputs/variables.scss */ A { color: green; } +/* line 79, inputs/variables.scss */ +body { + color: #000; } From 4ac664e32bd68833e69d88f0f1568239f7731113 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Tue, 15 Dec 2015 13:51:36 -0500 Subject: [PATCH 008/329] tweak tests --- tests/inputs/comments.scss | 4 ++++ tests/inputs/variables.scss | 4 ++-- tests/outputs/comments.css | 1 + tests/outputs_numbered/comments.css | 1 + 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/inputs/comments.scss b/tests/inputs/comments.scss index 80ab6c73..3e641cc1 100644 --- a/tests/inputs/comments.scss +++ b/tests/inputs/comments.scss @@ -41,4 +41,8 @@ a { } /* comment 7 */ +/* коммент */ + +// коммент + // end diff --git a/tests/inputs/variables.scss b/tests/inputs/variables.scss index 53149e6e..5212c385 100644 --- a/tests/inputs/variables.scss +++ b/tests/inputs/variables.scss @@ -74,9 +74,9 @@ A { color: $color; } -$коммент : #000; +$цвет : #000; body { - color: $коммент ; + color: $цвет; } diff --git a/tests/outputs/comments.css b/tests/outputs/comments.css index 6535554c..f6f8d184 100644 --- a/tests/outputs/comments.css +++ b/tests/outputs/comments.css @@ -29,3 +29,4 @@ a { /* comment 5 */ /* comment 6 */ } /* comment 7 */ +/* коммент */ diff --git a/tests/outputs_numbered/comments.css b/tests/outputs_numbered/comments.css index 6226d416..3669d1d8 100644 --- a/tests/outputs_numbered/comments.css +++ b/tests/outputs_numbered/comments.css @@ -31,3 +31,4 @@ a { /* comment 5 */ /* comment 6 */ } /* comment 7 */ +/* коммент */ From dbca8da31c3cfd5cfd9c7b2c5a0a74310fc248ae Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Tue, 15 Dec 2015 16:56:25 -0500 Subject: [PATCH 009/329] fixes #395 - bin/pscss: add --iso8859-1 option; defaults to utf-8 (slower but more compatible with ruby scss) --- bin/pscss | 11 +++++++++++ src/Compiler.php | 15 ++++++++++++++- src/Parser.php | 24 ++++++++++++++++++------ 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/bin/pscss b/bin/pscss index 16a12039..3175ea0b 100755 --- a/bin/pscss +++ b/bin/pscss @@ -31,6 +31,7 @@ $changeDir = false; $debugInfo = false; $lineNumbers = false; $ignoreErrors = false; +$encoding = false; /** * Parse argument @@ -73,6 +74,7 @@ Options include: --debug-info Annotate selectors with CSS referring to the source file and line number -f=format Set the output format (compact, compressed, crunched, expanded, or nested) -i=path Set import path + --iso8859-1 Use iso8859-1 encoding instead of utf-8 (default utf-8) --line-numbers Annotate selectors with comments referring to the source file and line number -p=precision Set decimal number precision (default 5) -T Dump formatted parse tree @@ -96,6 +98,11 @@ EOT; continue; } + if ($argv[$i] === '--iso8859-1') { + $encoding = 'iso8859-1'; + continue; + } + if ($argv[$i] === '--line-numbers' || $argv[$i] === '--line-comments') { $lineNumbers = true; continue; @@ -186,6 +193,10 @@ if ($style) { $scss->setFormatter('Leafo\\ScssPhp\\Formatter\\' . ucfirst($style)); } +if ($encoding) { + $scss->setEncoding($encoding); +} + echo $scss->compile($data, $inputFile); if ($changeDir) { diff --git a/src/Compiler.php b/src/Compiler.php index 57ec4d65..f55e1d7c 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -117,6 +117,7 @@ class Compiler 'global-variable-shadowing' => false, ); + protected $encoding = null; protected $lineNumberStyle = null; protected $formatter = 'Leafo\ScssPhp\Formatter\Nested'; @@ -208,7 +209,7 @@ public function compile($code, $path = null) */ private function parserFactory($path) { - $parser = new Parser($path, count($this->sourceNames)); + $parser = new Parser($path, count($this->sourceNames), $this->encoding); $this->sourceNames[] = $path; $this->addParsedFile($path); @@ -3239,6 +3240,18 @@ public function findImport($url) return null; } + /** + * Set encoding + * + * @api + * + * @param string $encoding + */ + public function setEncoding($encoding) + { + $this->encoding = $encoding; + } + /** * Ignore errors? * diff --git a/src/Parser.php b/src/Parser.php index a0986136..ac542dc4 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -62,6 +62,7 @@ class Parser private $inParens; private $eatWhiteDefault; private $buffer; + private $utf8; /** * Constructor @@ -70,12 +71,14 @@ class Parser * * @param string $sourceName * @param integer $sourceIndex + * @param string $encoding */ - public function __construct($sourceName, $sourceIndex = 0) + public function __construct($sourceName, $sourceIndex = 0, $encoding = 'utf-8') { $this->sourceName = $sourceName ?: '(stdin)'; $this->sourceIndex = $sourceIndex; $this->charset = null; + $this->utf8 = ! $encoding || strtolower($encoding) === 'utf-8'; if (empty(self::$operatorPattern)) { self::$operatorPattern = '([*\/%+-]|[!=]\=|\>\=?|\<\=\>|\<\=?|and|or)'; @@ -85,7 +88,9 @@ public function __construct($sourceName, $sourceIndex = 0) $commentMultiRight = '\*\/'; self::$commentPattern = $commentMultiLeft . '.*?' . $commentMultiRight; - self::$whitePattern = '/' . $commentSingle . '[^\n]*\s*|(' . self::$commentPattern . ')\s*|\s+/AisuS'; + self::$whitePattern = $this->utf8 + ? '/' . $commentSingle . '[^\n]*\s*|(' . self::$commentPattern . ')\s*|\s+/AisuS' + : '/' . $commentSingle . '[^\n]*\s*|(' . self::$commentPattern . ')\s*|\s+/AisS'; } } @@ -762,7 +767,7 @@ protected function peek($regex, &$out, $from = null) $from = $this->count; } - $r = '/' . $regex . '/Aisu'; + $r = $this->utf8 ? '/' . $regex . '/Aisu' : '/' . $regex . '/Ais'; $result = preg_match($r, $this->buffer, $out, null, $from); return $result; @@ -842,7 +847,7 @@ protected function match($regex, &$out, $eatWhitespace = null) $eatWhitespace = $this->eatWhiteDefault; } - $r = '/' . $regex . '/Aisu'; + $r = $this->utf8 ? '/' . $regex . '/Aisu' : '/' . $regex . '/Ais'; if (preg_match($r, $this->buffer, $out, null, $this->count)) { $this->count += strlen($out[0]); @@ -2235,7 +2240,9 @@ protected function variable(&$out) protected function keyword(&$word, $eatWhitespace = null) { if ($this->match( - '(([\pL\w_\-\*!"\']|[\\\\].)([\pL\w\-_"\']|[\\\\].)*)', + $this->utf8 + ? '(([\pL\w_\-\*!"\']|[\\\\].)([\pL\w\-_"\']|[\\\\].)*)' + : '(([\w_\-\*!"\']|[\\\\].)([\w\-_"\']|[\\\\].)*)', $m, $eatWhitespace )) { @@ -2256,7 +2263,12 @@ protected function keyword(&$word, $eatWhitespace = null) */ protected function placeholder(&$placeholder) { - if ($this->match('([\pL\w\-_]+|#[{][$][\pL\w\-_]+[}])', $m)) { + if ($this->match( + $this->utf8 + ? '([\pL\w\-_]+|#[{][$][\pL\w\-_]+[}])' + : '([\w\-_]+|#[{][$][\w\-_]+[}])', + $m + )) { $placeholder = $m[1]; return true; From 361faee948a150d4bb3623a67bb8efb98de2d33d Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Tue, 15 Dec 2015 17:03:18 -0500 Subject: [PATCH 010/329] rename Makefile target (conflict with tests/ folder) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d08ee190..b42e4a2b 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -tests: +test: vendor/bin/phpunit --colors tests compat: From b948673438b95e4bbf3fc55d3c1fec2d6f1cd8f4 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 16 Dec 2015 00:09:30 -0500 Subject: [PATCH 011/329] change die() to throw exception instead --- scss.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scss.inc.php b/scss.inc.php index d3720eb7..b6892fec 100644 --- a/scss.inc.php +++ b/scss.inc.php @@ -1,6 +1,6 @@ Date: Wed, 16 Dec 2015 00:41:13 -0500 Subject: [PATCH 012/329] fixes #394 - parser exception with mbstring.func_overload=2 and mbstring.internal_encoding=utf-8 --- src/Parser.php | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/src/Parser.php b/src/Parser.php index ac542dc4..68f205ae 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -63,6 +63,7 @@ class Parser private $eatWhiteDefault; private $buffer; private $utf8; + private $encoding; /** * Constructor @@ -119,7 +120,7 @@ public function throwParseError($msg = 'parse error') { list($line, $column) = $this->getSourcePosition($this->count); - $loc = empty($this->sourceName) ? "line: $line" : "$this->sourceName on line $line"; + $loc = empty($this->sourceName) ? "line: $line" : "$this->sourceName on line $line"; if ($this->peek("(.*?)(\n|$)", $m, $this->count)) { throw new ParserException("$msg: failed at `$m[1]` $loc"); @@ -145,6 +146,7 @@ public function parse($buffer) $this->eatWhiteDefault = true; $this->buffer = rtrim($buffer, "\x00..\x1f"); + $this->saveEncoding(); $this->extractLineNumbers($buffer); $this->pushBlock(null); // root block @@ -170,6 +172,8 @@ public function parse($buffer) $this->env->isRoot = true; + $this->restoreEncoding(); + return $this->env; } @@ -191,7 +195,13 @@ public function parseValue($buffer, &$out) $this->eatWhiteDefault = true; $this->buffer = (string) $buffer; - return $this->valueList($out); + $this->saveEncoding(); + + $list = $this->valueList($out); + + $this->restoreEncoding(); + + return $list; } /** @@ -212,7 +222,13 @@ public function parseSelector($buffer, &$out) $this->eatWhiteDefault = true; $this->buffer = (string) $buffer; - return $this->selectors($out); + $this->saveEncoding(); + + $selector = $this->selectors($out); + + $this->restoreEncoding(); + + return $selector; } /** @@ -2485,4 +2501,26 @@ private function getSourcePosition($pos) return array($low + 1, $pos - $this->sourcePositions[$low]); } + + /** + * Save internal encoding + */ + private function saveEncoding() + { + if (ini_get('mbstring.func_overload') & 2) { + $this->encoding = mb_internal_encoding(); + + mb_internal_encoding('iso-8859-1'); + } + } + + /** + * Restore internal encoding + */ + private function restoreEncoding() + { + if ($this->encoding) { + mb_internal_encoding($this->encoding); + } + } } From e7fa252c35a24d5a1beb418fc0f2360848edc812 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 16 Dec 2015 00:58:24 -0500 Subject: [PATCH 013/329] optimze attribute selector code --- src/Parser.php | 63 +++++++++++--------------------------------------- 1 file changed, 13 insertions(+), 50 deletions(-) diff --git a/src/Parser.php b/src/Parser.php index 68f205ae..5b72dafb 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -1461,7 +1461,7 @@ protected function func(&$func) $this->seek($ss); } - if (($this->openString(')', $str, '(') || true ) && + if (($this->openString(')', $str, '(') || true) && $this->literal(')') ) { $args = array(); @@ -2135,7 +2135,7 @@ protected function selectorSingle(&$out) $ss = $this->seek(); if ($this->literal('(') && - ($this->openString(')', $str, '(') || true ) && + ($this->openString(')', $str, '(') || true) && $this->literal(')') ) { $parts[] = '('; @@ -2155,60 +2155,23 @@ protected function selectorSingle(&$out) $this->seek($s); // attribute selector - // TODO: replace with open string? - if ($this->literal('[', false)) { - $attrParts = array('['); - - // keyword, string, operator - for (;;) { - if ($this->literal(']', false)) { - $this->count--; - break; // get out early - } - - if ($this->match('\s+', $m)) { - $attrParts[] = ' '; - continue; - } - - if ($this->string($str)) { - $attrParts[] = $str; - continue; - } - - if ($this->keyword($word)) { - $attrParts[] = $word; - continue; - } - - if ($this->interpolation($inter, false)) { - $attrParts[] = $inter; - continue; - } - - // operator, handles attr namespace too - if ($this->match('[|-~\$\*\^=]+', $m)) { - $attrParts[] = $m[0]; - continue; - } + if ($this->literal('[') && + ($this->openString(']', $str, '[') || true) && + $this->literal(']') + ) { + $parts[] = '['; - break; + if (! empty($str)) { + $parts[] = $str; } - if ($this->literal(']', false)) { - $attrParts[] = ']'; + $parts[] = ']'; - foreach ($attrParts as $part) { - $parts[] = $part; - } - - continue; - } - - $this->seek($s); - // TODO: should just break here? + continue; } + $this->seek($s); + break; } From 0f52e57cadd1d52a3d4c00ce27fd74f3df638dbc Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 16 Dec 2015 01:13:15 -0500 Subject: [PATCH 014/329] unused "use" --- src/Compiler/Environment.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Compiler/Environment.php b/src/Compiler/Environment.php index e6314cbe..d44bff76 100644 --- a/src/Compiler/Environment.php +++ b/src/Compiler/Environment.php @@ -11,8 +11,6 @@ namespace Leafo\ScssPhp\Compiler; -use Leafo\ScssPhp\Block; - /** * Compiler environment * From 7edbcf499498f5376fa82da26a76b34f955b59e6 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 16 Dec 2015 01:13:43 -0500 Subject: [PATCH 015/329] add typehint --- src/Compiler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compiler.php b/src/Compiler.php index f55e1d7c..524a3c41 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -863,7 +863,7 @@ protected function compileKeyframeBlock(Block $block, $selectors) $envs = $this->compactEnv($env); - $this->env = $this->extractEnv(array_filter($envs, function ($e) { + $this->env = $this->extractEnv(array_filter($envs, function (Environment $e) { return ! isset($e->block->selectors); })); From 5951a597fe330179009abbd49afe717c92f1ee5f Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 16 Dec 2015 01:14:08 -0500 Subject: [PATCH 016/329] unused variables --- src/Parser.php | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/Parser.php b/src/Parser.php index 5b72dafb..19bd9319 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -631,7 +631,7 @@ protected function parseChunk() // opening css block if ($this->selectors($selectors) && $this->literal('{')) { - $b = $this->pushBlock($selectors, $s); + $this->pushBlock($selectors, $s); return true; } @@ -1006,8 +1006,6 @@ protected function mediaQueryList(&$out) */ protected function mediaQuery(&$out) { - $s = $this->seek(); - $expressions = null; $parts = array(); @@ -1496,8 +1494,6 @@ protected function argumentList(&$out) $args = array(); while ($this->keyword($var)) { - $ss = $this->seek(); - if ($this->literal('=') && $this->expression($exp)) { $args[] = array(Type::T_STRING, '', array($var . '=')); $arg = $exp; @@ -1765,8 +1761,6 @@ protected function string(&$out) */ protected function mixedKeyword(&$out) { - $s = $this->seek(); - $parts = array(); $oldWhite = $this->eatWhiteDefault; @@ -1918,7 +1912,6 @@ protected function interpolation(&$out, $lookWhite = true) */ protected function propertyName(&$out) { - $s = $this->seek(); $parts = array(); $oldWhite = $this->eatWhiteDefault; From fc1b22ca74bae384d36e9a1e771d66153ef22f46 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 16 Dec 2015 15:19:58 -0500 Subject: [PATCH 017/329] Remove the compressed patch -- it no longer makes any difference --- src/Formatter/Compressed.php | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/Formatter/Compressed.php b/src/Formatter/Compressed.php index 1e27240a..a54b3e3a 100644 --- a/src/Formatter/Compressed.php +++ b/src/Formatter/Compressed.php @@ -70,15 +70,4 @@ public function blockLines(OutputBlock $block) echo $this->break; } } - - /** - * {@inherit} - */ - public function format(OutputBlock $block) - { - return parent::format($block); - - // TODO: we need to fix the 2 "compressed" tests where the "close" is applied - return trim(str_replace(';}', '}', parent::format($block))); - } } From 8443d11ad3c54c44a94a28aee2761e649de9bfda Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 16 Dec 2015 15:21:30 -0500 Subject: [PATCH 018/329] remove orphaned @todo --- src/Node/Number.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Node/Number.php b/src/Node/Number.php index 17e856db..6549f495 100644 --- a/src/Node/Number.php +++ b/src/Node/Number.php @@ -271,7 +271,6 @@ public function output(Compiler $compiler = null) return $unitSize; }); - // @todo refactor normalize() if (count($units) > 1 && array_sum($units) === 0) { $dimension = $this->dimension; $units = array(); From 1a95d89f15ba4cf876b9c6f331c7abe9a0bbf024 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 16 Dec 2015 15:26:28 -0500 Subject: [PATCH 019/329] remove unused variable declarations --- src/Compiler.php | 4 ++-- src/Parser.php | 2 +- src/Server.php | 7 +++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index 524a3c41..46ba6aa7 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -479,7 +479,7 @@ protected function matchExtendsSingle($rawSingle, &$outOrigin) $found = false; foreach ($counts as $idx => $count) { - list($target, $origin, $block) = $this->extends[$idx]; + list($target, $origin, /* $block */) = $this->extends[$idx]; // check count if ($count !== count($target)) { @@ -1766,7 +1766,7 @@ protected function compileChild($child, OutputBlock $out) */ protected function expToString($exp) { - list(, $op, $left, $right, $inParens, $whiteLeft, $whiteRight) = $exp; + list(, $op, $left, $right, /* $inParens */, $whiteLeft, $whiteRight) = $exp; $content = array($this->reduce($left)); diff --git a/src/Parser.php b/src/Parser.php index 19bd9319..cd815900 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -118,7 +118,7 @@ public function getSourceName() */ public function throwParseError($msg = 'parse error') { - list($line, $column) = $this->getSourcePosition($this->count); + list($line, /* $column */) = $this->getSourcePosition($this->count); $loc = empty($this->sourceName) ? "line: $line" : "$this->sourceName on line $line"; diff --git a/src/Server.php b/src/Server.php index cada00e0..cbbdae15 100644 --- a/src/Server.php +++ b/src/Server.php @@ -116,13 +116,12 @@ protected function metadataName($out) /** * Determine whether .scss file needs to be re-compiled. * - * @param string $in Input path * @param string $out Output path * @param string $etag ETag * * @return boolean True if compile required. */ - protected function needsCompile($in, $out, &$etag) + protected function needsCompile($out, &$etag) { if (! is_file($out)) { return true; @@ -326,7 +325,7 @@ public function serve($salt = '') $output = $this->cacheName($salt . $input); $etag = $noneMatch = trim($this->getIfNoneMatchHeader(), '"'); - if ($this->needsCompile($input, $output, $etag)) { + if ($this->needsCompile($output, $etag)) { try { list($css, $etag) = $this->compile($input, $output); @@ -408,7 +407,7 @@ public function checkedCachedCompile($in, $out, $force = false) throw new ServerException('Invalid or unwritable output file specified.'); } - if ($force || $this->needsCompile($in, $out, $etag)) { + if ($force || $this->needsCompile($out, $etag)) { list($css, $etag) = $this->compile($in, $out); } else { $css = file_get_contents($out); From 1152ca9c27f65da8e31abf26e1dff7d961abbb9d Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 16 Dec 2015 15:29:01 -0500 Subject: [PATCH 020/329] remove more TODOs --- src/Compiler.php | 1 - src/Parser.php | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index 46ba6aa7..ecdb8c97 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -4568,7 +4568,6 @@ protected function libLength($args) return count($list[2]); } - // TODO: need a way to declare this built-in as varargs //protected static $libListSeparator = array('list...'); protected function libListSeparator($args) { diff --git a/src/Parser.php b/src/Parser.php index cd815900..562ea701 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -1878,8 +1878,6 @@ protected function interpolation(&$out, $lookWhite = true) $s = $this->seek(); if ($this->literal('#{') && $this->valueList($value) && $this->literal('}', false)) { - // TODO: don't error if out of bounds - if ($lookWhite) { $left = preg_match('/\s/', $this->buffer[$s - 1]) ? ' ' : ''; $right = preg_match('/\s/', $this->buffer[$this->count]) ? ' ': ''; From 4c6e8be425c6cc53c70a641a8cc097ad06727826 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 16 Dec 2015 15:34:14 -0500 Subject: [PATCH 021/329] refactoring (for size) --- src/Formatter/Compressed.php | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/src/Formatter/Compressed.php b/src/Formatter/Compressed.php index a54b3e3a..4a2bb41a 100644 --- a/src/Formatter/Compressed.php +++ b/src/Formatter/Compressed.php @@ -11,7 +11,7 @@ namespace Leafo\ScssPhp\Formatter; -use Leafo\ScssPhp\Formatter; +use Leafo\ScssPhp\Formatter\Crunched; use Leafo\ScssPhp\Formatter\OutputBlock; /** @@ -19,34 +19,8 @@ * * @author Leaf Corcoran */ -class Compressed extends Formatter +class Compressed extends Crunched { - /** - * {@inheritdoc} - */ - public function __construct() - { - $this->indentLevel = 0; - $this->indentChar = ' '; - $this->break = ''; - $this->open = '{'; - $this->close = '}'; - $this->tagSeparator = ','; - $this->assignSeparator = ':'; - } - - /** - * {@inheritdoc} - */ - public function stripSemicolon(&$lines) - { - if (($count = count($lines)) - && substr($lines[$count - 1], -1) === ';' - ) { - $lines[$count - 1] = substr($lines[$count - 1], 0, -1); - } - } - /** * {@inheritdoc} */ From ca57dd3e57859de6599a2ed4a769591fc5ca0501 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 16 Dec 2015 15:53:30 -0500 Subject: [PATCH 022/329] Compiler: refactoring duplicated code --- src/Compiler.php | 55 +++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index ecdb8c97..93c581ba 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -697,23 +697,10 @@ private function spliceTree($envs, Block $block, $without) } if (isset($e->block->type) && $e->block->type === Type::T_AT_ROOT) { - continue; - } - - if (($without & self::WITH_RULE) && isset($e->block->selectors)) { - continue; + continue; } - if (($without & self::WITH_MEDIA) && - isset($e->block->type) && $e->block->type === Type::T_MEDIA - ) { - continue; - } - - if (($without & self::WITH_SUPPORTS) && - isset($e->block->type) && $e->block->type === Type::T_DIRECTIVE && - isset($e->block->name) && $e->block->name === 'supports' - ) { + if ($this->isWithout($without, $e->block)) { continue; } @@ -828,20 +815,7 @@ private function filterWithout($envs, $without) $filtered = array(); foreach ($envs as $e) { - if (($without & self::WITH_RULE) && isset($e->block->selectors)) { - continue; - } - - if (($without & self::WITH_MEDIA) && - isset($e->block->type) && $e->block->type === Type::T_MEDIA - ) { - continue; - } - - if (($without & self::WITH_SUPPORTS) && - isset($e->block->type) && $e->block->type === Type::T_DIRECTIVE && - isset($e->block->name) && $e->block->name === 'supports' - ) { + if ($this->isWithout($without, $e->block)) { continue; } @@ -851,6 +825,29 @@ private function filterWithout($envs, $without) return $this->extractEnv($filtered); } + /** + * Filter WITH rules + * + * @param integer $without + * @param \stdClass $block + * + * @return boolean + */ + private function isWithout($without, $block) + { + if ((($without & self::WITH_RULE) && isset($block->selectors)) || + (($without & self::WITH_MEDIA) && + isset($block->type) && $block->type === Type::T_MEDIA) || + (($without & self::WITH_SUPPORTS) && + isset($block->type) && $block->type === Type::T_DIRECTIVE && + isset($block->name) && $block->name === 'supports') + ) { + return true; + } + + return false; + } + /** * Compile keyframe block * From 2996d07d16d53b2e6fe222b20a67e3322bbec43a Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 16 Dec 2015 15:57:07 -0500 Subject: [PATCH 023/329] Server: remove @ operator on date functions --- src/Server.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Server.php b/src/Server.php index cbbdae15..e34ff5c3 100644 --- a/src/Server.php +++ b/src/Server.php @@ -207,7 +207,7 @@ protected function compile($in, $out) $elapsed = round((microtime(true) - $start), 4); $v = Version::VERSION; - $t = @date('r'); + $t = date('r'); $css = "/* compiled by scssphp $v on $t (${elapsed}s) */\n\n" . $css; $etag = md5($css); @@ -365,7 +365,7 @@ public function serve($salt = '') $modifiedSince = $this->getIfModifiedSinceHeader(); $mtime = filemtime($output); - if (@strtotime($modifiedSince) === $mtime) { + if (strtotime($modifiedSince) === $mtime) { header($protocol . ' 304 Not Modified'); return; @@ -444,6 +444,10 @@ public function __construct($dir, $cacheDir = null, $scss = null) $this->scss = $scss; $this->showErrorsAsCSS = false; + + if (! ini_get('date.timezone')) { + date_default_timezone_set('UTC'); + } } /** From 2e1f5bd062faa2c7cf23519d6d171287663bae59 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 16 Dec 2015 16:03:40 -0500 Subject: [PATCH 024/329] Compiler: add typehint to isWithout() --- src/Compiler.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index 93c581ba..04c1af01 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -700,7 +700,7 @@ private function spliceTree($envs, Block $block, $without) continue; } - if ($this->isWithout($without, $e->block)) { + if ($e->block && $this->isWithout($without, $e->block)) { continue; } @@ -815,7 +815,7 @@ private function filterWithout($envs, $without) $filtered = array(); foreach ($envs as $e) { - if ($this->isWithout($without, $e->block)) { + if ($e->block && $this->isWithout($without, $e->block)) { continue; } @@ -828,12 +828,12 @@ private function filterWithout($envs, $without) /** * Filter WITH rules * - * @param integer $without - * @param \stdClass $block + * @param integer $without + * @param \Leafo\ScssPhp\Block $block * * @return boolean */ - private function isWithout($without, $block) + private function isWithout($without, Block $block) { if ((($without & self::WITH_RULE) && isset($block->selectors)) || (($without & self::WITH_MEDIA) && From 9177e859a01ca1395fbede153d1eb93ab86645d4 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 16 Dec 2015 16:22:06 -0500 Subject: [PATCH 025/329] composition via trait --- scss.inc.php | 1 + src/Formatter/Compressed.php | 6 ++-- src/Formatter/Crunched.php | 26 +---------------- src/Formatter/StripSemiColons.php | 46 +++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 27 deletions(-) create mode 100644 src/Formatter/StripSemiColons.php diff --git a/scss.inc.php b/scss.inc.php index b6892fec..ddfd1297 100644 --- a/scss.inc.php +++ b/scss.inc.php @@ -20,6 +20,7 @@ include_once __DIR__ . '/src/Formatter/Expanded.php'; include_once __DIR__ . '/src/Formatter/Nested.php'; include_once __DIR__ . '/src/Formatter/OutputBlock.php'; + include_once __DIR__ . '/src/Formatter/StripSemiColons.php'; include_once __DIR__ . '/src/Node.php'; include_once __DIR__ . '/src/Node/Number.php'; include_once __DIR__ . '/src/Parser.php'; diff --git a/src/Formatter/Compressed.php b/src/Formatter/Compressed.php index 4a2bb41a..af55da02 100644 --- a/src/Formatter/Compressed.php +++ b/src/Formatter/Compressed.php @@ -11,7 +11,7 @@ namespace Leafo\ScssPhp\Formatter; -use Leafo\ScssPhp\Formatter\Crunched; +use Leafo\ScssPhp\Formatter; use Leafo\ScssPhp\Formatter\OutputBlock; /** @@ -19,8 +19,10 @@ * * @author Leaf Corcoran */ -class Compressed extends Crunched +class Compressed extends Formatter { + use StripSemiColons; + /** * {@inheritdoc} */ diff --git a/src/Formatter/Crunched.php b/src/Formatter/Crunched.php index 5e80a824..c31cac56 100644 --- a/src/Formatter/Crunched.php +++ b/src/Formatter/Crunched.php @@ -21,31 +21,7 @@ */ class Crunched extends Formatter { - /** - * {@inheritdoc} - */ - public function __construct() - { - $this->indentLevel = 0; - $this->indentChar = ' '; - $this->break = ''; - $this->open = '{'; - $this->close = '}'; - $this->tagSeparator = ','; - $this->assignSeparator = ':'; - } - - /** - * {@inheritdoc} - */ - public function stripSemicolon(&$lines) - { - if (($count = count($lines)) - && substr($lines[$count - 1], -1) === ';' - ) { - $lines[$count - 1] = substr($lines[$count - 1], 0, -1); - } - } + use StripSemiColons; /** * {@inheritdoc} diff --git a/src/Formatter/StripSemiColons.php b/src/Formatter/StripSemiColons.php new file mode 100644 index 00000000..8e42c16e --- /dev/null +++ b/src/Formatter/StripSemiColons.php @@ -0,0 +1,46 @@ + + */ +trait StripSemiColons +{ + /** + * {@inheritdoc} + */ + public function __construct() + { + $this->indentLevel = 0; + $this->indentChar = ' '; + $this->break = ''; + $this->open = '{'; + $this->close = '}'; + $this->tagSeparator = ','; + $this->assignSeparator = ':'; + } + + /** + * {@inheritdoc} + */ + public function stripSemicolon(&$lines) + { + if (($count = count($lines)) + && substr($lines[$count - 1], -1) === ';' + ) { + $lines[$count - 1] = substr($lines[$count - 1], 0, -1); + } + } +} From 183412ca18111b2484bca0f2327df6ee8af97945 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 16 Dec 2015 16:22:20 -0500 Subject: [PATCH 026/329] errant tabs --- src/Compiler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compiler.php b/src/Compiler.php index 04c1af01..3039a704 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -697,7 +697,7 @@ private function spliceTree($envs, Block $block, $without) } if (isset($e->block->type) && $e->block->type === Type::T_AT_ROOT) { - continue; + continue; } if ($e->block && $this->isWithout($without, $e->block)) { From 7f2ae8d1a8d324052460be2061143a3663f1f479 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 16 Dec 2015 17:18:28 -0500 Subject: [PATCH 027/329] Update codesniffer to 2.5.0 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 691a68a2..112a6bde 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "php": ">=5.4.0" }, "require-dev": { - "squizlabs/php_codesniffer": "~2.3", + "squizlabs/php_codesniffer": "~2.5", "phpunit/phpunit": "~3.7", "kherge/box": "~2.5" }, From 69e49077ed9d4c16d2bfd2b74cb6b9b6d00dcd3d Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 16 Dec 2015 17:19:22 -0500 Subject: [PATCH 028/329] php5.4: Use shorthand array() syntax --- src/Colors.php | 4 +- src/Compiler.php | 498 +++++++++++++++++++-------------------- src/Formatter/Nested.php | 2 +- src/Node/Number.php | 38 +-- src/Parser.php | 181 +++++++------- src/Server.php | 10 +- 6 files changed, 366 insertions(+), 367 deletions(-) diff --git a/src/Colors.php b/src/Colors.php index e3936a5f..ff48c199 100644 --- a/src/Colors.php +++ b/src/Colors.php @@ -25,7 +25,7 @@ class Colors * * @var array */ - public static $cssColors = array( + public static $cssColors = [ 'aliceblue' => '240,248,255', 'antiquewhite' => '250,235,215', 'aqua' => '0,255,255', @@ -175,5 +175,5 @@ class Colors 'whitesmoke' => '245,245,245', 'yellow' => '255,255,0', 'yellowgreen' => '154,205,50', - ); + ]; } diff --git a/src/Compiler.php b/src/Compiler.php index 3039a704..64dfb8b3 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -67,7 +67,7 @@ class Compiler /** * @var array */ - static protected $operatorNames = array( + static protected $operatorNames = [ '+' => 'add', '-' => 'sub', '*' => 'mul', @@ -82,40 +82,40 @@ class Compiler '<=' => 'lte', '>=' => 'gte', '<=>' => 'cmp', - ); + ]; /** * @var array */ - static protected $namespaces = array( + static protected $namespaces = [ 'special' => '%', 'mixin' => '@', 'function' => '^', - ); - - static public $true = array(Type::T_KEYWORD, 'true'); - static public $false = array(Type::T_KEYWORD, 'false'); - static public $null = array(Type::T_NULL); - static public $nullString = array(Type::T_STRING, '', array()); - static public $defaultValue = array(Type::T_KEYWORD, ''); - static public $selfSelector = array(Type::T_SELF); - static public $emptyList = array(Type::T_LIST, '', array()); - static public $emptyMap = array(Type::T_MAP, array(), array()); - static public $emptyString = array(Type::T_STRING, '"', array()); - static public $with = array(Type::T_KEYWORD, 'with'); - static public $without = array(Type::T_KEYWORD, 'without'); - - protected $importPaths = array(''); - protected $importCache = array(); - protected $importedFiles = array(); - protected $userFunctions = array(); - protected $registeredVars = array(); - protected $registeredFeatures = array( + ]; + + static public $true = [Type::T_KEYWORD, 'true']; + static public $false = [Type::T_KEYWORD, 'false']; + static public $null = [Type::T_NULL]; + static public $nullString = [Type::T_STRING, '', []]; + static public $defaultValue = [Type::T_KEYWORD, '']; + static public $selfSelector = [Type::T_SELF]; + static public $emptyList = [Type::T_LIST, '', []]; + static public $emptyMap = [Type::T_MAP, [], []]; + static public $emptyString = [Type::T_STRING, '"', []]; + static public $with = [Type::T_KEYWORD, 'with']; + static public $without = [Type::T_KEYWORD, 'without']; + + protected $importPaths = ['']; + protected $importCache = []; + protected $importedFiles = []; + protected $userFunctions = []; + protected $registeredVars = []; + protected $registeredFeatures = [ 'extend-selector-pseudoclass' => false, 'at-error' => true, 'units-level-3' => false, 'global-variable-shadowing' => false, - ); + ]; protected $encoding = null; protected $lineNumberStyle = null; @@ -148,8 +148,8 @@ class Compiler */ public function __construct() { - $this->parsedFiles = array(); - $this->sourceNames = array(); + $this->parsedFiles = []; + $this->sourceNames = []; } /** @@ -168,9 +168,9 @@ public function compile($code, $path = null) setlocale(LC_NUMERIC, 'C'); $this->indentLevel = -1; - $this->commentsSeen = array(); - $this->extends = array(); - $this->extendsMap = array(); + $this->commentsSeen = []; + $this->extends = []; + $this->extendsMap = []; $this->sourceIndex = null; $this->sourceLine = null; $this->sourceColumn = null; @@ -250,13 +250,13 @@ protected function pushExtends($target, $origin, $block) } $i = count($this->extends); - $this->extends[] = array($target, $origin, $block); + $this->extends[] = [$target, $origin, $block]; foreach ($target as $part) { if (isset($this->extendsMap[$part])) { $this->extendsMap[$part][] = $i; } else { - $this->extendsMap[$part] = array($i); + $this->extendsMap[$part] = [$i]; } } } @@ -273,8 +273,8 @@ protected function makeOutputBlock($type, $selectors = null) { $out = new OutputBlock; $out->type = $type; - $out->lines = array(); - $out->children = array(); + $out->lines = []; + $out->children = []; $out->parent = $this->scope; $out->selectors = $selectors; $out->depth = $this->env->depth; @@ -330,7 +330,7 @@ protected function missingSelectors() protected function flattenSelectors(OutputBlock $block, $parentKey = null) { if ($block->selectors) { - $selectors = array(); + $selectors = []; foreach ($block->selectors as $s) { $selectors[] = $s; @@ -356,7 +356,7 @@ protected function flattenSelectors(OutputBlock $block, $parentKey = null) } } - $block->selectors = array(); + $block->selectors = []; $placeholderSelector = false; foreach ($selectors as $selector) { @@ -451,8 +451,8 @@ protected function matchExtends($selector, &$out, $from = 0, $initial = true) */ protected function matchExtendsSingle($rawSingle, &$outOrigin) { - $counts = array(); - $single = array(); + $counts = []; + $single = []; foreach ($rawSingle as $part) { // matches Number @@ -475,7 +475,7 @@ protected function matchExtendsSingle($rawSingle, &$outOrigin) } } - $outOrigin = array(); + $outOrigin = []; $found = false; foreach ($counts as $idx => $count) { @@ -522,9 +522,9 @@ protected function matchExtendsSingle($rawSingle, &$outOrigin) protected function combineSelectorSingle($base, $other) { $tag = null; - $out = array(); + $out = []; - foreach (array($base, $other) as $single) { + foreach ([$base, $other] as $single) { foreach ($single as $part) { if (preg_match('/^[^\[.#:]/', $part)) { $tag = $part; @@ -553,7 +553,7 @@ protected function compileMedia(Block $media) $mediaQuery = $this->compileMediaQuery($this->multiplyMedia($this->env)); if (! empty($mediaQuery)) { - $this->scope = $this->makeOutputBlock(Type::T_MEDIA, array($mediaQuery)); + $this->scope = $this->makeOutputBlock(Type::T_MEDIA, [$mediaQuery]); $parentScope = $this->mediaParent($this->scope); $parentScope->children[] = $this->scope; @@ -579,12 +579,12 @@ protected function compileMedia(Block $media) $wrapped->sourceIndex = $media->sourceIndex; $wrapped->sourceLine = $media->sourceLine; $wrapped->sourceColumn = $media->sourceColumn; - $wrapped->selectors = array(); - $wrapped->comments = array(); + $wrapped->selectors = []; + $wrapped->comments = []; $wrapped->parent = $media; $wrapped->children = $media->children; - $media->children = array(array(Type::T_BLOCK, $wrapped)); + $media->children = [[Type::T_BLOCK, $wrapped]]; } $this->compileChildrenNoReturn($media->children, $this->scope); @@ -629,9 +629,9 @@ protected function compileDirective(Block $block) } if ($block->name === 'keyframes' || substr($block->name, -10) === '-keyframes') { - $this->compileKeyframeBlock($block, array($s)); + $this->compileKeyframeBlock($block, [$s]); } else { - $this->compileNestedBlock($block, array($s)); + $this->compileNestedBlock($block, [$s]); } } @@ -653,11 +653,11 @@ protected function compileAtRoot(Block $block) $wrapped->sourceLine = $block->sourceLine; $wrapped->sourceColumn = $block->sourceColumn; $wrapped->selectors = $block->selector; - $wrapped->comments = array(); + $wrapped->comments = []; $wrapped->parent = $block; $wrapped->children = $block->children; - $block->children = array(array(Type::T_BLOCK, $wrapped)); + $block->children = [[Type::T_BLOCK, $wrapped]]; } $this->env = $this->filterWithout($envs, $without); @@ -708,14 +708,14 @@ private function spliceTree($envs, Block $block, $without) $b->sourceIndex = $e->block->sourceIndex; $b->sourceLine = $e->block->sourceLine; $b->sourceColumn = $e->block->sourceColumn; - $b->selectors = array(); + $b->selectors = []; $b->comments = $e->block->comments; $b->parent = null; if ($newBlock) { $type = isset($newBlock->type) ? $newBlock->type : Type::T_BLOCK; - $b->children = array(array($type, $newBlock)); + $b->children = [[$type, $newBlock]]; $newBlock->parent = $b; } elseif (count($block->children)) { @@ -749,7 +749,7 @@ private function spliceTree($envs, Block $block, $without) $type = isset($newBlock->type) ? $newBlock->type : Type::T_BLOCK; - return array($type, $newBlock); + return [$type, $newBlock]; } /** @@ -761,20 +761,20 @@ private function spliceTree($envs, Block $block, $without) */ private function compileWith($with) { - static $mapping = array( + static $mapping = [ 'rule' => self::WITH_RULE, 'media' => self::WITH_MEDIA, 'supports' => self::WITH_SUPPORTS, 'all' => self::WITH_ALL, - ); + ]; // exclude selectors by default $without = self::WITH_RULE; - if ($this->libMapHasKey(array($with, self::$with))) { + if ($this->libMapHasKey([$with, self::$with])) { $without = self::WITH_ALL; - $list = $this->coerceList($this->libMapGet(array($with, self::$with))); + $list = $this->coerceList($this->libMapGet([$with, self::$with])); foreach ($list[2] as $item) { $keyword = $this->compileStringContent($this->coerceString($item)); @@ -785,10 +785,10 @@ private function compileWith($with) } } - if ($this->libMapHasKey(array($with, self::$without))) { + if ($this->libMapHasKey([$with, self::$without])) { $without = 0; - $list = $this->coerceList($this->libMapGet(array($with, self::$without))); + $list = $this->coerceList($this->libMapGet([$with, self::$without])); foreach ($list[2] as $item) { $keyword = $this->compileStringContent($this->coerceString($item)); @@ -812,7 +812,7 @@ private function compileWith($with) */ private function filterWithout($envs, $without) { - $filtered = array(); + $filtered = []; foreach ($envs as $e) { if ($e->block && $this->isWithout($without, $e->block)) { @@ -978,7 +978,7 @@ protected function evalSelectors($selectors) { $this->shouldEvaluate = false; - $selectors = array_map(array($this, 'evalSelector'), $selectors); + $selectors = array_map([$this, 'evalSelector'], $selectors); // after evaluating interpolates, we might need a second pass if ($this->shouldEvaluate) { @@ -986,7 +986,7 @@ protected function evalSelectors($selectors) $parser = $this->parserFactory(__METHOD__); if ($parser->parseSelector($buffer, $newSelectors)) { - $selectors = array_map(array($this, 'evalSelector'), $newSelectors); + $selectors = array_map([$this, 'evalSelector'], $newSelectors); } } @@ -1002,7 +1002,7 @@ protected function evalSelectors($selectors) */ protected function evalSelector($selector) { - return array_map(array($this, 'evalSelectorPart'), $selector); + return array_map([$this, 'evalSelectorPart'], $selector); } /** @@ -1042,7 +1042,7 @@ protected function evalSelectorPart($part) */ protected function collapseSelectors($selectors) { - $parts = array(); + $parts = []; foreach ($selectors as $selector) { $output = ''; @@ -1069,7 +1069,7 @@ function ($value, $key) use (&$output) { */ protected function flattenSelectorSingle($single) { - $joined = array(); + $joined = []; foreach ($single as $part) { if (empty($joined) || @@ -1106,7 +1106,7 @@ protected function compileSelector($selector) return implode( ' ', array_map( - array($this, 'compileSelectorPart'), + [$this, 'compileSelectorPart'], $selector ) ); @@ -1218,7 +1218,7 @@ protected function compileMediaQuery($queryList) foreach ($queryList as $query) { $type = null; - $parts = array(); + $parts = []; foreach ($query as $q) { switch ($q[0]) { @@ -1226,14 +1226,14 @@ protected function compileMediaQuery($queryList) if ($type) { $type = $this->mergeMediaTypes( $type, - array_map(array($this, 'compileValue'), array_slice($q, 1)) + array_map([$this, 'compileValue'], array_slice($q, 1)) ); if (empty($type)) { // merge failed return null; } } else { - $type = array_map(array($this, 'compileValue'), array_slice($q, 1)); + $type = array_map([$this, 'compileValue'], array_slice($q, 1)); } break; @@ -1319,10 +1319,10 @@ protected function mergeMediaTypes($type1, $type2) return null; } - return array( + return [ $m1 === Type::T_NOT ? $m2 : $m1, $m1 === Type::T_NOT ? $t2 : $t1, - ); + ]; } if ($m1 === Type::T_NOT && $m2 === Type::T_NOT) { @@ -1331,7 +1331,7 @@ protected function mergeMediaTypes($type1, $type2) return null; } - return array(Type::T_NOT, $t1); + return [Type::T_NOT, $t1]; } if ($t1 !== $t2) { @@ -1339,7 +1339,7 @@ protected function mergeMediaTypes($type1, $type2) } // t1 == t2, neither m1 nor m2 are "not" - return array(empty($m1)? $m2 : $m1, $t1); + return [empty($m1)? $m2 : $m1, $t1]; } /** @@ -1525,7 +1525,7 @@ protected function compileChild($child, OutputBlock $out) list(, $selectors) = $child; foreach ($selectors as $sel) { - $results = $this->evalSelectors(array($sel)); + $results = $this->evalSelectors([$sel]); foreach ($results as $result) { // only use the first one @@ -1640,10 +1640,10 @@ protected function compileChild($child, OutputBlock $out) break; case Type::T_BREAK: - return array(Type::T_CONTROL, true); + return [Type::T_CONTROL, true]; case Type::T_CONTINUE: - return array(Type::T_CONTROL, false); + return [Type::T_CONTROL, false]; case Type::T_RETURN: return $this->reduce($child[1], true); @@ -1651,7 +1651,7 @@ protected function compileChild($child, OutputBlock $out) case Type::T_NESTED_PROPERTY: list(, $prop) = $child; - $prefixed = array(); + $prefixed = []; $prefix = $this->compileValue($prop->prefix) . '-'; foreach ($prop->children as $child) { @@ -1765,7 +1765,7 @@ protected function expToString($exp) { list(, $op, $left, $right, /* $inParens */, $whiteLeft, $whiteRight) = $exp; - $content = array($this->reduce($left)); + $content = [$this->reduce($left)]; if ($whiteLeft) { $content[] = ' '; @@ -1779,7 +1779,7 @@ protected function expToString($exp) $content[] = $this->reduce($right); - return array(Type::T_STRING, '', $content); + return [Type::T_STRING, '', $content]; } /** @@ -1867,12 +1867,12 @@ protected function reduce($value, $inExp = false) // 3. op[op name] $fn = "op${ucOpName}${ucLType}${ucRType}"; - if (is_callable(array($this, $fn)) || + if (is_callable([$this, $fn]) || (($fn = "op${ucLType}${ucRType}") && - is_callable(array($this, $fn)) && + is_callable([$this, $fn]) && $passOp = true) || (($fn = "op${ucOpName}") && - is_callable(array($this, $fn)) && + is_callable([$this, $fn]) && $genOp = true) ) { $coerceUnit = false; @@ -1960,7 +1960,7 @@ protected function reduce($value, $inExp = false) $op = $op . ' '; } - return array(Type::T_STRING, '', array($op, $exp)); + return [Type::T_STRING, '', [$op, $exp]]; case Type::T_VARIABLE: list(, $name) = $value; @@ -2030,7 +2030,7 @@ private function fncall($name, $argValues) } // for CSS functions, simply flatten the arguments into a list - $listArgs = array(); + $listArgs = []; foreach ((array) $argValues as $arg) { if (empty($arg[0])) { @@ -2038,7 +2038,7 @@ private function fncall($name, $argValues) } } - return array(Type::T_FUNCTION, $name, array(Type::T_LIST, ',', $listArgs)); + return [Type::T_FUNCTION, $name, [Type::T_LIST, ',', $listArgs]]; } /** @@ -2070,7 +2070,7 @@ public function normalizeValue($value) $value = $this->extractInterpolation($value); if ($value[0] !== Type::T_LIST) { - return array(Type::T_KEYWORD, $this->compileValue($value)); + return [Type::T_KEYWORD, $this->compileValue($value)]; } foreach ($value[2] as $key => $item) { @@ -2080,13 +2080,13 @@ public function normalizeValue($value) return $value; case Type::T_STRING: - return array($type, '"', array($this->compileStringContent($value))); + return [$type, '"', [$this->compileStringContent($value)]]; case Type::T_NUMBER: return $value->normalize(); case Type::T_INTERPOLATE: - return array(Type::T_KEYWORD, $this->compileValue($value)); + return [Type::T_KEYWORD, $this->compileValue($value)]; default: return $value; @@ -2143,7 +2143,7 @@ protected function opSubNumberNumber($left, $right) protected function opDivNumberNumber($left, $right) { if ($right[1] == 0) { - return array(Type::T_STRING, '', array($left[1] . $left[2] . '/' . $right[1] . $right[2])); + return [Type::T_STRING, '', [$left[1] . $left[2] . '/' . $right[1] . $right[2]]]; } return new Node\Number($left[1] / $right[1], $left[2]); @@ -2248,9 +2248,9 @@ protected function opOr($left, $right, $shouldEval) */ protected function opColorColor($op, $left, $right) { - $out = array(Type::T_COLOR); + $out = [Type::T_COLOR]; - foreach (array(1, 2, 3) as $i) { + foreach ([1, 2, 3] as $i) { $lval = isset($left[$i]) ? $left[$i] : 0; $rval = isset($right[$i]) ? $right[$i] : 0; @@ -2317,7 +2317,7 @@ protected function opColorNumber($op, $left, $right) return $this->opColorColor( $op, $left, - array(Type::T_COLOR, $value, $value, $value) + [Type::T_COLOR, $value, $value, $value] ); } @@ -2336,7 +2336,7 @@ protected function opNumberColor($op, $left, $right) return $this->opColorColor( $op, - array(Type::T_COLOR, $value, $value, $value), + [Type::T_COLOR, $value, $value, $value], $right ); } @@ -2539,7 +2539,7 @@ public function compileValue($value) $delim .= ' '; } - $filtered = array(); + $filtered = []; foreach ($items as $item) { if ($item[0] === Type::T_NULL) { @@ -2554,7 +2554,7 @@ public function compileValue($value) case Type::T_MAP: $keys = $value[1]; $values = $value[2]; - $filtered = array(); + $filtered = []; for ($i = 0, $s = count($keys); $i < $s; $i++) { $filtered[$this->compileValue($keys[$i])] = $this->compileValue($values[$i]); @@ -2588,11 +2588,11 @@ public function compileValue($value) switch ($reduced[0]) { case Type::T_STRING: - $reduced = array(Type::T_KEYWORD, $this->compileStringContent($reduced)); + $reduced = [Type::T_KEYWORD, $this->compileStringContent($reduced)]; break; case Type::T_NULL: - $reduced = array(Type::T_KEYWORD, ''); + $reduced = [Type::T_KEYWORD, '']; } return $this->compileValue($reduced); @@ -2626,7 +2626,7 @@ protected function flattenList($list) */ protected function compileStringContent($string) { - $parts = array(); + $parts = []; foreach ($string[2] as $part) { if (is_array($part) || $part instanceof \ArrayAccess) { @@ -2652,10 +2652,10 @@ protected function extractInterpolation($list) foreach ($items as $i => $item) { if ($item[0] === Type::T_INTERPOLATE) { - $before = array(Type::T_LIST, $list[1], array_slice($items, 0, $i)); - $after = array(Type::T_LIST, $list[1], array_slice($items, $i + 1)); + $before = [Type::T_LIST, $list[1], array_slice($items, 0, $i)]; + $after = [Type::T_LIST, $list[1], array_slice($items, $i + 1)]; - return array(Type::T_INTERPOLATED, $item, $before, $after); + return [Type::T_INTERPOLATED, $item, $before, $after]; } } @@ -2672,15 +2672,15 @@ protected function extractInterpolation($list) protected function multiplySelectors(Environment $env) { $envs = $this->compactEnv($env); - $selectors = array(); - $parentSelectors = array(array()); + $selectors = []; + $parentSelectors = [[]]; while ($env = array_pop($envs)) { if (empty($env->selectors)) { continue; } - $selectors = array(); + $selectors = []; foreach ($env->selectors as $selector) { foreach ($parentSelectors as $parent) { @@ -2705,10 +2705,10 @@ protected function multiplySelectors(Environment $env) protected function joinSelectors($parent, $child) { $setSelf = false; - $out = array(); + $out = []; foreach ($child as $part) { - $newPart = array(); + $newPart = []; foreach ($part as $p) { if ($p === self::$selfSelector) { @@ -2717,7 +2717,7 @@ protected function joinSelectors($parent, $child) foreach ($parent as $i => $parentPart) { if ($i > 0) { $out[] = $newPart; - $newPart = array(); + $newPart = []; } foreach ($parentPart as $pp) { @@ -2758,13 +2758,13 @@ protected function multiplyMedia(Environment $env = null, $childQueries = null) $parentQueries = isset($env->block->queryList) ? $env->block->queryList - : array(array(array(Type::T_MEDIA_VALUE, $env->block->value))); + : [[[Type::T_MEDIA_VALUE, $env->block->value]]]; if ($childQueries === null) { $childQueries = $parentQueries; } else { $originalQueries = $childQueries; - $childQueries = array(); + $childQueries = []; foreach ($parentQueries as $parentQuery) { foreach ($originalQueries as $childQuery) { @@ -2785,7 +2785,7 @@ protected function multiplyMedia(Environment $env = null, $childQueries = null) */ private function compactEnv(Environment $env) { - for ($envs = array(); $env; $env = $env->parent) { + for ($envs = []; $env; $env = $env->parent) { $envs[] = $env; } @@ -2820,7 +2820,7 @@ protected function pushEnv(Block $block = null) { $env = new Environment; $env->parent = $this->env; - $env->store = array(); + $env->store = []; $env->block = $block; $env->depth = isset($this->env->depth) ? $this->env->depth + 1 : 0; @@ -3135,7 +3135,7 @@ public function setLineNumberStyle($lineNumberStyle) */ public function registerFunction($name, $func, $prototype = null) { - $this->userFunctions[$this->normalizeName($name)] = array($func, $prototype); + $this->userFunctions[$this->normalizeName($name)] = [$func, $prototype]; } /** @@ -3202,12 +3202,12 @@ protected function importFile($path, $out) */ public function findImport($url) { - $urls = array(); + $urls = []; // for "normal" scss imports (ignore vanilla css and external requests) if (! preg_match('/\.css$|^https?:\/\//', $url)) { // try both normal and the _partial filename - $urls = array($url, preg_replace('/[^\/]+$/', '_\0', $url)); + $urls = [$url, preg_replace('/[^\/]+$/', '_\0', $url)]; } foreach ($this->importPaths as $dir) { @@ -3345,8 +3345,8 @@ protected function callScssFunction($name, $argValues, &$returnValue) // throw away lines and children $tmp = new OutputBlock; - $tmp->lines = array(); - $tmp->children = array(); + $tmp->lines = []; + $tmp->children = []; $this->env->marker = 'function'; @@ -3419,7 +3419,7 @@ function ($m) { ucfirst($name) ); - return array($this, $libName); + return [$this, $libName]; } /** @@ -3432,8 +3432,8 @@ function ($m) { */ protected function sortArgs($prototype, $args) { - $keyArgs = array(); - $posArgs = array(); + $keyArgs = []; + $posArgs = []; // separate positional and keyword arguments foreach ($args as $arg) { @@ -3449,7 +3449,7 @@ protected function sortArgs($prototype, $args) } if (! isset($prototype)) { - return array($posArgs, $keyArgs); + return [$posArgs, $keyArgs]; } // copy positional args @@ -3464,7 +3464,7 @@ protected function sortArgs($prototype, $args) } } - return array($finalArgs, $keyArgs); + return [$finalArgs, $keyArgs]; } /** @@ -3483,18 +3483,18 @@ protected function applyArguments($argDef, $argValues) $env->store = $storeEnv->store; $hasVariable = false; - $args = array(); + $args = []; foreach ($argDef as $i => $arg) { list($name, $default, $isVariable) = $argDef[$i]; - $args[$name] = array($i, $name, $default, $isVariable); + $args[$name] = [$i, $name, $default, $isVariable]; $hasVariable |= $isVariable; } - $keywordArgs = array(); - $deferredKeywordArgs = array(); - $remaining = array(); + $keywordArgs = []; + $deferredKeywordArgs = []; + $remaining = []; // assign the keyword args foreach ((array) $argValues as $arg) { @@ -3549,7 +3549,7 @@ protected function applyArguments($argDef, $argValues) list($i, $name, $default, $isVariable) = $arg; if ($isVariable) { - $val = array(Type::T_LIST, ',', array(), $isVariable); + $val = [Type::T_LIST, ',', [], $isVariable]; for ($count = count($remaining); $i < $count; $i++) { $val[2][] = $remaining[$i]; @@ -3614,7 +3614,7 @@ private function coerceValue($value) return self::$emptyString; } - return array(Type::T_KEYWORD, $value); + return [Type::T_KEYWORD, $value]; } /** @@ -3634,7 +3634,7 @@ protected function coerceMap($item) return self::$emptyMap; } - return array(Type::T_MAP, array($item), array(self::$null)); + return [Type::T_MAP, [$item], [self::$null]]; } /** @@ -3653,23 +3653,23 @@ protected function coerceList($item, $delim = ',') if (isset($item) && $item[0] === Type::T_MAP) { $keys = $item[1]; $values = $item[2]; - $list = array(); + $list = []; for ($i = 0, $s = count($keys); $i < $s; $i++) { $key = $keys[$i]; $value = $values[$i]; - $list[] = array( + $list[] = [ Type::T_LIST, '', - array(array(Type::T_KEYWORD, $this->compileStringContent($this->coerceString($key))), $value) - ); + [[Type::T_KEYWORD, $this->compileStringContent($this->coerceString($key))], $value] + ]; } - return array(Type::T_LIST, ',', $list); + return [Type::T_LIST, ',', $list]; } - return array(Type::T_LIST, $delim, ! isset($item) ? array(): array($item)); + return [Type::T_LIST, $delim, ! isset($item) ? []: [$item]]; } /** @@ -3708,8 +3708,8 @@ protected function coerceColor($value) $rgba = explode(',', Colors::$cssColors[$name]); return isset($rgba[3]) - ? array(Type::T_COLOR, (int) $rgba[0], (int) $rgba[1], (int) $rgba[2], (int) $rgba[3]) - : array(Type::T_COLOR, (int) $rgba[0], (int) $rgba[1], (int) $rgba[2]); + ? [Type::T_COLOR, (int) $rgba[0], (int) $rgba[1], (int) $rgba[2], (int) $rgba[3]] + : [Type::T_COLOR, (int) $rgba[0], (int) $rgba[1], (int) $rgba[2]]; } return null; @@ -3731,7 +3731,7 @@ protected function coerceString($value) return $value; } - return array(Type::T_STRING, '', array($this->compileValue($value))); + return [Type::T_STRING, '', [$this->compileValue($value)]]; } /** @@ -3845,7 +3845,7 @@ public function assertNumber($value) */ protected function fixColor($c) { - foreach (array(1, 2, 3) as $i) { + foreach ([1, 2, 3] as $i) { if ($c[$i] < 0) { $c[$i] = 0; } @@ -3895,7 +3895,7 @@ public function toHSL($red, $green, $blue) } } - return array(Type::T_HSL, fmod($h, 360), $s * 100, $l / 5.1); + return [Type::T_HSL, fmod($h, 360), $s * 100, $l / 5.1]; } /** @@ -3958,35 +3958,35 @@ public function toRGB($hue, $saturation, $lightness) $g = $this->hueToRGB($m1, $m2, $h) * 255; $b = $this->hueToRGB($m1, $m2, $h - 1/3) * 255; - $out = array(Type::T_COLOR, $r, $g, $b); + $out = [Type::T_COLOR, $r, $g, $b]; return $out; } // Built in functions - //protected static $libCall = array('name', 'args...'); + //protected static $libCall = ['name', 'args...']; protected function libCall($args, $kwargs) { $name = $this->compileStringContent($this->coerceString($this->reduce(array_shift($args), true))); $args = array_map( function ($a) { - return array(null, $a, false); + return [null, $a, false]; }, $args ); if (count($kwargs)) { foreach ($kwargs as $key => $value) { - $args[] = array(array(Type::T_VARIABLE, $key), $value, false); + $args[] = [[Type::T_VARIABLE, $key], $value, false]; } } - return $this->reduce(array(Type::T_FUNCTION_CALL, $name, $args)); + return $this->reduce([Type::T_FUNCTION_CALL, $name, $args]); } - protected static $libIf = array('condition', 'if-true', 'if-false'); + protected static $libIf = ['condition', 'if-true', 'if-false']; protected function libIf($args) { list($cond, $t, $f) = $args; @@ -3998,7 +3998,7 @@ protected function libIf($args) return $this->reduce($t, true); } - protected static $libIndex = array('list', 'value'); + protected static $libIndex = ['list', 'value']; protected function libIndex($args) { list($list, $value) = $args; @@ -4019,7 +4019,7 @@ protected function libIndex($args) return self::$null; } - $values = array(); + $values = []; foreach ($list[2] as $item) { $values[] = $this->normalizeValue($item); @@ -4030,17 +4030,17 @@ protected function libIndex($args) return false === $key ? self::$null : $key + 1; } - protected static $libRgb = array('red', 'green', 'blue'); + protected static $libRgb = ['red', 'green', 'blue']; protected function libRgb($args) { list($r, $g, $b) = $args; - return array(Type::T_COLOR, $r[1], $g[1], $b[1]); + return [Type::T_COLOR, $r[1], $g[1], $b[1]]; } - protected static $libRgba = array( - array('red', 'color'), - 'green', 'blue', 'alpha'); + protected static $libRgba = [ + ['red', 'color'], + 'green', 'blue', 'alpha']; protected function libRgba($args) { if ($color = $this->coerceColor($args[0])) { @@ -4053,7 +4053,7 @@ protected function libRgba($args) list($r, $g, $b, $a) = $args; - return array(Type::T_COLOR, $r[1], $g[1], $b[1], $a[1]); + return [Type::T_COLOR, $r[1], $g[1], $b[1], $a[1]]; } // helper function for adjust_color, change_color, and scale_color @@ -4061,7 +4061,7 @@ protected function alterColor($args, $fn) { $color = $this->assertColor($args[0]); - foreach (array(1, 2, 3, 7) as $i) { + foreach ([1, 2, 3, 7] as $i) { if (isset($args[$i])) { $val = $this->assertNumber($args[$i]); $ii = $i === 7 ? 4 : $i; // alpha @@ -4072,7 +4072,7 @@ protected function alterColor($args, $fn) if (isset($args[4]) || isset($args[5]) || isset($args[6])) { $hsl = $this->toHSL($color[1], $color[2], $color[3]); - foreach (array(4, 5, 6) as $i) { + foreach ([4, 5, 6] as $i) { if (isset($args[$i])) { $val = $this->assertNumber($args[$i]); $hsl[$i - 3] = call_user_func($fn, $hsl[$i - 3], $val, $i); @@ -4091,10 +4091,10 @@ protected function alterColor($args, $fn) return $color; } - protected static $libAdjustColor = array( + protected static $libAdjustColor = [ 'color', 'red', 'green', 'blue', 'hue', 'saturation', 'lightness', 'alpha' - ); + ]; protected function libAdjustColor($args) { return $this->alterColor($args, function ($base, $alter, $i) { @@ -4102,10 +4102,10 @@ protected function libAdjustColor($args) }); } - protected static $libChangeColor = array( + protected static $libChangeColor = [ 'color', 'red', 'green', 'blue', 'hue', 'saturation', 'lightness', 'alpha' - ); + ]; protected function libChangeColor($args) { return $this->alterColor($args, function ($base, $alter, $i) { @@ -4113,10 +4113,10 @@ protected function libChangeColor($args) }); } - protected static $libScaleColor = array( + protected static $libScaleColor = [ 'color', 'red', 'green', 'blue', 'hue', 'saturation', 'lightness', 'alpha' - ); + ]; protected function libScaleColor($args) { return $this->alterColor($args, function ($base, $scale, $i) { @@ -4152,7 +4152,7 @@ protected function libScaleColor($args) }); } - protected static $libIeHexStr = array('color'); + protected static $libIeHexStr = ['color']; protected function libIeHexStr($args) { $color = $this->coerceColor($args[0]); @@ -4161,7 +4161,7 @@ protected function libIeHexStr($args) return sprintf('#%02X%02X%02X%02X', $color[4], $color[1], $color[2], $color[3]); } - protected static $libRed = array('color'); + protected static $libRed = ['color']; protected function libRed($args) { $color = $this->coerceColor($args[0]); @@ -4169,7 +4169,7 @@ protected function libRed($args) return $color[1]; } - protected static $libGreen = array('color'); + protected static $libGreen = ['color']; protected function libGreen($args) { $color = $this->coerceColor($args[0]); @@ -4177,7 +4177,7 @@ protected function libGreen($args) return $color[2]; } - protected static $libBlue = array('color'); + protected static $libBlue = ['color']; protected function libBlue($args) { $color = $this->coerceColor($args[0]); @@ -4185,7 +4185,7 @@ protected function libBlue($args) return $color[3]; } - protected static $libAlpha = array('color'); + protected static $libAlpha = ['color']; protected function libAlpha($args) { if ($color = $this->coerceColor($args[0])) { @@ -4196,7 +4196,7 @@ protected function libAlpha($args) return null; } - protected static $libOpacity = array('color'); + protected static $libOpacity = ['color']; protected function libOpacity($args) { $value = $args[0]; @@ -4209,7 +4209,7 @@ protected function libOpacity($args) } // mix two colors - protected static $libMix = array('color-1', 'color-2', 'weight'); + protected static $libMix = ['color-1', 'color-2', 'weight']; protected function libMix($args) { list($first, $second, $weight) = $args; @@ -4232,11 +4232,11 @@ protected function libMix($args) $w1 = (($w * $a === -1 ? $w : ($w + $a) / (1 + $w * $a)) + 1) / 2.0; $w2 = 1.0 - $w1; - $new = array(Type::T_COLOR, + $new = [Type::T_COLOR, $w1 * $first[1] + $w2 * $second[1], $w1 * $first[2] + $w2 * $second[2], $w1 * $first[3] + $w2 * $second[3], - ); + ]; if ($firstAlpha != 1.0 || $secondAlpha != 1.0) { $new[] = $firstAlpha * $weight + $secondAlpha * ($weight - 1); @@ -4245,7 +4245,7 @@ protected function libMix($args) return $this->fixColor($new); } - protected static $libHsl = array('hue', 'saturation', 'lightness'); + protected static $libHsl = ['hue', 'saturation', 'lightness']; protected function libHsl($args) { list($h, $s, $l) = $args; @@ -4253,7 +4253,7 @@ protected function libHsl($args) return $this->toRGB($h[1], $s[1], $l[1]); } - protected static $libHsla = array('hue', 'saturation', 'lightness', 'alpha'); + protected static $libHsla = ['hue', 'saturation', 'lightness', 'alpha']; protected function libHsla($args) { list($h, $s, $l, $a) = $args; @@ -4264,7 +4264,7 @@ protected function libHsla($args) return $color; } - protected static $libHue = array('color'); + protected static $libHue = ['color']; protected function libHue($args) { $color = $this->assertColor($args[0]); @@ -4273,7 +4273,7 @@ protected function libHue($args) return new Node\Number($hsl[1], 'deg'); } - protected static $libSaturation = array('color'); + protected static $libSaturation = ['color']; protected function libSaturation($args) { $color = $this->assertColor($args[0]); @@ -4282,7 +4282,7 @@ protected function libSaturation($args) return new Node\Number($hsl[2], '%'); } - protected static $libLightness = array('color'); + protected static $libLightness = ['color']; protected function libLightness($args) { $color = $this->assertColor($args[0]); @@ -4304,7 +4304,7 @@ protected function adjustHsl($color, $idx, $amount) return $out; } - protected static $libAdjustHue = array('color', 'degrees'); + protected static $libAdjustHue = ['color', 'degrees']; protected function libAdjustHue($args) { $color = $this->assertColor($args[0]); @@ -4313,7 +4313,7 @@ protected function libAdjustHue($args) return $this->adjustHsl($color, 1, $degrees); } - protected static $libLighten = array('color', 'amount'); + protected static $libLighten = ['color', 'amount']; protected function libLighten($args) { $color = $this->assertColor($args[0]); @@ -4322,7 +4322,7 @@ protected function libLighten($args) return $this->adjustHsl($color, 3, $amount); } - protected static $libDarken = array('color', 'amount'); + protected static $libDarken = ['color', 'amount']; protected function libDarken($args) { $color = $this->assertColor($args[0]); @@ -4331,7 +4331,7 @@ protected function libDarken($args) return $this->adjustHsl($color, 3, -$amount); } - protected static $libSaturate = array('color', 'amount'); + protected static $libSaturate = ['color', 'amount']; protected function libSaturate($args) { $value = $args[0]; @@ -4346,7 +4346,7 @@ protected function libSaturate($args) return $this->adjustHsl($color, 2, $amount); } - protected static $libDesaturate = array('color', 'amount'); + protected static $libDesaturate = ['color', 'amount']; protected function libDesaturate($args) { $color = $this->assertColor($args[0]); @@ -4355,7 +4355,7 @@ protected function libDesaturate($args) return $this->adjustHsl($color, 2, -$amount); } - protected static $libGrayscale = array('color'); + protected static $libGrayscale = ['color']; protected function libGrayscale($args) { $value = $args[0]; @@ -4367,13 +4367,13 @@ protected function libGrayscale($args) return $this->adjustHsl($this->assertColor($value), 2, -100); } - protected static $libComplement = array('color'); + protected static $libComplement = ['color']; protected function libComplement($args) { return $this->adjustHsl($this->assertColor($args[0]), 1, 180); } - protected static $libInvert = array('color'); + protected static $libInvert = ['color']; protected function libInvert($args) { $value = $args[0]; @@ -4391,7 +4391,7 @@ protected function libInvert($args) } // increases opacity by amount - protected static $libOpacify = array('color', 'amount'); + protected static $libOpacify = ['color', 'amount']; protected function libOpacify($args) { $color = $this->assertColor($args[0]); @@ -4403,14 +4403,14 @@ protected function libOpacify($args) return $color; } - protected static $libFadeIn = array('color', 'amount'); + protected static $libFadeIn = ['color', 'amount']; protected function libFadeIn($args) { return $this->libOpacify($args); } // decreases opacity by amount - protected static $libTransparentize = array('color', 'amount'); + protected static $libTransparentize = ['color', 'amount']; protected function libTransparentize($args) { $color = $this->assertColor($args[0]); @@ -4422,13 +4422,13 @@ protected function libTransparentize($args) return $color; } - protected static $libFadeOut = array('color', 'amount'); + protected static $libFadeOut = ['color', 'amount']; protected function libFadeOut($args) { return $this->libTransparentize($args); } - protected static $libUnquote = array('string'); + protected static $libUnquote = ['string']; protected function libUnquote($args) { $str = $args[0]; @@ -4440,7 +4440,7 @@ protected function libUnquote($args) return $str; } - protected static $libQuote = array('string'); + protected static $libQuote = ['string']; protected function libQuote($args) { $value = $args[0]; @@ -4449,16 +4449,16 @@ protected function libQuote($args) return $value; } - return array(Type::T_STRING, '"', array($value)); + return [Type::T_STRING, '"', [$value]]; } - protected static $libPercentage = array('value'); + protected static $libPercentage = ['value']; protected function libPercentage($args) { return new Node\Number($this->coercePercent($args[0]) * 100, '%'); } - protected static $libRound = array('value'); + protected static $libRound = ['value']; protected function libRound($args) { $num = $args[0]; @@ -4467,7 +4467,7 @@ protected function libRound($args) return $num; } - protected static $libFloor = array('value'); + protected static $libFloor = ['value']; protected function libFloor($args) { $num = $args[0]; @@ -4476,7 +4476,7 @@ protected function libFloor($args) return $num; } - protected static $libCeil = array('value'); + protected static $libCeil = ['value']; protected function libCeil($args) { $num = $args[0]; @@ -4485,7 +4485,7 @@ protected function libCeil($args) return $num; } - protected static $libAbs = array('value'); + protected static $libAbs = ['value']; protected function libAbs($args) { $num = $args[0]; @@ -4501,7 +4501,7 @@ protected function libMin($args) foreach ($numbers as $key => $number) { if (null === $min || $number[1] <= $min[1]) { - $min = array($key, $number[1]); + $min = [$key, $number[1]]; } } @@ -4515,7 +4515,7 @@ protected function libMax($args) foreach ($numbers as $key => $number) { if (null === $max || $number[1] >= $max[1]) { - $max = array($key, $number[1]); + $max = [$key, $number[1]]; } } @@ -4533,7 +4533,7 @@ protected function getNormalizedNumbers($args) { $unit = null; $originalUnit = null; - $numbers = array(); + $numbers = []; foreach ($args as $key => $item) { if ($item[0] !== Type::T_NUMBER) { @@ -4557,7 +4557,7 @@ protected function getNormalizedNumbers($args) return $numbers; } - protected static $libLength = array('list'); + protected static $libLength = ['list']; protected function libLength($args) { $list = $this->coerceList($args[0]); @@ -4565,7 +4565,7 @@ protected function libLength($args) return count($list[2]); } - //protected static $libListSeparator = array('list...'); + //protected static $libListSeparator = ['list...']; protected function libListSeparator($args) { if (count($args) > 1) { @@ -4585,7 +4585,7 @@ protected function libListSeparator($args) return 'space'; } - protected static $libNth = array('list', 'n'); + protected static $libNth = ['list', 'n']; protected function libNth($args) { $list = $this->coerceList($args[0]); @@ -4600,7 +4600,7 @@ protected function libNth($args) return isset($list[2][$n]) ? $list[2][$n] : self::$defaultValue; } - protected static $libSetNth = array('list', 'n', 'value'); + protected static $libSetNth = ['list', 'n', 'value']; protected function libSetNth($args) { $list = $this->coerceList($args[0]); @@ -4623,7 +4623,7 @@ protected function libSetNth($args) return $list; } - protected static $libMapGet = array('map', 'key'); + protected static $libMapGet = ['map', 'key']; protected function libMapGet($args) { $map = $this->assertMap($args[0]); @@ -4638,25 +4638,25 @@ protected function libMapGet($args) return self::$null; } - protected static $libMapKeys = array('map'); + protected static $libMapKeys = ['map']; protected function libMapKeys($args) { $map = $this->assertMap($args[0]); $keys = $map[1]; - return array(Type::T_LIST, ',', $keys); + return [Type::T_LIST, ',', $keys]; } - protected static $libMapValues = array('map'); + protected static $libMapValues = ['map']; protected function libMapValues($args) { $map = $this->assertMap($args[0]); $values = $map[2]; - return array(Type::T_LIST, ',', $values); + return [Type::T_LIST, ',', $values]; } - protected static $libMapRemove = array('map', 'key'); + protected static $libMapRemove = ['map', 'key']; protected function libMapRemove($args) { $map = $this->assertMap($args[0]); @@ -4672,7 +4672,7 @@ protected function libMapRemove($args) return $map; } - protected static $libMapHasKey = array('map', 'key'); + protected static $libMapHasKey = ['map', 'key']; protected function libMapHasKey($args) { $map = $this->assertMap($args[0]); @@ -4687,29 +4687,29 @@ protected function libMapHasKey($args) return false; } - protected static $libMapMerge = array('map-1', 'map-2'); + protected static $libMapMerge = ['map-1', 'map-2']; protected function libMapMerge($args) { $map1 = $this->assertMap($args[0]); $map2 = $this->assertMap($args[1]); - return array(Type::T_MAP, array_merge($map1[1], $map2[1]), array_merge($map1[2], $map2[2])); + return [Type::T_MAP, array_merge($map1[1], $map2[1]), array_merge($map1[2], $map2[2])]; } - protected static $libKeywords = array('args'); + protected static $libKeywords = ['args']; protected function libKeywords($args) { $this->assertList($args[0]); - $keys = array(); - $values = array(); + $keys = []; + $values = []; foreach ($args[0][2] as $name => $arg) { - $keys[] = array(Type::T_KEYWORD, $name); + $keys[] = [Type::T_KEYWORD, $name]; $values[] = $arg; } - return array(Type::T_MAP, $keys, $values); + return [Type::T_MAP, $keys, $values]; } protected function listSeparatorForJoin($list1, $sep) @@ -4730,7 +4730,7 @@ protected function listSeparatorForJoin($list1, $sep) } } - protected static $libJoin = array('list1', 'list2', 'separator'); + protected static $libJoin = ['list1', 'list2', 'separator']; protected function libJoin($args) { list($list1, $list2, $sep) = $args; @@ -4739,10 +4739,10 @@ protected function libJoin($args) $list2 = $this->coerceList($list2, ' '); $sep = $this->listSeparatorForJoin($list1, $sep); - return array(Type::T_LIST, $sep, array_merge($list1[2], $list2[2])); + return [Type::T_LIST, $sep, array_merge($list1[2], $list2[2])]; } - protected static $libAppend = array('list', 'val', 'separator'); + protected static $libAppend = ['list', 'val', 'separator']; protected function libAppend($args) { list($list1, $value, $sep) = $args; @@ -4750,7 +4750,7 @@ protected function libAppend($args) $list1 = $this->coerceList($list1, ' '); $sep = $this->listSeparatorForJoin($list1, $sep); - return array(Type::T_LIST, $sep, array_merge($list1[2], array($value))); + return [Type::T_LIST, $sep, array_merge($list1[2], [$value])]; } protected function libZip($args) @@ -4759,11 +4759,11 @@ protected function libZip($args) $this->assertList($arg); } - $lists = array(); + $lists = []; $firstList = array_shift($args); foreach ($firstList[2] as $key => $item) { - $list = array(Type::T_LIST, '', array($item)); + $list = [Type::T_LIST, '', [$item]]; foreach ($args as $arg) { if (isset($arg[2][$key])) { @@ -4776,10 +4776,10 @@ protected function libZip($args) $lists[] = $list; } - return array(Type::T_LIST, ',', $lists); + return [Type::T_LIST, ',', $lists]; } - protected static $libTypeOf = array('value'); + protected static $libTypeOf = ['value']; protected function libTypeOf($args) { $value = $args[0]; @@ -4809,19 +4809,19 @@ protected function libTypeOf($args) } } - protected static $libUnit = array('number'); + protected static $libUnit = ['number']; protected function libUnit($args) { $num = $args[0]; if ($num[0] === Type::T_NUMBER) { - return array(Type::T_STRING, '"', array($num->unitStr())); + return [Type::T_STRING, '"', [$num->unitStr()]]; } return ''; } - protected static $libUnitless = array('number'); + protected static $libUnitless = ['number']; protected function libUnitless($args) { $value = $args[0]; @@ -4829,7 +4829,7 @@ protected function libUnitless($args) return $value[0] === Type::T_NUMBER && $value->unitless(); } - protected static $libComparable = array('number-1', 'number-2'); + protected static $libComparable = ['number-1', 'number-2']; protected function libComparable($args) { list($number1, $number2) = $args; @@ -4848,7 +4848,7 @@ protected function libComparable($args) return $number1[2] === $number2[2] || $number1->unitless() || $number2->unitless(); } - protected static $libStrIndex = array('string', 'substring'); + protected static $libStrIndex = ['string', 'substring']; protected function libStrIndex($args) { $string = $this->coerceString($args[0]); @@ -4862,7 +4862,7 @@ protected function libStrIndex($args) return $result === false ? self::$null : new Node\Number($result + 1, ''); } - protected static $libStrInsert = array('string', 'insert', 'index'); + protected static $libStrInsert = ['string', 'insert', 'index']; protected function libStrInsert($args) { $string = $this->coerceString($args[0]); @@ -4873,12 +4873,12 @@ protected function libStrInsert($args) list(, $index) = $args[2]; - $string[2] = array(substr_replace($stringContent, $insertContent, $index - 1, 0)); + $string[2] = [substr_replace($stringContent, $insertContent, $index - 1, 0)]; return $string; } - protected static $libStrLength = array('string'); + protected static $libStrLength = ['string']; protected function libStrLength($args) { $string = $this->coerceString($args[0]); @@ -4887,7 +4887,7 @@ protected function libStrLength($args) return new Node\Number(strlen($stringContent), ''); } - protected static $libStrSlice = array('string', 'start-at', 'end-at'); + protected static $libStrSlice = ['string', 'start-at', 'end-at']; protected function libStrSlice($args) { if (isset($args[2]) && $args[2][1] == 0) { @@ -4907,35 +4907,35 @@ protected function libStrSlice($args) $length = $end < 0 ? $end + 1 : ($end > 0 ? $end - $start : $end); $string[2] = $length - ? array(substr($stringContent, $start, $length)) - : array(substr($stringContent, $start)); + ? [substr($stringContent, $start, $length)] + : [substr($stringContent, $start)]; return $string; } - protected static $libToLowerCase = array('string'); + protected static $libToLowerCase = ['string']; protected function libToLowerCase($args) { $string = $this->coerceString($args[0]); $stringContent = $this->compileStringContent($string); - $string[2] = array(mb_strtolower($stringContent)); + $string[2] = [mb_strtolower($stringContent)]; return $string; } - protected static $libToUpperCase = array('string'); + protected static $libToUpperCase = ['string']; protected function libToUpperCase($args) { $string = $this->coerceString($args[0]); $stringContent = $this->compileStringContent($string); - $string[2] = array(mb_strtoupper($stringContent)); + $string[2] = [mb_strtoupper($stringContent)]; return $string; } - protected static $libFeatureExists = array('feature'); + protected static $libFeatureExists = ['feature']; protected function libFeatureExists($args) { $string = $this->coerceString($args[0]); @@ -4946,7 +4946,7 @@ protected function libFeatureExists($args) ); } - protected static $libFunctionExists = array('name'); + protected static $libFunctionExists = ['name']; protected function libFunctionExists($args) { $string = $this->coerceString($args[0]); @@ -4969,7 +4969,7 @@ protected function libFunctionExists($args) return $this->toBool(is_callable($f)); } - protected static $libGlobalVariableExists = array('name'); + protected static $libGlobalVariableExists = ['name']; protected function libGlobalVariableExists($args) { $string = $this->coerceString($args[0]); @@ -4978,7 +4978,7 @@ protected function libGlobalVariableExists($args) return $this->has($name, $this->rootEnv); } - protected static $libMixinExists = array('name'); + protected static $libMixinExists = ['name']; protected function libMixinExists($args) { $string = $this->coerceString($args[0]); @@ -4987,7 +4987,7 @@ protected function libMixinExists($args) return $this->has(self::$namespaces['mixin'] . $name); } - protected static $libVariableExists = array('name'); + protected static $libVariableExists = ['name']; protected function libVariableExists($args) { $string = $this->coerceString($args[0]); @@ -5003,12 +5003,12 @@ protected function libVariableExists($args) */ protected function libCounter($args) { - $list = array_map(array($this, 'compileValue'), $args); + $list = array_map([$this, 'compileValue'], $args); - return array(Type::T_STRING, '', array('counter(' . implode(',', $list) . ')')); + return [Type::T_STRING, '', ['counter(' . implode(',', $list) . ')']]; } - protected static $libRandom = array('limit'); + protected static $libRandom = ['limit']; protected function libRandom($args) { if (isset($args[0])) { @@ -5036,14 +5036,14 @@ protected function libUniqueId() $id += mt_rand(0, 10) + 1; - return array(Type::T_STRING, '', array('u' . str_pad(base_convert($id, 10, 36), 8, '0', STR_PAD_LEFT))); + return [Type::T_STRING, '', ['u' . str_pad(base_convert($id, 10, 36), 8, '0', STR_PAD_LEFT)]]; } - protected static $libInspect = array('value'); + protected static $libInspect = ['value']; protected function libInspect($args) { if ($args[0] === self::$null) { - return array(Type::T_KEYWORD, 'null'); + return [Type::T_KEYWORD, 'null']; } return $args[0]; diff --git a/src/Formatter/Nested.php b/src/Formatter/Nested.php index 6fab43dc..ed9f075b 100644 --- a/src/Formatter/Nested.php +++ b/src/Formatter/Nested.php @@ -154,7 +154,7 @@ protected function block(OutputBlock $block) private function adjustAllChildren(OutputBlock $block) { // flatten empty nested blocks - $children = array(); + $children = []; foreach ($block->children as $i => $child) { if (empty($child->lines) && empty($child->children)) { diff --git a/src/Node/Number.php b/src/Node/Number.php index 6549f495..a803a6ca 100644 --- a/src/Node/Number.php +++ b/src/Node/Number.php @@ -38,8 +38,8 @@ class Number extends Node implements \ArrayAccess * * @var array */ - static protected $unitTable = array( - 'in' => array( + static protected $unitTable = [ + 'in' => [ 'in' => 1, 'pc' => 6, 'pt' => 72, @@ -47,27 +47,27 @@ class Number extends Node implements \ArrayAccess 'cm' => 2.54, 'mm' => 25.4, 'q' => 101.6, - ), - 'turn' => array( + ], + 'turn' => [ 'deg' => 360, 'grad' => 400, 'rad' => 6.28318530717958647692528676, // 2 * M_PI 'turn' => 1, - ), - 's' => array( + ], + 's' => [ 's' => 1, 'ms' => 1000, - ), - 'Hz' => array( + ], + 'Hz' => [ 'Hz' => 1, 'kHz' => 0.001, - ), - 'dpi' => array( + ], + 'dpi' => [ 'dpi' => 1, 'dpcm' => 2.54, 'dppx' => 96, - ), - ); + ], + ]; /** * @var integer|float @@ -91,8 +91,8 @@ public function __construct($dimension, $initialUnit) $this->dimension = $dimension; $this->units = is_array($initialUnit) ? $initialUnit - : ($initialUnit ? array($initialUnit => 1) - : array()); + : ($initialUnit ? [$initialUnit => 1] + : []); } /** @@ -128,7 +128,7 @@ public function coerce($units) public function normalize() { $dimension = $this->dimension; - $units = array(); + $units = []; $this->normalizeUnits($dimension, $units, 'in'); @@ -238,8 +238,8 @@ public function unitless() */ public function unitStr() { - $numerators = array(); - $denominators = array(); + $numerators = []; + $denominators = []; foreach ($this->units as $unit => $unitSize) { if ($unitSize > 0) { @@ -273,7 +273,7 @@ public function output(Compiler $compiler = null) if (count($units) > 1 && array_sum($units) === 0) { $dimension = $this->dimension; - $units = array(); + $units = []; $this->normalizeUnits($dimension, $units, 'in'); @@ -313,7 +313,7 @@ public function __toString() private function normalizeUnits(&$dimension, &$units, $baseUnit = 'in') { $dimension = $this->dimension; - $units = array(); + $units = []; foreach ($this->units as $unit => $exp) { if (isset(self::$unitTable[$baseUnit][$unit])) { diff --git a/src/Parser.php b/src/Parser.php index 562ea701..95e26049 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -31,7 +31,7 @@ class Parser /** * @var array */ - protected static $precedence = array( + protected static $precedence = [ '=' => 0, 'or' => 1, 'and' => 2, @@ -47,7 +47,7 @@ class Parser '*' => 6, '/' => 6, '%' => 6, - ); + ]; protected static $commentPattern; protected static $operatorPattern; @@ -321,8 +321,7 @@ protected function parseChunk() ($this->end() || $this->literal('{') && $hasBlock = true) ) { - $child = array(Type::T_INCLUDE, - $mixinName, isset($argValues) ? $argValues : null, null); + $child = [Type::T_INCLUDE, $mixinName, isset($argValues) ? $argValues : null, null]; if (! empty($hasBlock)) { $include = $this->pushSpecialBlock(Type::T_INCLUDE, $s); @@ -340,7 +339,7 @@ protected function parseChunk() $this->valueList($importPath) && $this->end() ) { - $this->append(array(Type::T_SCSSPHP_IMPORT_ONCE, $importPath), $s); + $this->append([Type::T_SCSSPHP_IMPORT_ONCE, $importPath], $s); return true; } @@ -351,7 +350,7 @@ protected function parseChunk() $this->valueList($importPath) && $this->end() ) { - $this->append(array(Type::T_IMPORT, $importPath), $s); + $this->append([Type::T_IMPORT, $importPath], $s); return true; } @@ -362,7 +361,7 @@ protected function parseChunk() $this->url($importPath) && $this->end() ) { - $this->append(array(Type::T_IMPORT, $importPath), $s); + $this->append([Type::T_IMPORT, $importPath], $s); return true; } @@ -375,7 +374,7 @@ protected function parseChunk() ) { // check for '!flag' $optional = $this->stripOptionalFlag($selectors); - $this->append(array(Type::T_EXTEND, $selectors, $optional), $s); + $this->append([Type::T_EXTEND, $selectors, $optional], $s); return true; } @@ -397,7 +396,7 @@ protected function parseChunk() $this->seek($s); if ($this->literal('@break') && $this->end()) { - $this->append(array(Type::T_BREAK), $s); + $this->append([Type::T_BREAK], $s); return true; } @@ -405,7 +404,7 @@ protected function parseChunk() $this->seek($s); if ($this->literal('@continue') && $this->end()) { - $this->append(array(Type::T_CONTINUE), $s); + $this->append([Type::T_CONTINUE], $s); return true; } @@ -414,7 +413,7 @@ protected function parseChunk() if ($this->literal('@return') && ($this->valueList($retVal) || true) && $this->end()) { - $this->append(array(Type::T_RETURN, isset($retVal) ? $retVal : array(Type::T_NULL)), $s); + $this->append([Type::T_RETURN, isset($retVal) ? $retVal : [Type::T_NULL]], $s); return true; } @@ -475,7 +474,7 @@ protected function parseChunk() if ($this->literal('@if') && $this->valueList($cond) && $this->literal('{')) { $if = $this->pushSpecialBlock(Type::T_IF, $s); $if->cond = $cond; - $if->cases = array(); + $if->cases = []; return true; } @@ -486,7 +485,7 @@ protected function parseChunk() $this->valueList($value) && $this->end() ) { - $this->append(array(Type::T_DEBUG, $value), $s); + $this->append([Type::T_DEBUG, $value], $s); return true; } @@ -497,7 +496,7 @@ protected function parseChunk() $this->valueList($value) && $this->end() ) { - $this->append(array(Type::T_WARN, $value), $s); + $this->append([Type::T_WARN, $value], $s); return true; } @@ -508,7 +507,7 @@ protected function parseChunk() $this->valueList($value) && $this->end() ) { - $this->append(array(Type::T_ERROR, $value), $s); + $this->append([Type::T_ERROR, $value], $s); return true; } @@ -516,7 +515,7 @@ protected function parseChunk() $this->seek($s); if ($this->literal('@content') && $this->end()) { - $this->append(array(Type::T_MIXIN_CONTENT), $s); + $this->append([Type::T_MIXIN_CONTENT], $s); return true; } @@ -553,7 +552,7 @@ protected function parseChunk() $this->end() ) { if (! isset($this->charset)) { - $statement = array(Type::T_CHARSET, $charset); + $statement = [Type::T_CHARSET, $charset]; list($line, $column) = $this->getSourcePosition($s); @@ -601,8 +600,8 @@ protected function parseChunk() $this->valueList($value) && $this->end() ) { - $name = array(Type::T_STRING, '', array($name)); - $this->append(array(Type::T_ASSIGN, $name, $value), $s); + $name = [Type::T_STRING, '', [$name]]; + $this->append([Type::T_ASSIGN, $name, $value], $s); return true; } @@ -617,7 +616,7 @@ protected function parseChunk() ) { // check for '!flag' $assignmentFlag = $this->stripAssignmentFlag($value); - $this->append(array(Type::T_ASSIGN, $name, $value, $assignmentFlag), $s); + $this->append([Type::T_ASSIGN, $name, $value, $assignmentFlag], $s); return true; } @@ -643,7 +642,7 @@ protected function parseChunk() $foundSomething = false; if ($this->valueList($value)) { - $this->append(array(Type::T_ASSIGN, $name, $value), $s); + $this->append([Type::T_ASSIGN, $name, $value], $s); $foundSomething = true; } @@ -673,7 +672,7 @@ protected function parseChunk() $this->append($include, $s); } elseif (empty($block->dontAppend)) { $type = isset($block->type) ? $block->type : Type::T_BLOCK; - $this->append(array($type, $block), $s); + $this->append([$type, $block], $s); } return true; @@ -706,18 +705,18 @@ protected function pushBlock($selectors, $pos = 0) $b->sourceColumn = $column; $b->sourceIndex = $this->sourceIndex; $b->selectors = $selectors; - $b->comments = array(); + $b->comments = []; $b->parent = $this->env; if (! $this->env) { - $b->children = array(); + $b->children = []; } elseif (empty($this->env->children)) { $this->env->children = $this->env->comments; - $b->children = array(); - $this->env->comments = array(); + $b->children = []; + $this->env->comments = []; } else { $b->children = $this->env->comments; - $this->env->comments = array(); + $this->env->comments = []; } $this->env = $b; @@ -824,7 +823,7 @@ protected function matchString(&$m, $delim) $end = strlen($this->buffer); // look for either ending delim, escape, or string interpolation - foreach (array('#{', '\\', $delim) as $lookahead) { + foreach (['#{', '\\', $delim] as $lookahead) { $pos = strpos($this->buffer, $lookahead, $this->count); if ($pos !== false && $pos < $end) { @@ -838,11 +837,11 @@ protected function matchString(&$m, $delim) } $match = substr($this->buffer, $this->count, $end - $this->count); - $m = array( + $m = [ $match . $token, $match, $token - ); + ]; $this->count = $end + strlen($token); return true; @@ -921,7 +920,7 @@ protected function whitespace() while (preg_match(self::$whitePattern, $this->buffer, $m, null, $this->count)) { if (isset($m[1]) && empty($this->commentsSeen[$this->count])) { - $this->appendComment(array(Type::T_COMMENT, $m[1])); + $this->appendComment([Type::T_COMMENT, $m[1]]); $this->commentsSeen[$this->count] = true; } @@ -940,7 +939,7 @@ protected function whitespace() */ protected function appendComment($comment) { - $comment[1] = substr(preg_replace(array('/^\s+/m', '/^(.)/m'), array('', ' \1'), $comment[1]), 1); + $comment[1] = substr(preg_replace(['/^\s+/m', '/^(.)/m'], ['', ' \1'], $comment[1]), 1); $this->env->comments[] = $comment; } @@ -967,7 +966,7 @@ protected function append($statement, $pos = null) if (count($comments)) { $this->env->children = array_merge($this->env->children, $comments); - $this->env->comments = array(); + $this->env->comments = []; } } @@ -1007,28 +1006,28 @@ protected function mediaQueryList(&$out) protected function mediaQuery(&$out) { $expressions = null; - $parts = array(); + $parts = []; if (($this->literal('only') && ($only = true) || $this->literal('not') && ($not = true) || true) && $this->mixedKeyword($mediaType) ) { - $prop = array(Type::T_MEDIA_TYPE); + $prop = [Type::T_MEDIA_TYPE]; if (isset($only)) { - $prop[] = array(Type::T_KEYWORD, 'only'); + $prop[] = [Type::T_KEYWORD, 'only']; } if (isset($not)) { - $prop[] = array(Type::T_KEYWORD, 'not'); + $prop[] = [Type::T_KEYWORD, 'not']; } - $media = array(Type::T_LIST, '', array()); + $media = [Type::T_LIST, '', []]; - foreach ((array)$mediaType as $type) { + foreach ((array) $mediaType as $type) { if (is_array($type)) { $media[2][] = $type; } else { - $media[2][] = array(Type::T_KEYWORD, $type); + $media[2][] = [Type::T_KEYWORD, $type]; } } @@ -1066,7 +1065,7 @@ protected function mediaExpression(&$out) ($this->literal(':') && $this->expression($value) || true) && $this->literal(')') ) { - $out = array(Type::T_MEDIA_EXPRESSION, $feature); + $out = [Type::T_MEDIA_EXPRESSION, $feature]; if ($value) { $out[] = $value; @@ -1117,7 +1116,7 @@ protected function argValue(&$out) } if ($this->genericList($value, 'expression')) { - $out = array($keyword, $value, false); + $out = [$keyword, $value, false]; $s = $this->seek(); if ($this->literal('...')) { @@ -1169,7 +1168,7 @@ protected function spaceList(&$out) protected function genericList(&$out, $parseItem, $delim = '', $flatten = true) { $s = $this->seek(); - $items = array(); + $items = []; while ($this->$parseItem($value)) { $items[] = $value; @@ -1190,7 +1189,7 @@ protected function genericList(&$out, $parseItem, $delim = '', $flatten = true) if ($flatten && count($items) === 1) { $out = $items[0]; } else { - $out = array(Type::T_LIST, $delim, $items); + $out = [Type::T_LIST, $delim, $items]; } return true; @@ -1209,7 +1208,7 @@ protected function expression(&$out) if ($this->literal('(')) { if ($this->literal(')')) { - $out = array(Type::T_LIST, '', array()); + $out = [Type::T_LIST, '', []]; return true; } @@ -1276,7 +1275,7 @@ protected function expHelper($lhs, $minP) $rhs = $this->expHelper($rhs, self::$precedence[$next[1]]); } - $lhs = array(Type::T_EXPRESSION, $op, $lhs, $rhs, $this->inParens, $whiteBefore, $whiteAfter); + $lhs = [Type::T_EXPRESSION, $op, $lhs, $rhs, $this->inParens, $whiteBefore, $whiteAfter]; $ss = $this->seek(); $whiteBefore = isset($this->buffer[$this->count - 1]) && ctype_space($this->buffer[$this->count - 1]); @@ -1299,7 +1298,7 @@ protected function value(&$out) $s = $this->seek(); if ($this->literal('not', false) && $this->whitespace() && $this->value($inner)) { - $out = array(Type::T_UNARY, 'not', $inner, $this->inParens); + $out = [Type::T_UNARY, 'not', $inner, $this->inParens]; return true; } @@ -1307,7 +1306,7 @@ protected function value(&$out) $this->seek($s); if ($this->literal('not', false) && $this->parenValue($inner)) { - $out = array(Type::T_UNARY, 'not', $inner, $this->inParens); + $out = [Type::T_UNARY, 'not', $inner, $this->inParens]; return true; } @@ -1315,7 +1314,7 @@ protected function value(&$out) $this->seek($s); if ($this->literal('+') && $this->value($inner)) { - $out = array(Type::T_UNARY, '+', $inner, $this->inParens); + $out = [Type::T_UNARY, '+', $inner, $this->inParens]; return true; } @@ -1328,7 +1327,7 @@ protected function value(&$out) $this->unit($inner) || $this->parenValue($inner)) ) { - $out = array(Type::T_UNARY, '-', $inner, $this->inParens); + $out = [Type::T_UNARY, '-', $inner, $this->inParens]; return true; } @@ -1349,9 +1348,9 @@ protected function value(&$out) if ($this->keyword($keyword)) { if ($keyword === 'null') { - $out = array(Type::T_NULL); + $out = [Type::T_NULL]; } else { - $out = array(Type::T_KEYWORD, $keyword); + $out = [Type::T_KEYWORD, $keyword]; } return true; @@ -1375,7 +1374,7 @@ protected function parenValue(&$out) if ($this->literal('(')) { if ($this->literal(')')) { - $out = array(Type::T_LIST, '', array()); + $out = [Type::T_LIST, '', []]; return true; } @@ -1414,9 +1413,9 @@ protected function progid(&$out) $this->openString(')', $args, '('); if ($this->literal(')')) { - $out = array(Type::T_STRING, '', array( + $out = [Type::T_STRING, '', [ 'progid:', $fn, '(', $args, ')' - )); + ]]; return true; } @@ -1442,7 +1441,7 @@ protected function func(&$func) $this->literal('(') ) { if ($name === 'alpha' && $this->argumentList($args)) { - $func = array(Type::T_FUNCTION, $name, array(Type::T_STRING, '', $args)); + $func = [Type::T_FUNCTION, $name, [Type::T_STRING, '', $args]]; return true; } @@ -1451,7 +1450,7 @@ protected function func(&$func) $ss = $this->seek(); if ($this->argValues($args) && $this->literal(')')) { - $func = array(Type::T_FUNCTION_CALL, $name, $args); + $func = [Type::T_FUNCTION_CALL, $name, $args]; return true; } @@ -1462,13 +1461,13 @@ protected function func(&$func) if (($this->openString(')', $str, '(') || true) && $this->literal(')') ) { - $args = array(); + $args = []; if (! empty($str)) { - $args[] = array(null, array(Type::T_STRING, '', array($str))); + $args[] = [null, [Type::T_STRING, '', [$str]]]; } - $func = array(Type::T_FUNCTION_CALL, $name, $args); + $func = [Type::T_FUNCTION_CALL, $name, $args]; return true; } @@ -1491,11 +1490,11 @@ protected function argumentList(&$out) $s = $this->seek(); $this->literal('('); - $args = array(); + $args = []; while ($this->keyword($var)) { if ($this->literal('=') && $this->expression($exp)) { - $args[] = array(Type::T_STRING, '', array($var . '=')); + $args[] = [Type::T_STRING, '', [$var . '=']]; $arg = $exp; } else { break; @@ -1507,7 +1506,7 @@ protected function argumentList(&$out) break; } - $args[] = array(Type::T_STRING, '', array(', ')); + $args[] = [Type::T_STRING, '', [', ']]; } if (! $this->literal(')') || ! count($args)) { @@ -1533,10 +1532,10 @@ protected function argumentDef(&$out) $s = $this->seek(); $this->literal('('); - $args = array(); + $args = []; while ($this->variable($var)) { - $arg = array($var[1], null, false); + $arg = [$var[1], null, false]; $ss = $this->seek(); @@ -1594,8 +1593,8 @@ protected function map(&$out) return false; } - $keys = array(); - $values = array(); + $keys = []; + $values = []; while ($this->genericList($key, 'expression') && $this->literal(':') && $this->genericList($value, 'expression') @@ -1614,7 +1613,7 @@ protected function map(&$out) return false; } - $out = array(Type::T_MAP, $keys, $values); + $out = [Type::T_MAP, $keys, $values]; return true; } @@ -1628,13 +1627,13 @@ protected function map(&$out) */ protected function color(&$out) { - $color = array(Type::T_COLOR); + $color = [Type::T_COLOR]; if ($this->match('(#([0-9a-f]{6})|#([0-9a-f]{3}))', $m)) { if (isset($m[3])) { $num = hexdec($m[3]); - foreach (array(3, 2, 1) as $i) { + foreach ([3, 2, 1] as $i) { $t = $num & 0xf; $color[$i] = $t << 4 | $t; $num >>= 4; @@ -1642,7 +1641,7 @@ protected function color(&$out) } else { $num = hexdec($m[2]); - foreach (array(3, 2, 1) as $i) { + foreach ([3, 2, 1] as $i) { $color[$i] = $num & 0xff; $num >>= 8; } @@ -1693,7 +1692,7 @@ protected function string(&$out) return false; } - $content = array(); + $content = []; $oldWhite = $this->eatWhiteDefault; $this->eatWhiteDefault = false; $hasInterpolation = false; @@ -1742,7 +1741,7 @@ protected function string(&$out) } } - $out = array(Type::T_STRING, $delim, $content); + $out = [Type::T_STRING, $delim, $content]; return true; } @@ -1761,7 +1760,7 @@ protected function string(&$out) */ protected function mixedKeyword(&$out) { - $parts = array(); + $parts = []; $oldWhite = $this->eatWhiteDefault; $this->eatWhiteDefault = false; @@ -1813,7 +1812,7 @@ protected function openString($end, &$out, $nestingOpen = null) $nestingLevel = 0; - $content = array(); + $content = []; while ($this->match($patt, $m, false)) { if (isset($m[1]) && $m[1] !== '') { @@ -1857,7 +1856,7 @@ protected function openString($end, &$out, $nestingOpen = null) $content[count($content) - 1] = rtrim(end($content)); } - $out = array(Type::T_STRING, '', $content); + $out = [Type::T_STRING, '', $content]; return true; } @@ -1885,7 +1884,7 @@ protected function interpolation(&$out, $lookWhite = true) $left = $right = false; } - $out = array(Type::T_INTERPOLATE, $value, $left, $right); + $out = [Type::T_INTERPOLATE, $value, $left, $right]; $this->eatWhiteDefault = $oldWhite; if ($this->eatWhiteDefault) { @@ -1910,7 +1909,7 @@ protected function interpolation(&$out, $lookWhite = true) */ protected function propertyName(&$out) { - $parts = array(); + $parts = []; $oldWhite = $this->eatWhiteDefault; $this->eatWhiteDefault = false; @@ -1957,7 +1956,7 @@ protected function propertyName(&$out) $this->whitespace(); // get any extra whitespace - $out = array(Type::T_STRING, '', $parts); + $out = [Type::T_STRING, '', $parts]; return true; } @@ -1972,7 +1971,7 @@ protected function propertyName(&$out) protected function selectors(&$out) { $s = $this->seek(); - $selectors = array(); + $selectors = []; while ($this->selector($sel)) { $selectors[] = $sel; @@ -2006,11 +2005,11 @@ protected function selectors(&$out) */ protected function selector(&$out) { - $selector = array(); + $selector = []; for (;;) { if ($this->match('[>+~]+', $m)) { - $selector[] = array($m[0]); + $selector[] = [$m[0]]; continue; } @@ -2021,7 +2020,7 @@ protected function selector(&$out) } if ($this->match('\/[^\/]+\/', $m)) { - $selector[] = array($m[0]); + $selector[] = [$m[0]]; continue; } @@ -2052,7 +2051,7 @@ protected function selectorSingle(&$out) $oldWhite = $this->eatWhiteDefault; $this->eatWhiteDefault = false; - $parts = array(); + $parts = []; if ($this->literal('*', false)) { $parts[] = '*'; @@ -2189,7 +2188,7 @@ protected function variable(&$out) $s = $this->seek(); if ($this->literal('$', false) && $this->keyword($name)) { - $out = array(Type::T_VARIABLE, $name); + $out = [Type::T_VARIABLE, $name]; return true; } @@ -2257,7 +2256,7 @@ protected function placeholder(&$placeholder) protected function url(&$out) { if ($this->match('(url\(\s*(["\']?)([^)]+)\2\s*\))', $m)) { - $out = array(Type::T_STRING, '', array('url(' . $m[2] . $m[3] . $m[2] . ')')); + $out = [Type::T_STRING, '', ['url(' . $m[2] . $m[3] . $m[2] . ')']]; return true; } @@ -2298,7 +2297,7 @@ protected function stripAssignmentFlag(&$value) for ($token = &$value; $token[0] === Type::T_LIST && ($s = count($token[2])); $token = &$lastNode) { $lastNode = &$token[2][$s - 1]; - if ($lastNode[0] === Type::T_KEYWORD && in_array($lastNode[1], array('!default', '!global'))) { + if ($lastNode[0] === Type::T_KEYWORD && in_array($lastNode[1], ['!default', '!global'])) { array_pop($token[2]); $token = $this->flattenList($token); @@ -2324,7 +2323,7 @@ protected function stripOptionalFlag(&$selectors) $selector = end($selectors); $part = end($selector); - if ($part === array('!optional')) { + if ($part === ['!optional']) { array_pop($selectors[count($selectors) - 1]); $optional = true; @@ -2410,7 +2409,7 @@ private function pregQuote($what) */ private function extractLineNumbers($buffer) { - $this->sourcePositions = array(0 => 0); + $this->sourcePositions = [0 => 0]; $prev = 0; while (($pos = strpos($buffer, "\n", $prev)) !== false) { @@ -2450,10 +2449,10 @@ private function getSourcePosition($pos) continue; } - return array($mid + 1, $pos - $this->sourcePositions[$mid]); + return [$mid + 1, $pos - $this->sourcePositions[$mid]]; } - return array($low + 1, $pos - $this->sourcePositions[$low]); + return [$low + 1, $pos - $this->sourcePositions[$low]]; } /** diff --git a/src/Server.php b/src/Server.php index e34ff5c3..221655ca 100644 --- a/src/Server.php +++ b/src/Server.php @@ -214,14 +214,14 @@ protected function compile($in, $out) file_put_contents($out, $css); file_put_contents( $this->metadataName($out), - serialize(array( + serialize([ 'etag' => $etag, 'imports' => $this->scss->getParsedFiles(), 'vars' => crc32(serialize($this->scss->getVariables())), - )) + ]) ); - return array($css, $etag); + return [$css, $etag]; } /** @@ -234,8 +234,8 @@ protected function compile($in, $out) protected function createErrorCSS(\Exception $error) { $message = str_replace( - array("'", "\n"), - array("\\'", "\\A"), + ["'", "\n"], + ["\\'", "\\A"], $error->getfile() . ":\n\n" . $error->getMessage() ); From 05369ac7ff3ce06b89dca0913da560aa7dcdba6c Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 16 Dec 2015 17:29:58 -0500 Subject: [PATCH 029/329] refactor semi-colon stripping (again) --- scss.inc.php | 1 - src/Formatter.php | 14 ++++++++++ src/Formatter/Compact.php | 1 + src/Formatter/Compressed.php | 15 +++++++++- src/Formatter/Crunched.php | 15 +++++++++- src/Formatter/Debug.php | 1 + src/Formatter/Expanded.php | 1 + src/Formatter/Nested.php | 1 + src/Formatter/StripSemiColons.php | 46 ------------------------------- 9 files changed, 46 insertions(+), 49 deletions(-) delete mode 100644 src/Formatter/StripSemiColons.php diff --git a/scss.inc.php b/scss.inc.php index ddfd1297..b6892fec 100644 --- a/scss.inc.php +++ b/scss.inc.php @@ -20,7 +20,6 @@ include_once __DIR__ . '/src/Formatter/Expanded.php'; include_once __DIR__ . '/src/Formatter/Nested.php'; include_once __DIR__ . '/src/Formatter/OutputBlock.php'; - include_once __DIR__ . '/src/Formatter/StripSemiColons.php'; include_once __DIR__ . '/src/Node.php'; include_once __DIR__ . '/src/Node/Number.php'; include_once __DIR__ . '/src/Parser.php'; diff --git a/src/Formatter.php b/src/Formatter.php index caa9d660..2770bb2d 100644 --- a/src/Formatter.php +++ b/src/Formatter.php @@ -55,6 +55,11 @@ abstract class Formatter */ public $assignSeparator; + /** + * @var boolea + */ + public $keepSemicolons; + /** * Initialize formatter * @@ -96,6 +101,15 @@ public function property($name, $value) */ public function stripSemicolon(&$lines) { + if ($this->keepSemicolons) { + return; + } + + if (($count = count($lines)) + && substr($lines[$count - 1], -1) === ';' + ) { + $lines[$count - 1] = substr($lines[$count - 1], 0, -1); + } } /** diff --git a/src/Formatter/Compact.php b/src/Formatter/Compact.php index 721390d7..94abe329 100644 --- a/src/Formatter/Compact.php +++ b/src/Formatter/Compact.php @@ -32,6 +32,7 @@ public function __construct() $this->close = "}\n\n"; $this->tagSeparator = ','; $this->assignSeparator = ':'; + $this->keepSemicolons = true; } /** diff --git a/src/Formatter/Compressed.php b/src/Formatter/Compressed.php index af55da02..df7bc75f 100644 --- a/src/Formatter/Compressed.php +++ b/src/Formatter/Compressed.php @@ -21,7 +21,20 @@ */ class Compressed extends Formatter { - use StripSemiColons; + /** + * {@inheritdoc} + */ + public function __construct() + { + $this->indentLevel = 0; + $this->indentChar = ' '; + $this->break = ''; + $this->open = '{'; + $this->close = '}'; + $this->tagSeparator = ','; + $this->assignSeparator = ':'; + $this->keepSemicolons = false; + } /** * {@inheritdoc} diff --git a/src/Formatter/Crunched.php b/src/Formatter/Crunched.php index c31cac56..ccba1333 100644 --- a/src/Formatter/Crunched.php +++ b/src/Formatter/Crunched.php @@ -21,7 +21,20 @@ */ class Crunched extends Formatter { - use StripSemiColons; + /** + * {@inheritdoc} + */ + public function __construct() + { + $this->indentLevel = 0; + $this->indentChar = ' '; + $this->break = ''; + $this->open = '{'; + $this->close = '}'; + $this->tagSeparator = ','; + $this->assignSeparator = ':'; + $this->keepSemicolons = false; + } /** * {@inheritdoc} diff --git a/src/Formatter/Debug.php b/src/Formatter/Debug.php index e4555bb3..855742e7 100644 --- a/src/Formatter/Debug.php +++ b/src/Formatter/Debug.php @@ -33,6 +33,7 @@ public function __construct() $this->close = ' }'; $this->tagSeparator = ', '; $this->assignSeparator = ': '; + $this->keepSemicolons = true; } /** diff --git a/src/Formatter/Expanded.php b/src/Formatter/Expanded.php index b1a0bf24..54db742f 100644 --- a/src/Formatter/Expanded.php +++ b/src/Formatter/Expanded.php @@ -33,6 +33,7 @@ public function __construct() $this->close = '}'; $this->tagSeparator = ', '; $this->assignSeparator = ': '; + $this->keepSemicolons = true; } /** diff --git a/src/Formatter/Nested.php b/src/Formatter/Nested.php index ed9f075b..9fdb4dd0 100644 --- a/src/Formatter/Nested.php +++ b/src/Formatter/Nested.php @@ -38,6 +38,7 @@ public function __construct() $this->close = ' }'; $this->tagSeparator = ', '; $this->assignSeparator = ': '; + $this->keepSemicolons = true; } /** diff --git a/src/Formatter/StripSemiColons.php b/src/Formatter/StripSemiColons.php deleted file mode 100644 index 8e42c16e..00000000 --- a/src/Formatter/StripSemiColons.php +++ /dev/null @@ -1,46 +0,0 @@ - - */ -trait StripSemiColons -{ - /** - * {@inheritdoc} - */ - public function __construct() - { - $this->indentLevel = 0; - $this->indentChar = ' '; - $this->break = ''; - $this->open = '{'; - $this->close = '}'; - $this->tagSeparator = ','; - $this->assignSeparator = ':'; - } - - /** - * {@inheritdoc} - */ - public function stripSemicolon(&$lines) - { - if (($count = count($lines)) - && substr($lines[$count - 1], -1) === ';' - ) { - $lines[$count - 1] = substr($lines[$count - 1], 0, -1); - } - } -} From feecdbe1defcd89089e51bf89bf77e0332658517 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 16 Dec 2015 17:46:24 -0500 Subject: [PATCH 030/329] Bump version to v0.6.2 --- src/Version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Version.php b/src/Version.php index ef096e94..0d54dd51 100644 --- a/src/Version.php +++ b/src/Version.php @@ -18,5 +18,5 @@ */ class Version { - const VERSION = 'v0.6.1'; + const VERSION = 'v0.6.2'; } From aa18ff29729691ccbececb52d839c5a517505980 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Thu, 24 Dec 2015 12:33:50 -0500 Subject: [PATCH 031/329] fixes #396 extend+parent+placeholder --- src/Compiler.php | 19 +++++++++++++------ tests/inputs/extends.scss | 20 ++++++++++++++++++++ tests/outputs/extends.css | 9 +++++++++ tests/outputs_numbered/extends.css | 14 ++++++++++++++ 4 files changed, 56 insertions(+), 6 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index 64dfb8b3..8c14d36d 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -521,21 +521,28 @@ protected function matchExtendsSingle($rawSingle, &$outOrigin) */ protected function combineSelectorSingle($base, $other) { - $tag = null; + $tag = []; $out = []; + $wasTag = true; foreach ([$base, $other] as $single) { foreach ($single as $part) { - if (preg_match('/^[^\[.#:]/', $part)) { - $tag = $part; - } else { + if (preg_match('/^[\[.:#]/', $part)) { $out[] = $part; + $wasTag = false; + } elseif (preg_match('/^[^_-]/', $part)) { + $tag[] = $part; + $wasTag = true; + } elseif ($wasTag) { + $tag[count($tag) - 1] .= $part; + } else { + $out[count($out) - 1] .= $part; } } } - if ($tag) { - array_unshift($out, $tag); + if (count($tag)) { + array_unshift($out, $tag[0]); } return $out; diff --git a/tests/inputs/extends.scss b/tests/inputs/extends.scss index 9da03502..467d3624 100644 --- a/tests/inputs/extends.scss +++ b/tests/inputs/extends.scss @@ -285,3 +285,23 @@ $var: ".selector1, .selector2"; a.important { @extend .notice !optional; } + +$color-base: white; + +%pagination-bullet { + width: 6px; + height: 6px; + margin-left: 5px; + &:first-child { + margin-left: 0; + } + &.is-active { + background-color: $color-base; + } +} + +.pagination { + &-bullet { + @extend %pagination-bullet; + } +} diff --git a/tests/outputs/extends.css b/tests/outputs/extends.css index 82a65823..8e2916a3 100644 --- a/tests/outputs/extends.css +++ b/tests/outputs/extends.css @@ -129,3 +129,12 @@ body .to-extend, body .test { font-size: 14px; } .main .block__element--modifier { font-weight: bold; } + +.pagination-bullet { + width: 6px; + height: 6px; + margin-left: 5px; } + .pagination-bullet:first-child { + margin-left: 0; } + .pagination-bullet.is-active { + background-color: white; } diff --git a/tests/outputs_numbered/extends.css b/tests/outputs_numbered/extends.css index 5d76d9d3..e32f01b7 100644 --- a/tests/outputs_numbered/extends.css +++ b/tests/outputs_numbered/extends.css @@ -201,3 +201,17 @@ body .to-extend, body .test { .main .block__element--modifier { font-weight: bold; } /* line 285, inputs/extends.scss */ +/* line 291, inputs/extends.scss */ + +.pagination-bullet { + width: 6px; + height: 6px; + margin-left: 5px; } +/* line 295, inputs/extends.scss */ +.pagination-bullet:first-child { + margin-left: 0; } +/* line 298, inputs/extends.scss */ +.pagination-bullet.is-active { + background-color: white; } +/* line 303, inputs/extends.scss */ +/* line 304, inputs/extends.scss */ From 3eef90cd8ecff0790713090d1cfd17e1cced589f Mon Sep 17 00:00:00 2001 From: josh Date: Sun, 27 Dec 2015 12:50:20 -0700 Subject: [PATCH 032/329] improve performance: use substr() instead of preg_match() for literals --- src/Parser.php | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/Parser.php b/src/Parser.php index 95e26049..3b44cfcd 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -64,6 +64,8 @@ class Parser private $buffer; private $utf8; private $encoding; + private $pattern_modifiers = 'Ais'; + /** * Constructor @@ -81,6 +83,10 @@ public function __construct($sourceName, $sourceIndex = 0, $encoding = 'utf-8') $this->charset = null; $this->utf8 = ! $encoding || strtolower($encoding) === 'utf-8'; + if ($this->utf8) { + $this->pattern_modifiers = 'Aisu'; + } + if (empty(self::$operatorPattern)) { self::$operatorPattern = '([*\/%+-]|[!=]\=|\>\=?|\<\=\>|\<\=?|and|or)'; @@ -782,7 +788,7 @@ protected function peek($regex, &$out, $from = null) $from = $this->count; } - $r = $this->utf8 ? '/' . $regex . '/Aisu' : '/' . $regex . '/Ais'; + $r = '/' . $regex . '/'.$this->pattern_modifiers; $result = preg_match($r, $this->buffer, $out, null, $from); return $result; @@ -862,7 +868,7 @@ protected function match($regex, &$out, $eatWhitespace = null) $eatWhitespace = $this->eatWhiteDefault; } - $r = $this->utf8 ? '/' . $regex . '/Aisu' : '/' . $regex . '/Ais'; + $r = '/' . $regex . '/'.$this->pattern_modifiers; if (preg_match($r, $this->buffer, $out, null, $this->count)) { $this->count += strlen($out[0]); @@ -891,24 +897,20 @@ protected function literal($what, $eatWhitespace = null) $eatWhitespace = $this->eatWhiteDefault; } - // shortcut on single letter - if (! isset($what[1]) && isset($this->buffer[$this->count])) { - if ($this->buffer[$this->count] === $what) { - if (! $eatWhitespace) { - $this->count++; - - return true; - } - // goes below... - } else { - return false; + $len = strlen($what); + if( substr($this->buffer,$this->count,$len) === $what ){ + $this->count += $len; + if ($eatWhitespace) { + $this->whitespace(); } + return true; } - return $this->match($this->pregQuote($what), $m, $eatWhitespace); + return false; } + /** * Match some whitespace * From c45de613d9b31ccf02559fc5e2accb6b565feeed Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Tue, 29 Dec 2015 23:09:50 -0500 Subject: [PATCH 033/329] Fix PSR2 and naming convention violations --- src/Parser.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Parser.php b/src/Parser.php index 3b44cfcd..daa61b96 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -64,7 +64,7 @@ class Parser private $buffer; private $utf8; private $encoding; - private $pattern_modifiers = 'Ais'; + private $patternModifiers = 'Ais'; /** @@ -84,7 +84,7 @@ public function __construct($sourceName, $sourceIndex = 0, $encoding = 'utf-8') $this->utf8 = ! $encoding || strtolower($encoding) === 'utf-8'; if ($this->utf8) { - $this->pattern_modifiers = 'Aisu'; + $this->patternModifiers = 'Aisu'; } if (empty(self::$operatorPattern)) { @@ -788,7 +788,7 @@ protected function peek($regex, &$out, $from = null) $from = $this->count; } - $r = '/' . $regex . '/'.$this->pattern_modifiers; + $r = '/' . $regex . '/'.$this->patternModifiers; $result = preg_match($r, $this->buffer, $out, null, $from); return $result; @@ -868,7 +868,7 @@ protected function match($regex, &$out, $eatWhitespace = null) $eatWhitespace = $this->eatWhiteDefault; } - $r = '/' . $regex . '/'.$this->pattern_modifiers; + $r = '/' . $regex . '/'.$this->patternModifiers; if (preg_match($r, $this->buffer, $out, null, $this->count)) { $this->count += strlen($out[0]); @@ -897,20 +897,21 @@ protected function literal($what, $eatWhitespace = null) $eatWhitespace = $this->eatWhiteDefault; } - $len = strlen($what); - if( substr($this->buffer,$this->count,$len) === $what ){ + + if (substr($this->buffer, $this->count, $len) === $what) { $this->count += $len; + if ($eatWhitespace) { $this->whitespace(); } + return true; } return false; } - /** * Match some whitespace * From b949c6e4effef797267744e0f421a7c6918240c2 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Tue, 29 Dec 2015 23:41:47 -0500 Subject: [PATCH 034/329] coding style --- src/Parser.php | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/Parser.php b/src/Parser.php index daa61b96..7874a97c 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -64,8 +64,7 @@ class Parser private $buffer; private $utf8; private $encoding; - private $patternModifiers = 'Ais'; - + private $patternModifiers; /** * Constructor @@ -78,14 +77,11 @@ class Parser */ public function __construct($sourceName, $sourceIndex = 0, $encoding = 'utf-8') { - $this->sourceName = $sourceName ?: '(stdin)'; - $this->sourceIndex = $sourceIndex; - $this->charset = null; - $this->utf8 = ! $encoding || strtolower($encoding) === 'utf-8'; - - if ($this->utf8) { - $this->patternModifiers = 'Aisu'; - } + $this->sourceName = $sourceName ?: '(stdin)'; + $this->sourceIndex = $sourceIndex; + $this->charset = null; + $this->utf8 = ! $encoding || strtolower($encoding) === 'utf-8'; + $this->patternModifiers = $this->utf8 ? 'Aisu' : 'Ais'; if (empty(self::$operatorPattern)) { self::$operatorPattern = '([*\/%+-]|[!=]\=|\>\=?|\<\=\>|\<\=?|and|or)'; @@ -788,7 +784,7 @@ protected function peek($regex, &$out, $from = null) $from = $this->count; } - $r = '/' . $regex . '/'.$this->patternModifiers; + $r = '/' . $regex . '/' . $this->patternModifiers; $result = preg_match($r, $this->buffer, $out, null, $from); return $result; @@ -868,7 +864,7 @@ protected function match($regex, &$out, $eatWhitespace = null) $eatWhitespace = $this->eatWhiteDefault; } - $r = '/' . $regex . '/'.$this->patternModifiers; + $r = '/' . $regex . '/' . $this->patternModifiers; if (preg_match($r, $this->buffer, $out, null, $this->count)) { $this->count += strlen($out[0]); From 42e863ec7d18a7894da472358dc70e0fda7f04de Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Thu, 31 Dec 2015 23:30:53 -0500 Subject: [PATCH 035/329] add unit test from #399 --- tests/inputs/content.scss | 19 +++++++++++++++++++ tests/outputs/content.css | 3 +++ tests/outputs_numbered/content.css | 3 +++ 3 files changed, 25 insertions(+) diff --git a/tests/inputs/content.scss b/tests/inputs/content.scss index 7fef7800..bae453b3 100644 --- a/tests/inputs/content.scss +++ b/tests/inputs/content.scss @@ -97,3 +97,22 @@ A { } } } + +@mixin two() { + @content; +} +@mixin three() { + @content; +} +@mixin one() { + @include two() { + @include three() { + @content; + } + } +} +.test { + @include one() { + display: none; + } +} diff --git a/tests/outputs/content.css b/tests/outputs/content.css index 93ed1372..6a8ba90b 100644 --- a/tests/outputs/content.css +++ b/tests/outputs/content.css @@ -33,3 +33,6 @@ A { top: 10px; } + +.test { + display: none; } diff --git a/tests/outputs_numbered/content.css b/tests/outputs_numbered/content.css index ace5a98a..a0bf6e1e 100644 --- a/tests/outputs_numbered/content.css +++ b/tests/outputs_numbered/content.css @@ -42,3 +42,6 @@ /* line 91, inputs/content.scss */ A { top: 10px; } +/* line 114, inputs/content.scss */ +.test { + display: none; } From 1176de902cfafee5779d6d1291be92e83392bb50 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Fri, 1 Jan 2016 00:07:40 -0500 Subject: [PATCH 036/329] fixes #399 - nested @content infinite loop --- src/Compiler.php | 5 +++-- tests/inputs/content.scss | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index 8c14d36d..d6afc99a 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -1698,7 +1698,7 @@ protected function compileChild($child, OutputBlock $out) if (isset($content)) { $content->scope = $callingScope; - $this->setRaw(self::$namespaces['special'] . 'content', $content, $this->getStoreEnv()); + $this->setRaw(self::$namespaces['special'] . 'content', $content, $this->env); } if (isset($mixin->args)) { @@ -1713,7 +1713,8 @@ protected function compileChild($child, OutputBlock $out) break; case Type::T_MIXIN_CONTENT: - $content = $this->get(self::$namespaces['special'] . 'content', false, $this->getStoreEnv()); + $content = $this->get(self::$namespaces['special'] . 'content', false, $this->getStoreEnv()) + ?: $this->get(self::$namespaces['special'] . 'content', false, $this->env); if (! $content) { $this->throwError('Expected @content inside of mixin'); diff --git a/tests/inputs/content.scss b/tests/inputs/content.scss index bae453b3..a9c00c46 100644 --- a/tests/inputs/content.scss +++ b/tests/inputs/content.scss @@ -60,7 +60,7 @@ $color: white; } } -@mixin nested { +@mixin nested($args) { * body { @content; } From 6de8e373951a0094eabef2ab379a516d3ac7e131 Mon Sep 17 00:00:00 2001 From: Jonathan Rehm Date: Thu, 14 Jan 2016 17:07:32 -0700 Subject: [PATCH 037/329] Only divide by 100 if number is truly a percent Includes test --- src/Compiler.php | 2 +- tests/inputs/builtins.scss | 1 + tests/outputs/builtins.css | 1 + tests/outputs_numbered/builtins.css | 17 +++++++++-------- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index d6afc99a..ded0b7a0 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -3752,7 +3752,7 @@ protected function coerceString($value) protected function coercePercent($value) { if ($value[0] === Type::T_NUMBER) { - if (isset($value[2]['%'])) { + if (!empty($value[2]['%'])) { return $value[1] / 100; } diff --git a/tests/inputs/builtins.scss b/tests/inputs/builtins.scss index 70ec3012..a80db5b1 100644 --- a/tests/inputs/builtins.scss +++ b/tests/inputs/builtins.scss @@ -104,6 +104,7 @@ #number { color: percentage(100/40); + $test: 50%; $test: 0 + ($test / 100%); color: percentage($test); color: round(3.4); color: floor(3.4); color: ceil(3.4); diff --git a/tests/outputs/builtins.css b/tests/outputs/builtins.css index fa74c1e2..50e2a82e 100644 --- a/tests/outputs/builtins.css +++ b/tests/outputs/builtins.css @@ -76,6 +76,7 @@ #number { color: 250%; + color: 50%; color: 3; color: 3; color: 4; diff --git a/tests/outputs_numbered/builtins.css b/tests/outputs_numbered/builtins.css index b0170c8d..722c6af4 100644 --- a/tests/outputs_numbered/builtins.css +++ b/tests/outputs_numbered/builtins.css @@ -77,6 +77,7 @@ /* line 105, inputs/builtins.scss */ #number { color: 250%; + color: 50%; color: 3; color: 3; color: 4; @@ -85,7 +86,7 @@ width: 200%; bottom: 10px; padding: 3em 1in 96px 72pt; } -/* line 118, inputs/builtins.scss */ +/* line 119, inputs/builtins.scss */ #list { len: 3; len: 1; @@ -107,7 +108,7 @@ cool: great job one two three; zip: 1px solid, 2px dashed; zip: 1px solid red, 2px dashed green; } -/* line 154, inputs/builtins.scss */ +/* line 155, inputs/builtins.scss */ #introspection { t: number; t: string; @@ -127,35 +128,35 @@ c: true; c: false; c: true; } -/* line 178, inputs/builtins.scss */ +/* line 179, inputs/builtins.scss */ #if { color: yes; color: no; color: yes; color: yes; } -/* line 185, inputs/builtins.scss */ +/* line 186, inputs/builtins.scss */ .transparent { r: 0; g: 0; b: 0; a: 0; } -/* line 192, inputs/builtins.scss */ +/* line 193, inputs/builtins.scss */ .alpha { a: 1; a: 1; a: 1; a: 0.5; a: alpha(currentColor); } -/* line 201, inputs/builtins.scss */ +/* line 202, inputs/builtins.scss */ #exists { a: true; b: true; c: false; } -/* line 208, inputs/builtins.scss */ +/* line 209, inputs/builtins.scss */ div.call-tests { a: #0a64ff; b: #0058ef; c: b; } -/* line 215, inputs/builtins.scss */ +/* line 216, inputs/builtins.scss */ div.unquote-test { a: [type='text']; } From 11d2c785748fe2cb19fe9f9b14eb7f9bd53e70bf Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Thu, 14 Jan 2016 21:44:47 -0500 Subject: [PATCH 038/329] spacing --- src/Compiler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compiler.php b/src/Compiler.php index ded0b7a0..b19b9e56 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -3752,7 +3752,7 @@ protected function coerceString($value) protected function coercePercent($value) { if ($value[0] === Type::T_NUMBER) { - if (!empty($value[2]['%'])) { + if (! empty($value[2]['%'])) { return $value[1] / 100; } From a27edad3d16635a222d7204706572e24c338aa17 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Thu, 14 Jan 2016 21:50:06 -0500 Subject: [PATCH 039/329] bump version to 0.6.3 --- src/Version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Version.php b/src/Version.php index 0d54dd51..8dfa0e93 100644 --- a/src/Version.php +++ b/src/Version.php @@ -18,5 +18,5 @@ */ class Version { - const VERSION = 'v0.6.2'; + const VERSION = 'v0.6.3'; } From aef75351d3496ccd478ef169440da43a0005ea34 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Sat, 23 Jan 2016 08:05:40 -0500 Subject: [PATCH 040/329] Update travis CI config --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 80b481f1..e5b70fb7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ php: - 5.4 - 5.5 - 5.6 + - 7.0 - nightly script: From 0ac284821993e4eac001f5b3d32203a826ae7251 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Mon, 8 Feb 2016 10:34:46 -0500 Subject: [PATCH 041/329] fixes #411; regression from #397 --- src/Parser.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Parser.php b/src/Parser.php index 7874a97c..42d8f0dc 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -895,7 +895,7 @@ protected function literal($what, $eatWhitespace = null) $len = strlen($what); - if (substr($this->buffer, $this->count, $len) === $what) { + if (strcasecmp(substr($this->buffer, $this->count, $len), $what) === 0) { $this->count += $len; if ($eatWhitespace) { From b1905524a27fa62c8fec709c14008ef75048cae7 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Thu, 11 Feb 2016 00:40:00 -0500 Subject: [PATCH 042/329] fixes #412 - parsing multiple assignment flags --- src/Compiler.php | 6 +++--- src/Parser.php | 23 +++++++++++++---------- tests/inputs/variables.scss | 7 +++++++ tests/outputs/variables.css | 3 +++ tests/outputs_numbered/variables.css | 3 +++ 5 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index b19b9e56..8fbbc1a2 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -1460,9 +1460,9 @@ protected function compileChild($child, OutputBlock $out) list(, $name, $value) = $child; if ($name[0] === Type::T_VARIABLE) { - $flag = isset($child[3]) ? $child[3] : null; - $isDefault = $flag === '!default'; - $isGlobal = $flag === '!global'; + $flags = isset($child[3]) ? $child[3] : []; + $isDefault = in_array('!default', $flags); + $isGlobal = in_array('!global', $flags); if ($isGlobal) { $this->set($name[1], $this->reduce($value), false, $this->rootEnv); diff --git a/src/Parser.php b/src/Parser.php index 42d8f0dc..39b306eb 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -617,8 +617,8 @@ protected function parseChunk() $this->end() ) { // check for '!flag' - $assignmentFlag = $this->stripAssignmentFlag($value); - $this->append([Type::T_ASSIGN, $name, $value, $assignmentFlag], $s); + $assignmentFlags = $this->stripAssignmentFlags($value); + $this->append([Type::T_ASSIGN, $name, $value, $assignmentFlags], $s); return true; } @@ -2287,25 +2287,28 @@ protected function end() * * @param array $value * - * @return string + * @return array */ - protected function stripAssignmentFlag(&$value) + protected function stripAssignmentFlags(&$value) { - $token = &$value; + $flags = []; for ($token = &$value; $token[0] === Type::T_LIST && ($s = count($token[2])); $token = &$lastNode) { - $lastNode = &$token[2][$s - 1]; - - if ($lastNode[0] === Type::T_KEYWORD && in_array($lastNode[1], ['!default', '!global'])) { + for ($lastNode = &$token[2][$s - 1]; + $lastNode[0] === Type::T_KEYWORD && in_array($lastNode[1], ['!default', '!global']); + $lastNode = $node + ) { array_pop($token[2]); + $node = end($token[2]); + $token = $this->flattenList($token); - return $lastNode[1]; + $flags[] = $lastNode[1]; } } - return false; + return $flags; } /** diff --git a/tests/inputs/variables.scss b/tests/inputs/variables.scss index 5212c385..d6461a86 100644 --- a/tests/inputs/variables.scss +++ b/tests/inputs/variables.scss @@ -80,3 +80,10 @@ body { color: $цвет; } + +$test: 12 !default !global; + +* { + // Expected: 12 + data: $test; +} diff --git a/tests/outputs/variables.css b/tests/outputs/variables.css index ed3e6b21..7112efae 100644 --- a/tests/outputs/variables.css +++ b/tests/outputs/variables.css @@ -34,3 +34,6 @@ A { body { color: #000; } + +* { + data: 12; } diff --git a/tests/outputs_numbered/variables.css b/tests/outputs_numbered/variables.css index 206fa249..77153c44 100644 --- a/tests/outputs_numbered/variables.css +++ b/tests/outputs_numbered/variables.css @@ -37,3 +37,6 @@ A { /* line 79, inputs/variables.scss */ body { color: #000; } +/* line 86, inputs/variables.scss */ +* { + data: 12; } From b670910167016567c1891b7b59e94be249c58cbd Mon Sep 17 00:00:00 2001 From: Raul Date: Mon, 22 Feb 2016 20:53:24 +0100 Subject: [PATCH 043/329] Fix Issue #416 --- src/Compiler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compiler.php b/src/Compiler.php index 8fbbc1a2..e60ae331 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -1742,7 +1742,7 @@ protected function compileChild($child, OutputBlock $out) $line = $this->sourceLine; $value = $this->compileValue($this->reduce($value, true)); - echo "Line $line WARN: $value\n"; + fwrite($this->stderr, "Line $line WARN: $value\n"); break; case Type::T_ERROR: From fbe587471b5bfe1e57cde7fb42df8c3ce20626da Mon Sep 17 00:00:00 2001 From: Moises Date: Tue, 23 Feb 2016 20:46:43 +0100 Subject: [PATCH 044/329] Fix: ( null or/and 'foo' ) --- src/Compiler.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index 8fbbc1a2..49beeccc 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -2216,7 +2216,7 @@ protected function opAnd($left, $right, $shouldEval) return; } - if ($left !== self::$false) { + if ($left !== self::$false and $left !== self::$null) { return $this->reduce($right, true); } @@ -2238,7 +2238,7 @@ protected function opOr($left, $right, $shouldEval) return; } - if ($left !== self::$false) { + if ($left !== self::$false and $left !== self::$null) { return $left; } From 9d763a8474ee2a8b0935db959a0e7bec269b3919 Mon Sep 17 00:00:00 2001 From: Moises Date: Tue, 23 Feb 2016 21:26:42 +0100 Subject: [PATCH 045/329] add unit test PR #418 --- tests/inputs/operators.scss | 2 + tests/outputs/operators.css | 3 +- tests/outputs_numbered/operators.css | 55 ++++++++++++++-------------- 3 files changed, 32 insertions(+), 28 deletions(-) diff --git a/tests/inputs/operators.scss b/tests/inputs/operators.scss index 79662604..31e65b17 100644 --- a/tests/inputs/operators.scss +++ b/tests/inputs/operators.scss @@ -99,10 +99,12 @@ div { and: (false and two); and: (one and two); and: (one and false); + and: (null and two); or: (false or two); or: (one or two); or: (one or false); + or: (null or two); } diff --git a/tests/outputs/operators.css b/tests/outputs/operators.css index 3582c871..fb492c82 100644 --- a/tests/outputs/operators.css +++ b/tests/outputs/operators.css @@ -77,7 +77,8 @@ div { and: false; or: two; or: one; - or: one; } + or: one; + or: two; } #nots-fail { not: false2; diff --git a/tests/outputs_numbered/operators.css b/tests/outputs_numbered/operators.css index acf984e3..c3ea3d1d 100644 --- a/tests/outputs_numbered/operators.css +++ b/tests/outputs_numbered/operators.css @@ -78,8 +78,9 @@ div { and: false; or: two; or: one; - or: one; } -/* line 109, inputs/operators.scss */ + or: one; + or: two; } +/* line 111, inputs/operators.scss */ #nots-fail { not: false2; not: not false; @@ -87,7 +88,7 @@ div { not: not 1; not: not ""; not: not hello; } -/* line 118, inputs/operators.scss */ +/* line 120, inputs/operators.scss */ #nots { not: false2; not: true; @@ -96,7 +97,7 @@ div { not: false; not: false; not: true; } -/* line 128, inputs/operators.scss */ +/* line 130, inputs/operators.scss */ #string-test { str: true; str: false; @@ -104,72 +105,72 @@ div { str: true; str: xhellohellofalse; str: true; } -/* line 144, inputs/operators.scss */ +/* line 146, inputs/operators.scss */ #special { cancel-unit: 1; } -/* line 151, inputs/operators.scss */ +/* line 153, inputs/operators.scss */ .row .a { margin: -0.5em; } -/* line 152, inputs/operators.scss */ +/* line 154, inputs/operators.scss */ .row .b { margin: -0.5em; } -/* line 153, inputs/operators.scss */ +/* line 155, inputs/operators.scss */ .row .c { margin: -0.5em; } -/* line 154, inputs/operators.scss */ +/* line 156, inputs/operators.scss */ .row .d { margin: -0.5em; } -/* line 155, inputs/operators.scss */ +/* line 157, inputs/operators.scss */ .row .e { margin: 0 -0.5em; } -/* line 157, inputs/operators.scss */ +/* line 159, inputs/operators.scss */ .alt .a { margin: -0.5em; } -/* line 158, inputs/operators.scss */ +/* line 160, inputs/operators.scss */ .alt .b { margin: -0.5em; } -/* line 159, inputs/operators.scss */ +/* line 161, inputs/operators.scss */ .alt .c { margin: -0.5em; } -/* line 160, inputs/operators.scss */ +/* line 162, inputs/operators.scss */ .alt .d { margin: 0 -0.5em; } -/* line 161, inputs/operators.scss */ +/* line 163, inputs/operators.scss */ .alt .e { margin: 0 -0.5em; } -/* line 163, inputs/operators.scss */ +/* line 165, inputs/operators.scss */ .row .f { margin: -2em; } -/* line 164, inputs/operators.scss */ +/* line 166, inputs/operators.scss */ .row .g { margin: -2em; } -/* line 165, inputs/operators.scss */ +/* line 167, inputs/operators.scss */ .row .h { margin: -2em; } -/* line 166, inputs/operators.scss */ +/* line 168, inputs/operators.scss */ .row .i { margin: -2em; } -/* line 167, inputs/operators.scss */ +/* line 169, inputs/operators.scss */ .row .j { margin: 0 -2em; } -/* line 169, inputs/operators.scss */ +/* line 171, inputs/operators.scss */ .alt .f { margin: -2em; } -/* line 170, inputs/operators.scss */ +/* line 172, inputs/operators.scss */ .alt .g { margin: -2em; } -/* line 171, inputs/operators.scss */ +/* line 173, inputs/operators.scss */ .alt .h { margin: -2em; } -/* line 172, inputs/operators.scss */ +/* line 174, inputs/operators.scss */ .alt .i { margin: 0 -2em; } -/* line 173, inputs/operators.scss */ +/* line 175, inputs/operators.scss */ .alt .j { margin: 0 -2em; } -/* line 182, inputs/operators.scss */ +/* line 184, inputs/operators.scss */ div { *margin-left: 2.07447%; } -/* line 188, inputs/operators.scss */ +/* line 190, inputs/operators.scss */ .foo { width: 12.5%; } From 9f4655e6c6324a6cff7b51c0dc2589b125bd10d5 Mon Sep 17 00:00:00 2001 From: jo Date: Wed, 20 Jan 2016 14:13:39 +0100 Subject: [PATCH 046/329] Compiler: change scope to faciliate subclassing --- src/Compiler.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index 0120872a..19623e6a 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -125,20 +125,21 @@ class Compiler protected $rootEnv; protected $rootBlock; + protected $env; + protected $scope; + protected $storeEnv; + protected $charsetSeen; + protected $sourceNames; + private $indentLevel; private $commentsSeen; private $extends; private $extendsMap; private $parsedFiles; - private $env; - private $scope; private $parser; - private $sourceNames; private $sourceIndex; private $sourceLine; private $sourceColumn; - private $storeEnv; - private $charsetSeen; private $stderr; private $shouldEvaluate; private $ignoreErrors; @@ -207,7 +208,7 @@ public function compile($code, $path = null) * * @return \Leafo\ScssPhp\Parser */ - private function parserFactory($path) + protected function parserFactory($path) { $parser = new Parser($path, count($this->sourceNames), $this->encoding); @@ -2944,7 +2945,6 @@ public function get($name, $shouldThrow = true, Environment $env = null) } $hasNamespace = $name[0] === '^' || $name[0] === '@' || $name[0] === '%'; - for (;;) { if (array_key_exists($name, $env->store)) { return $env->store[$name]; @@ -3303,7 +3303,7 @@ public function throwError($msg) * * @throws \Exception */ - private function handleImportLoop($name) + protected function handleImportLoop($name) { for ($env = $this->env; $env; $env = $env->parent) { $file = $this->sourceNames[$env->block->sourceIndex]; From c4ad181885e5f85a9f71002983597d9da2c11a8c Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 24 Feb 2016 10:41:07 -0500 Subject: [PATCH 047/329] phpcs --- src/Parser.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Parser.php b/src/Parser.php index 39b306eb..3cdd2c7e 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -2294,10 +2294,9 @@ protected function stripAssignmentFlags(&$value) $flags = []; for ($token = &$value; $token[0] === Type::T_LIST && ($s = count($token[2])); $token = &$lastNode) { - for ($lastNode = &$token[2][$s - 1]; - $lastNode[0] === Type::T_KEYWORD && in_array($lastNode[1], ['!default', '!global']); - $lastNode = $node - ) { + $lastNode = &$token[2][$s - 1]; + + while ($lastNode[0] === Type::T_KEYWORD && in_array($lastNode[1], ['!default', '!global'])) { array_pop($token[2]); $node = end($token[2]); @@ -2305,6 +2304,8 @@ protected function stripAssignmentFlags(&$value) $token = $this->flattenList($token); $flags[] = $lastNode[1]; + + $lastNode = $node; } } From f73a054101715a2cd288658291c7425c39fdcfc8 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 15 Jun 2016 18:20:16 -0400 Subject: [PATCH 048/329] Bump version to v0.6.4 --- src/Version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Version.php b/src/Version.php index 8dfa0e93..45db5de9 100644 --- a/src/Version.php +++ b/src/Version.php @@ -18,5 +18,5 @@ */ class Version { - const VERSION = 'v0.6.3'; + const VERSION = 'v0.6.4'; } From 1d700dcf86c92144857ccd390cabd51feef4e087 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 15 Jun 2016 18:32:10 -0400 Subject: [PATCH 049/329] fixes #426 keep the un-normalized name for error reporting --- src/Compiler.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index 19623e6a..87ffd68f 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -2938,16 +2938,16 @@ protected function setRaw($name, $value, Environment $env) */ public function get($name, $shouldThrow = true, Environment $env = null) { - $name = $this->normalizeName($name); + $normalizedName = $this->normalizeName($name); if (! isset($env)) { $env = $this->getStoreEnv(); } - $hasNamespace = $name[0] === '^' || $name[0] === '@' || $name[0] === '%'; + $hasNamespace = $normalizedName[0] === '^' || $normalizedName[0] === '@' || $normalizedName[0] === '%'; for (;;) { - if (array_key_exists($name, $env->store)) { - return $env->store[$name]; + if (array_key_exists($normalizedName, $env->store)) { + return $env->store[$normalizedName]; } if (! $hasNamespace && isset($env->marker)) { From b42b2e23128b06f482f8947533f7dfa0c49a3123 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Thu, 16 Jun 2016 11:33:35 -0400 Subject: [PATCH 050/329] Compiler: coerceValue support for #rgb values --- src/Compiler.php | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/Compiler.php b/src/Compiler.php index 87ffd68f..6e5e45dc 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -3622,6 +3622,29 @@ private function coerceValue($value) return self::$emptyString; } + if (preg_match('/^(#([0-9a-f]{6})|#([0-9a-f]{3}))$/i', $value, $m)) { + $color = [Type::T_COLOR]; + + if (isset($m[3])) { + $num = hexdec($m[3]); + + foreach ([3, 2, 1] as $i) { + $t = $num & 0xf; + $color[$i] = $t << 4 | $t; + $num >>= 4; + } + } else { + $num = hexdec($m[2]); + + foreach ([3, 2, 1] as $i) { + $color[$i] = $num & 0xff; + $num >>= 8; + } + } + + return $color; + } + return [Type::T_KEYWORD, $value]; } From 1270b5c5437559b07f9237aa11ee035c9a07d997 Mon Sep 17 00:00:00 2001 From: Matias Griese Date: Thu, 16 Jun 2016 21:28:23 +0300 Subject: [PATCH 051/329] Fix mixin and variable scopes (#440) --- src/Compiler.php | 10 ++++++++ tests/inputs/functions.scss | 38 ++++++++++++++++++++++++++++ tests/inputs/mixins.scss | 18 +++++++++++++ tests/outputs/functions.css | 4 +++ tests/outputs/mixins.css | 7 +++++ tests/outputs_numbered/functions.css | 4 +++ tests/outputs_numbered/mixins.css | 8 ++++++ 7 files changed, 89 insertions(+) diff --git a/src/Compiler.php b/src/Compiler.php index 6e5e45dc..96e71692 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -1696,6 +1696,9 @@ protected function compileChild($child, OutputBlock $out) $this->pushEnv(); $this->env->depth--; + $storeEnv = $this->storeEnv; + $this->storeEnv = $this->env; + if (isset($content)) { $content->scope = $callingScope; @@ -1710,6 +1713,8 @@ protected function compileChild($child, OutputBlock $out) $this->compileChildrenNoReturn($mixin->children, $out); + $this->storeEnv = $storeEnv; + $this->popEnv(); break; @@ -3346,6 +3351,9 @@ protected function callScssFunction($name, $argValues, &$returnValue) $this->pushEnv(); + $storeEnv = $this->storeEnv; + $this->storeEnv = $this->env; + // set the args if (isset($func->args)) { $this->applyArguments($func->args, $argValues); @@ -3360,6 +3368,8 @@ protected function callScssFunction($name, $argValues, &$returnValue) $ret = $this->compileChildren($func->children, $tmp); + $this->storeEnv = $storeEnv; + $this->popEnv(); $returnValue = ! isset($ret) ? self::$defaultValue : $ret; diff --git a/tests/inputs/functions.scss b/tests/inputs/functions.scss index bcceaffd..bf3edf1f 100644 --- a/tests/inputs/functions.scss +++ b/tests/inputs/functions.scss @@ -128,3 +128,41 @@ $str: 'global'; l4: inspect((a: 1, b: 2)); l5: inspect($value: (a: 1, b: 2)); } + +@function contains($list, $values...) { + @each $value in $values { + @if type-of(index($list, $value)) != "number" { + @return false; + } + } + + @return true; +} + +@function mapping($items) { + $src: (); + $map: ( + one: 1px 1px, + two: 2px 2px, + ); + + @each $key, $values in $map { + @if contains($items, $key) { + $value1: nth($values, 1); + $value2: nth($values, 2); + + $src: append($src, $value1 $value2, space); + } + } + + @return $src; +} + +@mixin test() { + padding: mapping(one two); +} + +div { + margin: mapping(one two); + @include test(); +} \ No newline at end of file diff --git a/tests/inputs/mixins.scss b/tests/inputs/mixins.scss index 63f9007b..02ed81d0 100644 --- a/tests/inputs/mixins.scss +++ b/tests/inputs/mixins.scss @@ -190,3 +190,21 @@ div.parameter-name-scope { .test{ @include test-mixin(); } + +@mixin inner($value) {} + +@mixin outer($value) { + #{$value} { + content: "#{$value}"; + @content; + content: "#{$value}"; + } +} + +@include outer(div) { + @include inner('break'); + @include outer(p) { + @include inner('break'); + } +} + diff --git a/tests/outputs/functions.css b/tests/outputs/functions.css index 252e3909..aa0bebbb 100644 --- a/tests/outputs/functions.css +++ b/tests/outputs/functions.css @@ -45,3 +45,7 @@ p { l3: 5, 6; l4: (a: 1, b: 2); l5: (a: 1, b: 2); } + +div { + margin: 1px 1px 2px 2px; + padding: 1px 1px 2px 2px; } diff --git a/tests/outputs/mixins.css b/tests/outputs/mixins.css index e2004a07..ee692574 100644 --- a/tests/outputs/mixins.css +++ b/tests/outputs/mixins.css @@ -95,3 +95,10 @@ div.parameter-name-scope { @media screen and (min-width:0\0) { .test { color: #000; } } + +div { + content: "div"; + content: "div"; } + div p { + content: "p"; + content: "p"; } diff --git a/tests/outputs_numbered/functions.css b/tests/outputs_numbered/functions.css index 9b525e8d..6583ff05 100644 --- a/tests/outputs_numbered/functions.css +++ b/tests/outputs_numbered/functions.css @@ -47,3 +47,7 @@ p { l3: 5, 6; l4: (a: 1, b: 2); l5: (a: 1, b: 2); } +/* line 165, inputs/functions.scss */ +div { + margin: 1px 1px 2px 2px; + padding: 1px 1px 2px 2px; } diff --git a/tests/outputs_numbered/mixins.css b/tests/outputs_numbered/mixins.css index 2df05142..ed1f4ffb 100644 --- a/tests/outputs_numbered/mixins.css +++ b/tests/outputs_numbered/mixins.css @@ -108,3 +108,11 @@ div.parameter-name-scope { @media screen and (min-width:0\0) { .test { color: #000; } } +/* line 197, inputs/mixins.scss */ +div { + content: "div"; + content: "div"; } +/* line 197, inputs/mixins.scss */ +div p { + content: "p"; + content: "p"; } From 24388fafc2e9e9d997da7ca753336b15022b4148 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Mon, 20 Jun 2016 11:18:53 -0400 Subject: [PATCH 052/329] fixes #444 - strip optional BOM (byte order marker) --- src/Parser.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Parser.php b/src/Parser.php index 3cdd2c7e..ed0621ea 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -142,11 +142,16 @@ public function throwParseError($msg = 'parse error') */ public function parse($buffer) { + // strip BOM (byte order marker) + if (substr($buffer, 0, 3) === "\xef\xbb\xbf") { + $buffer = substr($buffer, 3); + } + + $this->buffer = rtrim($buffer, "\x00..\x1f"); $this->count = 0; $this->env = null; $this->inParens = false; $this->eatWhiteDefault = true; - $this->buffer = rtrim($buffer, "\x00..\x1f"); $this->saveEncoding(); $this->extractLineNumbers($buffer); From 588ebe29c5dd5c0308584fc5b758798c63f10fba Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Mon, 20 Jun 2016 11:24:44 -0400 Subject: [PATCH 053/329] #444 - add related unit test --- tests/ApiTest.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/ApiTest.php b/tests/ApiTest.php index ca5f3a28..8d89b588 100644 --- a/tests/ApiTest.php +++ b/tests/ApiTest.php @@ -105,6 +105,15 @@ public function provideSetVariables() ); } + public function testCompileByteOrderMarker() + { + // test that BOM is stripped/ignored + $this->assertEquals( + '@import "main";', + $this->compile("\xEF\xBB\xBF@import \"main\";") + ); + } + public function compile($str) { return trim($this->scss->compile($str)); From 0649d38dfef6808be1a89040a3312e8bda0b3aed Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Mon, 20 Jun 2016 11:25:08 -0400 Subject: [PATCH 054/329] Bump version to v0.6.5 --- src/Version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Version.php b/src/Version.php index 45db5de9..3be9cc31 100644 --- a/src/Version.php +++ b/src/Version.php @@ -18,5 +18,5 @@ */ class Version { - const VERSION = 'v0.6.4'; + const VERSION = 'v0.6.5'; } From e9400176899e3e10c7f3da06e79599d82ca22ae4 Mon Sep 17 00:00:00 2001 From: Alexssssss Date: Thu, 23 Jun 2016 16:50:55 +0200 Subject: [PATCH 055/329] Preg_match error array > string When a null value is given to coerceValue the following error is returned: ''' _WARNING [2]: preg_match() expects parameter 2 to be string, array given /vendor/leafo/scssphp/src/Compiler.php, line: 3635 ''' This change fixes that for me. --- src/Compiler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compiler.php b/src/Compiler.php index 96e71692..7e93fcb0 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -3621,7 +3621,7 @@ private function coerceValue($value) } if ($value === null) { - $value = self::$null; + return self::$null; } if (is_numeric($value)) { From 1149b762d93204e0d4a3a42866acd6b3ce2edc67 Mon Sep 17 00:00:00 2001 From: Frederic Massart Date: Tue, 12 Jul 2016 20:44:47 +0800 Subject: [PATCH 056/329] Resolve function arguments using mixin content scope --- src/Compiler.php | 8 +++++++ tests/inputs/nested_mixins.scss | 28 ++++++++++++++++++++++++ tests/outputs/nested_mixins.css | 9 ++++++++ tests/outputs_numbered/nested_mixins.css | 14 ++++++++++++ 4 files changed, 59 insertions(+) create mode 100644 tests/inputs/nested_mixins.scss create mode 100644 tests/outputs/nested_mixins.css create mode 100644 tests/outputs_numbered/nested_mixins.css diff --git a/src/Compiler.php b/src/Compiler.php index 7e93fcb0..485e0fd4 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -2944,11 +2944,13 @@ protected function setRaw($name, $value, Environment $env) public function get($name, $shouldThrow = true, Environment $env = null) { $normalizedName = $this->normalizeName($name); + $specialContentKey = self::$namespaces['special'] . 'content'; if (! isset($env)) { $env = $this->getStoreEnv(); } + $nextIsRoot = false; $hasNamespace = $normalizedName[0] === '^' || $normalizedName[0] === '@' || $normalizedName[0] === '%'; for (;;) { if (array_key_exists($normalizedName, $env->store)) { @@ -2956,6 +2958,12 @@ public function get($name, $shouldThrow = true, Environment $env = null) } if (! $hasNamespace && isset($env->marker)) { + if (! $nextIsRoot && !empty($env->store[$specialContentKey])) { + $env = $env->store[$specialContentKey]->scope; + $nextIsRoot = true; + continue; + } + $env = $this->rootEnv; continue; } diff --git a/tests/inputs/nested_mixins.scss b/tests/inputs/nested_mixins.scss new file mode 100644 index 00000000..f72ce365 --- /dev/null +++ b/tests/inputs/nested_mixins.scss @@ -0,0 +1,28 @@ +@mixin container() { + .container { + @content; + } +} +@mixin add-size($size) { + width: $size; +} +@function add($a, $b) { + @return $a + $b; +} + +div { + @include container() { + $i: 10px; + @include container() { + width: $i; + max-width: add($i, 2px); + } + @include add-size($i); + .foo { + @include add-size($i); + } + .bar { + @include add-size(add($i, 2px)); + } + } +} diff --git a/tests/outputs/nested_mixins.css b/tests/outputs/nested_mixins.css new file mode 100644 index 00000000..432580b8 --- /dev/null +++ b/tests/outputs/nested_mixins.css @@ -0,0 +1,9 @@ +div .container { + width: 10px; } + div .container .container { + width: 10px; + max-width: 12px; } + div .container .foo { + width: 10px; } + div .container .bar { + width: 12px; } diff --git a/tests/outputs_numbered/nested_mixins.css b/tests/outputs_numbered/nested_mixins.css new file mode 100644 index 00000000..ae9c6029 --- /dev/null +++ b/tests/outputs_numbered/nested_mixins.css @@ -0,0 +1,14 @@ +/* line 13, inputs/nested_mixins.scss */ +/* line 2, inputs/nested_mixins.scss */ + div .container { + width: 10px; } +/* line 2, inputs/nested_mixins.scss */ +div .container .container { + width: 10px; + max-width: 12px; } +/* line 21, inputs/nested_mixins.scss */ +div .container .foo { + width: 10px; } +/* line 24, inputs/nested_mixins.scss */ +div .container .bar { + width: 12px; } From 3e1b715325f85cf357c18c0c66856ec117b19dd8 Mon Sep 17 00:00:00 2001 From: Frederic Massart Date: Fri, 22 Jul 2016 15:19:21 +0800 Subject: [PATCH 057/329] Nesting with immediate relationship combinators --- src/Compiler.php | 57 +++++++++++++++++++--- tests/inputs/extends.scss | 18 +++++++ tests/inputs/extends_nesting.scss | 44 +++++++++++++++++ tests/outputs/extends.css | 3 ++ tests/outputs/extends_nesting.css | 28 +++++++++++ tests/outputs_numbered/extends.css | 10 ++++ tests/outputs_numbered/extends_nesting.css | 37 ++++++++++++++ 7 files changed, 190 insertions(+), 7 deletions(-) create mode 100644 tests/inputs/extends_nesting.scss create mode 100644 tests/outputs/extends_nesting.css create mode 100644 tests/outputs_numbered/extends_nesting.css diff --git a/src/Compiler.php b/src/Compiler.php index 485e0fd4..c1c14617 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -397,23 +397,46 @@ protected function matchExtends($selector, &$out, $from = 0, $initial = true) } if ($this->matchExtendsSingle($part, $origin)) { - $before = array_slice($selector, 0, $i); + $after = array_slice($selector, $i + 1); - $s = count($before); + $j = $i; + $s = $i; + do { + $nonBreakableBefore = $j != $i ? array_slice($selector, $j, $i - $j) : []; + $before = array_slice($selector, 0, $j); + $slice = end($before); + $hasImmediateRelationshipCombinator = !empty($slice) && $this->isImmediateRelationshipCombinator($slice[0]); + if ($hasImmediateRelationshipCombinator) { + $j -= 2; + } + } while ($hasImmediateRelationshipCombinator); foreach ($origin as $new) { $k = 0; // remove shared parts if ($initial) { - while ($k < $s && isset($new[$k]) && $before[$k] === $new[$k]) { + while ($k < $s && isset($new[$k]) && $selector[$k] === $new[$k]) { $k++; } } + $replacement = []; + $tempReplacement = $k > 0 ? array_slice($new, $k) : $new; + for ($l = count($tempReplacement) - 1; $l >= 0 ; $l--) { + $slice = $tempReplacement[$l]; + array_unshift($replacement, $slice); + if (!$this->isImmediateRelationshipCombinator(end($slice))) { + break; + } + } + $afterBefore = $l != 0 ? array_slice($tempReplacement, 0, $l) : []; + $result = array_merge( $before, - $k > 0 ? array_slice($new, $k) : $new, + $afterBefore, + $nonBreakableBefore, + $replacement, $after ); @@ -424,14 +447,22 @@ protected function matchExtends($selector, &$out, $from = 0, $initial = true) $out[] = $result; // recursively check for more matches - $this->matchExtends($result, $out, $i, false); + $this->matchExtends($result, $out, count($before) + count($afterBefore) + count($nonBreakableBefore), false); // selector sequence merging if (! empty($before) && count($new) > 1) { + $slice = !empty($afterBefore) ? end($afterBefore) : null; + + if ($slice && $this->isImmediateRelationshipCombinator(end($slice))) { + continue; + } + $result2 = array_merge( - array_slice($new, 0, -1), + $k > 0 ? array_slice($before, 0, $k) : [], + $afterBefore, $k > 0 ? array_slice($before, $k) : $before, - array_slice($new, -1), + $nonBreakableBefore, + $replacement, $after ); @@ -1808,6 +1839,18 @@ protected function isTruthy($value) return $value !== self::$false && $value !== self::$null; } + /** + * Is the value a direct relationship combinator? + * + * @param string $value + * + * @return bool + */ + protected function isImmediateRelationshipCombinator($value) + { + return $value === '>' || $value === '+' || $value === '~'; + } + /** * Should $value cause its operand to eval * diff --git a/tests/inputs/extends.scss b/tests/inputs/extends.scss index 467d3624..dbff56fc 100644 --- a/tests/inputs/extends.scss +++ b/tests/inputs/extends.scss @@ -305,3 +305,21 @@ $color-base: white; @extend %pagination-bullet; } } + +@mixin nested-foo() { + .in-nested-foo { + @content; + } +} + +.parent-nested-foo-include { + @include nested-foo() { + .child-nested-foo-include { + color: green; + } + } +} + +.beard + .mustache { + @extend .child-nested-foo-include; +} diff --git a/tests/inputs/extends_nesting.scss b/tests/inputs/extends_nesting.scss new file mode 100644 index 00000000..0cae18dc --- /dev/null +++ b/tests/inputs/extends_nesting.scss @@ -0,0 +1,44 @@ +.btn { + padding: 1px; +} +.btn-lg { + font-size: 10px; +} +.dropup .btn-lg .caret { + border-width: 100px; +} + +.dropup .btn { + content: "dropup btn"; + .caret { + content: "dropup btn caret"; + } +} +.dropup > .btn { + content: "dropup > btn"; + > .caret { + content: "dropup > btn > caret"; + } +} +.dropup + .btn { + content: "dropup + btn"; + + .caret { + content: "dropup + btn + caret"; + } +} +.dropup.btn { + content: "dropupbtn"; + &.caret { + content: "dropupbtncaret"; + } +} + +.btn-group-lg > .btn { + @extend .btn-lg; +} + +.extend { + .the-button { + @extend .btn; + } +} diff --git a/tests/outputs/extends.css b/tests/outputs/extends.css index 8e2916a3..7ced1cad 100644 --- a/tests/outputs/extends.css +++ b/tests/outputs/extends.css @@ -138,3 +138,6 @@ body .to-extend, body .test { margin-left: 0; } .pagination-bullet.is-active { background-color: white; } + +.parent-nested-foo-include .in-nested-foo .child-nested-foo-include, .parent-nested-foo-include .in-nested-foo .beard + .mustache { + color: green; } diff --git a/tests/outputs/extends_nesting.css b/tests/outputs/extends_nesting.css new file mode 100644 index 00000000..42329481 --- /dev/null +++ b/tests/outputs/extends_nesting.css @@ -0,0 +1,28 @@ +.btn, .extend .the-button { + padding: 1px; } + +.btn-lg, .btn-group-lg > .btn, .extend .btn-group-lg > .the-button { + font-size: 10px; } + +.dropup .btn-lg .caret, .dropup .btn-group-lg > .btn .caret, .dropup .extend .btn-group-lg > .the-button .caret, .extend .dropup .btn-group-lg > .the-button .caret { + border-width: 100px; } + +.dropup .btn, .dropup .extend .the-button, .extend .dropup .the-button { + content: "dropup btn"; } + .dropup .btn .caret, .dropup .extend .the-button .caret, .extend .dropup .the-button .caret { + content: "dropup btn caret"; } + +.dropup > .btn, .extend .dropup > .the-button { + content: "dropup > btn"; } + .dropup > .btn > .caret, .extend .dropup > .the-button > .caret { + content: "dropup > btn > caret"; } + +.dropup + .btn, .extend .dropup + .the-button { + content: "dropup + btn"; } + .dropup + .btn + .caret, .extend .dropup + .the-button + .caret { + content: "dropup + btn + caret"; } + +.dropup.btn, .extend .the-button.dropup { + content: "dropupbtn"; } + .dropup.btn.caret, .extend .the-button.dropup.caret { + content: "dropupbtncaret"; } diff --git a/tests/outputs_numbered/extends.css b/tests/outputs_numbered/extends.css index e32f01b7..51297cb4 100644 --- a/tests/outputs_numbered/extends.css +++ b/tests/outputs_numbered/extends.css @@ -215,3 +215,13 @@ body .to-extend, body .test { background-color: white; } /* line 303, inputs/extends.scss */ /* line 304, inputs/extends.scss */ + +/* line 315, inputs/extends.scss */ + +/* line 310, inputs/extends.scss */ + +/* line 317, inputs/extends.scss */ + +.parent-nested-foo-include .in-nested-foo .child-nested-foo-include, .parent-nested-foo-include .in-nested-foo .beard + .mustache { + color: green; } +/* line 323, inputs/extends.scss */ diff --git a/tests/outputs_numbered/extends_nesting.css b/tests/outputs_numbered/extends_nesting.css new file mode 100644 index 00000000..08c3027d --- /dev/null +++ b/tests/outputs_numbered/extends_nesting.css @@ -0,0 +1,37 @@ +/* line 1, inputs/extends_nesting.scss */ +.btn, .extend .the-button { + padding: 1px; } +/* line 4, inputs/extends_nesting.scss */ +.btn-lg, .btn-group-lg > .btn, .extend .btn-group-lg > .the-button { + font-size: 10px; } +/* line 7, inputs/extends_nesting.scss */ +.dropup .btn-lg .caret, .dropup .btn-group-lg > .btn .caret, .dropup .extend .btn-group-lg > .the-button .caret, .extend .dropup .btn-group-lg > .the-button .caret { + border-width: 100px; } +/* line 11, inputs/extends_nesting.scss */ +.dropup .btn, .dropup .extend .the-button, .extend .dropup .the-button { + content: "dropup btn"; } +/* line 13, inputs/extends_nesting.scss */ +.dropup .btn .caret, .dropup .extend .the-button .caret, .extend .dropup .the-button .caret { + content: "dropup btn caret"; } +/* line 17, inputs/extends_nesting.scss */ +.dropup > .btn, .extend .dropup > .the-button { + content: "dropup > btn"; } +/* line 19, inputs/extends_nesting.scss */ +.dropup > .btn > .caret, .extend .dropup > .the-button > .caret { + content: "dropup > btn > caret"; } +/* line 23, inputs/extends_nesting.scss */ +.dropup + .btn, .extend .dropup + .the-button { + content: "dropup + btn"; } +/* line 25, inputs/extends_nesting.scss */ +.dropup + .btn + .caret, .extend .dropup + .the-button + .caret { + content: "dropup + btn + caret"; } +/* line 29, inputs/extends_nesting.scss */ +.dropup.btn, .extend .the-button.dropup { + content: "dropupbtn"; } +/* line 31, inputs/extends_nesting.scss */ +.dropup.btn.caret, .extend .the-button.dropup.caret { + content: "dropupbtncaret"; } +/* line 36, inputs/extends_nesting.scss */ +/* line 40, inputs/extends_nesting.scss */ + +/* line 41, inputs/extends_nesting.scss */ From 62536ec1b32b63499684a91d67e8b6d90508bad2 Mon Sep 17 00:00:00 2001 From: Frederic Massart Date: Mon, 25 Jul 2016 19:12:10 +0800 Subject: [PATCH 058/329] Shared direct relationship are merged on extend --- src/Compiler.php | 96 +++++++++++++++++++++++------- tests/inputs/extends.scss | 20 +++++++ tests/outputs/extends.css | 10 ++++ tests/outputs_numbered/extends.css | 15 +++++ 4 files changed, 119 insertions(+), 22 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index c1c14617..d9dcc6e8 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -399,24 +399,15 @@ protected function matchExtends($selector, &$out, $from = 0, $initial = true) if ($this->matchExtendsSingle($part, $origin)) { $after = array_slice($selector, $i + 1); - $j = $i; - $s = $i; - do { - $nonBreakableBefore = $j != $i ? array_slice($selector, $j, $i - $j) : []; - $before = array_slice($selector, 0, $j); - $slice = end($before); - $hasImmediateRelationshipCombinator = !empty($slice) && $this->isImmediateRelationshipCombinator($slice[0]); - if ($hasImmediateRelationshipCombinator) { - $j -= 2; - } - } while ($hasImmediateRelationshipCombinator); + $before = array_slice($selector, 0, $i); + list($before, $nonBreakableBefore) = $this->extractRelationshipFromFragment($before); foreach ($origin as $new) { $k = 0; // remove shared parts if ($initial) { - while ($k < $s && isset($new[$k]) && $selector[$k] === $new[$k]) { + while ($k < $i && isset($new[$k]) && $selector[$k] === $new[$k]) { $k++; } } @@ -432,10 +423,12 @@ protected function matchExtends($selector, &$out, $from = 0, $initial = true) } $afterBefore = $l != 0 ? array_slice($tempReplacement, 0, $l) : []; + // Merge shared direct relationships. + $mergedBefore = $this->mergeDirectRelationships($afterBefore, $nonBreakableBefore); + $result = array_merge( $before, - $afterBefore, - $nonBreakableBefore, + $mergedBefore, $replacement, $after ); @@ -447,20 +440,20 @@ protected function matchExtends($selector, &$out, $from = 0, $initial = true) $out[] = $result; // recursively check for more matches - $this->matchExtends($result, $out, count($before) + count($afterBefore) + count($nonBreakableBefore), false); + $this->matchExtends($result, $out, count($before) + count($mergedBefore), false); // selector sequence merging if (! empty($before) && count($new) > 1) { - $slice = !empty($afterBefore) ? end($afterBefore) : null; - if ($slice && $this->isImmediateRelationshipCombinator(end($slice))) { - continue; - } + $sharedParts = $k > 0 ? array_slice($before, 0, $k) : []; + $postSharedParts = $k > 0 ? array_slice($before, $k) : $before; + list($injectBetweenSharedParts, $nonBreakable2) = $this->extractRelationshipFromFragment($afterBefore); $result2 = array_merge( - $k > 0 ? array_slice($before, 0, $k) : [], - $afterBefore, - $k > 0 ? array_slice($before, $k) : $before, + $sharedParts, + $injectBetweenSharedParts, + $postSharedParts, + $nonBreakable2, $nonBreakableBefore, $replacement, $after @@ -543,6 +536,37 @@ protected function matchExtendsSingle($rawSingle, &$outOrigin) return $found; } + + /** + * Extract a relationship from the fragment. + * + * When extracting the last portion of a selector we will be left with a + * fragment which may end with a direction relationship combinator. This + * method will extract the relationship fragment and return it along side + * the rest. + * + * @param array $fragment The selector fragment maybe ending with a direction relationship combinator. + * @return array The selector without the relationship fragment if any, the relationship fragment. + */ + protected function extractRelationshipFromFragment(array $fragment) + { + $parents = []; + $children = []; + $j = $i = count($fragment); + + do { + $children = $j != $i ? array_slice($fragment, $j, $i - $j) : []; + $parents = array_slice($fragment, 0, $j); + $slice = end($parents); + $hasImmediateRelationshipCombinator = !empty($slice) && $this->isImmediateRelationshipCombinator($slice[0]); + if ($hasImmediateRelationshipCombinator) { + $j -= 2; + } + } while ($hasImmediateRelationshipCombinator); + + return [$parents, $children]; + } + /** * Combine selector single * @@ -1315,6 +1339,34 @@ protected function compileMediaQuery($queryList) return $out; } + protected function mergeDirectRelationships($selectors1, $selectors2) { + if (empty($selectors1) || empty($selectors2)) { + return array_merge($selectors1, $selectors2); + } + + $part1 = end($selectors1); + $part2 = end($selectors2); + if (!$this->isImmediateRelationshipCombinator($part1[0]) || $part1 !== $part2) { + return array_merge($selectors1, $selectors2); + } + + $merged = []; + do { + $part1 = array_pop($selectors1); + $part2 = array_pop($selectors2); + + if ($this->isImmediateRelationshipCombinator($part1[0]) && $part1 === $part2) { + array_unshift($merged, $part1); + array_unshift($merged, [array_pop($selectors1)[0] . array_pop($selectors2)[0]]); + } else { + $merged = array_merge($selectors1, [$part1], $selectors2, [$part2], $merged); + break; + } + } while (!empty($selectors1) && !empty($selectors2)); + + return $merged; + } + /** * Merge media types * diff --git a/tests/inputs/extends.scss b/tests/inputs/extends.scss index dbff56fc..1024c93d 100644 --- a/tests/inputs/extends.scss +++ b/tests/inputs/extends.scss @@ -323,3 +323,23 @@ $color-base: white; .beard + .mustache { @extend .child-nested-foo-include; } + +// Shared direct relationship combinator. +.btn-group-lg > .btn { + @extend .btn-lg; +} +.btn-group > .btn-lg { + padding-right: 12px; + padding-left: 12px; +} + +// Reverse rules with direct relationship combinators. +.fp-content-center form + div { + @extend .form-group; + padding-left: 0; +} +.form-inline + .a { + .form-group > b { + margin-bottom: 0; + } +} diff --git a/tests/outputs/extends.css b/tests/outputs/extends.css index 7ced1cad..bc953bb8 100644 --- a/tests/outputs/extends.css +++ b/tests/outputs/extends.css @@ -141,3 +141,13 @@ body .to-extend, body .test { .parent-nested-foo-include .in-nested-foo .child-nested-foo-include, .parent-nested-foo-include .in-nested-foo .beard + .mustache { color: green; } + +.btn-group > .btn-lg, .btn-group-lg.btn-group > .btn, .edit .actions .btn-group-lg.btn-group > button, .edit .new .actions .btn-group-lg.btn-group > button { + padding-right: 12px; + padding-left: 12px; } + +.fp-content-center form + div { + padding-left: 0; } + +.form-inline + .a .form-group > b, .form-inline + .a .fp-content-center form + div > b, .fp-content-center .form-inline + .a form + div > b { + margin-bottom: 0; } diff --git a/tests/outputs_numbered/extends.css b/tests/outputs_numbered/extends.css index 51297cb4..c64df92a 100644 --- a/tests/outputs_numbered/extends.css +++ b/tests/outputs_numbered/extends.css @@ -225,3 +225,18 @@ body .to-extend, body .test { .parent-nested-foo-include .in-nested-foo .child-nested-foo-include, .parent-nested-foo-include .in-nested-foo .beard + .mustache { color: green; } /* line 323, inputs/extends.scss */ +/* line 328, inputs/extends.scss */ + +/* line 331, inputs/extends.scss */ + +.btn-group > .btn-lg, .btn-group-lg.btn-group > .btn, .edit .actions .btn-group-lg.btn-group > button, .edit .new .actions .btn-group-lg.btn-group > button { + padding-right: 12px; + padding-left: 12px; } +/* line 337, inputs/extends.scss */ +.fp-content-center form + div { + padding-left: 0; } +/* line 341, inputs/extends.scss */ +/* line 342, inputs/extends.scss */ + +.form-inline + .a .form-group > b, .form-inline + .a .fp-content-center form + div > b, .fp-content-center .form-inline + .a form + div > b { + margin-bottom: 0; } From b7675976a298570c27d875b51043a632fb0358c3 Mon Sep 17 00:00:00 2001 From: Frederic Massart Date: Tue, 26 Jul 2016 18:52:58 +0800 Subject: [PATCH 059/329] Do not extend decorated tags with another tag --- src/Compiler.php | 18 +++++++++++++++-- tests/inputs/extends.scss | 32 ++++++++++++++++++++++++++++++ tests/outputs/extends.css | 12 +++++++++++ tests/outputs_numbered/extends.css | 22 ++++++++++++++++++++ 4 files changed, 82 insertions(+), 2 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index d9dcc6e8..d008a844 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -395,7 +395,6 @@ protected function matchExtends($selector, &$out, $from = 0, $initial = true) if ($i < $from) { continue; } - if ($this->matchExtendsSingle($part, $origin)) { $after = array_slice($selector, $i + 1); @@ -492,6 +491,12 @@ protected function matchExtendsSingle($rawSingle, &$outOrigin) } } + $extendingDecoratedTag = false; + if (count($single) > 1) { + $matches = null; + $extendingDecoratedTag = preg_match('/^[a-z0-9]+$/i', $single[0], $matches) ? $matches[0] : false; + } + foreach ($single as $part) { if (isset($this->extendsMap[$part])) { foreach ($this->extendsMap[$part] as $idx) { @@ -521,7 +526,16 @@ protected function matchExtendsSingle($rawSingle, &$outOrigin) return false; } - $combined = $this->combineSelectorSingle(end($new), $rem); + $replacement = end($new); + + // Extending a decorated tag with another tag is not possible. + if ($extendingDecoratedTag && $replacement[0] != $extendingDecoratedTag + && preg_match('/^[a-z0-9]+$/i', $replacement[0])) { + unset($origin[$j]); + continue; + } + + $combined = $this->combineSelectorSingle($replacement, $rem); if (count(array_diff($combined, $origin[$j][count($origin[$j]) - 1]))) { $origin[$j][count($origin[$j]) - 1] = $combined; diff --git a/tests/inputs/extends.scss b/tests/inputs/extends.scss index 1024c93d..f9ea2a30 100644 --- a/tests/inputs/extends.scss +++ b/tests/inputs/extends.scss @@ -343,3 +343,35 @@ $color-base: white; margin-bottom: 0; } } + +// Decorated tags cannot be extended by tags of another type. +canvas { + color: yellow; +} +.popup { + color: red; +} +div.popup { + color: blue; +} +.before span.popup .after { + color: green; +} +input { + @extend .popup; +} +img.bar { + @extend .popup; +} +object { + @extend canvas; +} +embed.bar { + @extend canvas; +} +.prepend { + input.foo, + div.foo { + @extend .popup + } +} diff --git a/tests/outputs/extends.css b/tests/outputs/extends.css index bc953bb8..6a8dd855 100644 --- a/tests/outputs/extends.css +++ b/tests/outputs/extends.css @@ -151,3 +151,15 @@ body .to-extend, body .test { .form-inline + .a .form-group > b, .form-inline + .a .fp-content-center form + div > b, .fp-content-center .form-inline + .a form + div > b { margin-bottom: 0; } + +canvas, object, embed.bar { + color: yellow; } + +.popup, input, img.bar, .prepend input.foo, .prepend div.foo { + color: red; } + +div.popup, .prepend div.foo { + color: blue; } + +.before span.popup .after { + color: green; } diff --git a/tests/outputs_numbered/extends.css b/tests/outputs_numbered/extends.css index c64df92a..aa4c20ac 100644 --- a/tests/outputs_numbered/extends.css +++ b/tests/outputs_numbered/extends.css @@ -240,3 +240,25 @@ body .to-extend, body .test { .form-inline + .a .form-group > b, .form-inline + .a .fp-content-center form + div > b, .fp-content-center .form-inline + .a form + div > b { margin-bottom: 0; } +/* line 348, inputs/extends.scss */ +canvas, object, embed.bar { + color: yellow; } +/* line 351, inputs/extends.scss */ +.popup, input, img.bar, .prepend input.foo, .prepend div.foo { + color: red; } +/* line 354, inputs/extends.scss */ +div.popup, .prepend div.foo { + color: blue; } +/* line 357, inputs/extends.scss */ +.before span.popup .after { + color: green; } +/* line 360, inputs/extends.scss */ +/* line 363, inputs/extends.scss */ + +/* line 366, inputs/extends.scss */ + +/* line 369, inputs/extends.scss */ + +/* line 372, inputs/extends.scss */ + +/* line 373, inputs/extends.scss */ From f7c9a494de90ce13db84fb90cca13bf24dc60eb3 Mon Sep 17 00:00:00 2001 From: Dan Diemer Date: Tue, 23 Aug 2016 11:06:04 -0400 Subject: [PATCH 060/329] =?UTF-8?q?Let=20@content=20work=20when=20a=20bloc?= =?UTF-8?q?k=20isn=E2=80=99t=20passed=20in.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Compiler.php | 4 +++- tests/inputs/content.scss | 9 +++++++++ tests/outputs/content.css | 4 ++++ tests/outputs_numbered/content.css | 4 ++++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Compiler.php b/src/Compiler.php index 7e93fcb0..07efa95a 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -1723,7 +1723,9 @@ protected function compileChild($child, OutputBlock $out) ?: $this->get(self::$namespaces['special'] . 'content', false, $this->env); if (! $content) { - $this->throwError('Expected @content inside of mixin'); + $content = new \stdClass(); + $content->scope = new \stdClass(); + $content->children = $this->storeEnv->parent->block->children; break; } diff --git a/tests/inputs/content.scss b/tests/inputs/content.scss index a9c00c46..0a16ae2f 100644 --- a/tests/inputs/content.scss +++ b/tests/inputs/content.scss @@ -116,3 +116,12 @@ A { display: none; } } + +@mixin empty_content() { + @content; +} +.test_empty_content { + display: inline; + font-weight: bold; + @include empty_content() +} diff --git a/tests/outputs/content.css b/tests/outputs/content.css index 6a8ba90b..6b24aca3 100644 --- a/tests/outputs/content.css +++ b/tests/outputs/content.css @@ -36,3 +36,7 @@ A { .test { display: none; } + +.test_empty_content { + display: inline; + font-weight: bold; } diff --git a/tests/outputs_numbered/content.css b/tests/outputs_numbered/content.css index a0bf6e1e..9d49e316 100644 --- a/tests/outputs_numbered/content.css +++ b/tests/outputs_numbered/content.css @@ -45,3 +45,7 @@ A { /* line 114, inputs/content.scss */ .test { display: none; } +/* line 123, inputs/content.scss */ +.test_empty_content { + display: inline; + font-weight: bold; } From e82bdfb9a41778288871a3f11cbffff6a304e6ce Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Sat, 10 Sep 2016 21:23:35 -0400 Subject: [PATCH 061/329] coding style tweaks --- src/Compiler.php | 52 +++++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index 01442e18..592f53b9 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -395,10 +395,11 @@ protected function matchExtends($selector, &$out, $from = 0, $initial = true) if ($i < $from) { continue; } - if ($this->matchExtendsSingle($part, $origin)) { + if ($this->matchExtendsSingle($part, $origin)) { $after = array_slice($selector, $i + 1); $before = array_slice($selector, 0, $i); + list($before, $nonBreakableBefore) = $this->extractRelationshipFromFragment($before); foreach ($origin as $new) { @@ -413,13 +414,16 @@ protected function matchExtends($selector, &$out, $from = 0, $initial = true) $replacement = []; $tempReplacement = $k > 0 ? array_slice($new, $k) : $new; - for ($l = count($tempReplacement) - 1; $l >= 0 ; $l--) { + + for ($l = count($tempReplacement) - 1; $l >= 0; $l--) { $slice = $tempReplacement[$l]; array_unshift($replacement, $slice); - if (!$this->isImmediateRelationshipCombinator(end($slice))) { + + if (! $this->isImmediateRelationshipCombinator(end($slice))) { break; } } + $afterBefore = $l != 0 ? array_slice($tempReplacement, 0, $l) : []; // Merge shared direct relationships. @@ -443,9 +447,9 @@ protected function matchExtends($selector, &$out, $from = 0, $initial = true) // selector sequence merging if (! empty($before) && count($new) > 1) { - $sharedParts = $k > 0 ? array_slice($before, 0, $k) : []; $postSharedParts = $k > 0 ? array_slice($before, $k) : $before; + list($injectBetweenSharedParts, $nonBreakable2) = $this->extractRelationshipFromFragment($afterBefore); $result2 = array_merge( @@ -492,6 +496,7 @@ protected function matchExtendsSingle($rawSingle, &$outOrigin) } $extendingDecoratedTag = false; + if (count($single) > 1) { $matches = null; $extendingDecoratedTag = preg_match('/^[a-z0-9]+$/i', $single[0], $matches) ? $matches[0] : false; @@ -529,8 +534,9 @@ protected function matchExtendsSingle($rawSingle, &$outOrigin) $replacement = end($new); // Extending a decorated tag with another tag is not possible. - if ($extendingDecoratedTag && $replacement[0] != $extendingDecoratedTag - && preg_match('/^[a-z0-9]+$/i', $replacement[0])) { + if ($extendingDecoratedTag && $replacement[0] != $extendingDecoratedTag && + preg_match('/^[a-z0-9]+$/i', $replacement[0]) + ) { unset($origin[$j]); continue; } @@ -568,15 +574,17 @@ protected function extractRelationshipFromFragment(array $fragment) $children = []; $j = $i = count($fragment); - do { + for (;;) { $children = $j != $i ? array_slice($fragment, $j, $i - $j) : []; $parents = array_slice($fragment, 0, $j); $slice = end($parents); - $hasImmediateRelationshipCombinator = !empty($slice) && $this->isImmediateRelationshipCombinator($slice[0]); - if ($hasImmediateRelationshipCombinator) { - $j -= 2; + + if (empty($slice) || ! $this->isImmediateRelationshipCombinator($slice[0])) { + break; } - } while ($hasImmediateRelationshipCombinator); + + $j -= 2; + } return [$parents, $children]; } @@ -1353,30 +1361,33 @@ protected function compileMediaQuery($queryList) return $out; } - protected function mergeDirectRelationships($selectors1, $selectors2) { + protected function mergeDirectRelationships($selectors1, $selectors2) + { if (empty($selectors1) || empty($selectors2)) { return array_merge($selectors1, $selectors2); } $part1 = end($selectors1); $part2 = end($selectors2); - if (!$this->isImmediateRelationshipCombinator($part1[0]) || $part1 !== $part2) { + + if (! $this->isImmediateRelationshipCombinator($part1[0]) || $part1 !== $part2) { return array_merge($selectors1, $selectors2); } $merged = []; + do { $part1 = array_pop($selectors1); $part2 = array_pop($selectors2); - if ($this->isImmediateRelationshipCombinator($part1[0]) && $part1 === $part2) { - array_unshift($merged, $part1); - array_unshift($merged, [array_pop($selectors1)[0] . array_pop($selectors2)[0]]); - } else { + if ($this->isImmediateRelationshipCombinator($part1[0]) && $part1 !== $part2) { $merged = array_merge($selectors1, [$part1], $selectors2, [$part2], $merged); break; } - } while (!empty($selectors1) && !empty($selectors2)); + + array_unshift($merged, $part1); + array_unshift($merged, [array_pop($selectors1)[0] . array_pop($selectors2)[0]]); + } while (! empty($selectors1) && ! empty($selectors2)); return $merged; } @@ -1720,7 +1731,7 @@ protected function compileChild($child, OutputBlock $out) $end = $end[1]; $d = $start < $end ? 1 : -1; - while (true) { + for (;;) { if ((! $for->until && $start - $d == $end) || ($for->until && $start == $end) ) { @@ -3063,13 +3074,14 @@ public function get($name, $shouldThrow = true, Environment $env = null) $nextIsRoot = false; $hasNamespace = $normalizedName[0] === '^' || $normalizedName[0] === '@' || $normalizedName[0] === '%'; + for (;;) { if (array_key_exists($normalizedName, $env->store)) { return $env->store[$normalizedName]; } if (! $hasNamespace && isset($env->marker)) { - if (! $nextIsRoot && !empty($env->store[$specialContentKey])) { + if (! $nextIsRoot && ! empty($env->store[$specialContentKey])) { $env = $env->store[$specialContentKey]->scope; $nextIsRoot = true; continue; From 6fdfe19d2b13a3f12ba0792227f0718809ce4e4d Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Sat, 10 Sep 2016 21:34:11 -0400 Subject: [PATCH 062/329] bump version --- src/Version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Version.php b/src/Version.php index 3be9cc31..80cdeee5 100644 --- a/src/Version.php +++ b/src/Version.php @@ -18,5 +18,5 @@ */ class Version { - const VERSION = 'v0.6.5'; + const VERSION = 'v0.6.6'; } From 8533a50c10f511ad63d03664d17dedd4cce29859 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Sun, 11 Sep 2016 00:15:21 -0400 Subject: [PATCH 063/329] v0.6.6 fixes #199 --- tests/FailingTest.php | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/tests/FailingTest.php b/tests/FailingTest.php index 3cdf0a04..86865049 100644 --- a/tests/FailingTest.php +++ b/tests/FailingTest.php @@ -84,32 +84,6 @@ public function provideFailing() background: #eee; } .nav-bar > .item, header ul > .item, header ul > li { margin: 0 10px; } -END_OF_EXPECTED - ), - array( - '#199 - issue with selectors', <<<'END_OF_SCSS' -.abc { - color: #ddd; -} - -a.abc:hover { - text-decoration: underline; -} - -small { - @extend .abc; - font-weight: italic; -} -END_OF_SCSS - , << Date: Fri, 4 Nov 2016 14:37:08 -0400 Subject: [PATCH 064/329] fixes #471 - list interpolation --- src/Compiler.php | 33 ++++++++++++++++++++++++ tests/inputs/interpolation.scss | 6 +++++ tests/outputs/interpolation.css | 3 +++ tests/outputs_numbered/interpolation.css | 3 +++ 4 files changed, 45 insertions(+) diff --git a/src/Compiler.php b/src/Compiler.php index 592f53b9..f0eaff78 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -2723,6 +2723,39 @@ public function compileValue($value) $reduced = $this->reduce($exp); switch ($reduced[0]) { + case Type::T_LIST: + $reduced = $this->extractInterpolation($reduced); + + if ($reduced[0] !== Type::T_LIST) { + break; + } + + list(, $delim, $items) = $reduced; + + if ($delim !== ' ') { + $delim .= ' '; + } + + $filtered = []; + + foreach ($items as $item) { + if ($item[0] === Type::T_NULL) { + continue; + } + + $temp = $this->compileValue([Type::T_KEYWORD, $item]); + if ($temp[0] === Type::T_STRING) { + $filtered[] = $this->compileStringContent($temp); + } elseif ($temp[0] === Type::T_KEYWORD) { + $filtered[] = $temp[1]; + } else { + $filtered[] = $this->compileValue($temp); + } + } + + $reduced = [Type::T_KEYWORD, implode("$delim", $filtered)]; + break; + case Type::T_STRING: $reduced = [Type::T_KEYWORD, $this->compileStringContent($reduced)]; break; diff --git a/tests/inputs/interpolation.scss b/tests/inputs/interpolation.scss index e4df9c84..e3736ca5 100644 --- a/tests/inputs/interpolation.scss +++ b/tests/inputs/interpolation.scss @@ -91,3 +91,9 @@ body{ foo, #{x, y} { color: #abc; } + +// interpolate lists +$foo: ('a', 'b'); +div { + prop: #{$foo}; +} diff --git a/tests/outputs/interpolation.css b/tests/outputs/interpolation.css index ebe8463d..d3084575 100644 --- a/tests/outputs/interpolation.css +++ b/tests/outputs/interpolation.css @@ -58,3 +58,6 @@ body { foo, x, y { color: #abc; } + +div { + prop: a, b; } diff --git a/tests/outputs_numbered/interpolation.css b/tests/outputs_numbered/interpolation.css index 64ef9ebc..f6d5f5fa 100644 --- a/tests/outputs_numbered/interpolation.css +++ b/tests/outputs_numbered/interpolation.css @@ -68,3 +68,6 @@ body { /* line 91, inputs/interpolation.scss */ foo, x, y { color: #abc; } +/* line 97, inputs/interpolation.scss */ +div { + prop: a, b; } From 10c650529b5c2f72094cc885eca327ead519e8c6 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Tue, 8 Nov 2016 13:17:17 -0500 Subject: [PATCH 065/329] fixes #476 - pscss: enable --line-numbers and --debug-info for stdin --- bin/pscss | 4 ++-- src/Compiler.php | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/bin/pscss b/bin/pscss index 3175ea0b..4ec061b8 100755 --- a/bin/pscss +++ b/bin/pscss @@ -169,11 +169,11 @@ if ($dumpTree) { $scss = new Compiler(); -if ($debugInfo && $inputFile) { +if ($debugInfo) { $scss->setLineNumberStyle(Compiler::DEBUG_INFO); } -if ($lineNumbers && $inputFile) { +if ($lineNumbers) { $scss->setLineNumberStyle(Compiler::LINE_COMMENTS); } diff --git a/src/Compiler.php b/src/Compiler.php index f0eaff78..fdb68240 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -1015,12 +1015,15 @@ protected function compileBlock(Block $block) switch ($this->lineNumberStyle) { case self::LINE_COMMENTS: - $annotation->lines[] = '/* line ' . $line . ', ' . $file . ' */'; + $annotation->lines[] = '/* line ' . $line + . ($file ? ', ' . $file : '') + . ' */'; break; case self::DEBUG_INFO: - $annotation->lines[] = '@media -sass-debug-info{filename{font-family:"' . $file - . '"}line{font-family:' . $line . '}}'; + $annotation->lines[] = '@media -sass-debug-info{' + . ($file ? 'filename{font-family:"' . $file . '"}' : '') + . 'line{font-family:' . $line . '}}'; break; } From f3bb6b7de4a11c10ad6f5e0e922b9197e962e404 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Tue, 22 Nov 2016 15:21:33 -0500 Subject: [PATCH 066/329] Change self:: to static:: where possible --- src/Compiler.php | 98 ++++++++++++++++++++++----------------------- src/Node/Number.php | 10 ++--- src/Parser.php | 38 +++++++++--------- src/Server.php | 2 +- 4 files changed, 74 insertions(+), 74 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index fdb68240..df322273 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -729,7 +729,7 @@ protected function compileAtRoot(Block $block) { $env = $this->pushEnv($block); $envs = $this->compactEnv($env); - $without = isset($block->with) ? $this->compileWith($block->with) : self::WITH_RULE; + $without = isset($block->with) ? $this->compileWith($block->with) : static::WITH_RULE; // wrap inline selector if ($block->selector) { @@ -854,12 +854,12 @@ private function compileWith($with) ]; // exclude selectors by default - $without = self::WITH_RULE; + $without = static::WITH_RULE; - if ($this->libMapHasKey([$with, self::$with])) { - $without = self::WITH_ALL; + if ($this->libMapHasKey([$with, static::$with])) { + $without = static::WITH_ALL; - $list = $this->coerceList($this->libMapGet([$with, self::$with])); + $list = $this->coerceList($this->libMapGet([$with, static::$with])); foreach ($list[2] as $item) { $keyword = $this->compileStringContent($this->coerceString($item)); @@ -870,10 +870,10 @@ private function compileWith($with) } } - if ($this->libMapHasKey([$with, self::$without])) { + if ($this->libMapHasKey([$with, static::$without])) { $without = 0; - $list = $this->coerceList($this->libMapGet([$with, self::$without])); + $list = $this->coerceList($this->libMapGet([$with, static::$without])); foreach ($list[2] as $item) { $keyword = $this->compileStringContent($this->coerceString($item)); @@ -920,10 +920,10 @@ private function filterWithout($envs, $without) */ private function isWithout($without, Block $block) { - if ((($without & self::WITH_RULE) && isset($block->selectors)) || - (($without & self::WITH_MEDIA) && + if ((($without & static::WITH_RULE) && isset($block->selectors)) || + (($without & static::WITH_MEDIA) && isset($block->type) && $block->type === Type::T_MEDIA) || - (($without & self::WITH_SUPPORTS) && + (($without & static::WITH_SUPPORTS) && isset($block->type) && $block->type === Type::T_DIRECTIVE && isset($block->name) && $block->name === 'supports') ) { @@ -1014,13 +1014,13 @@ protected function compileBlock(Block $block) $line = $block->sourceLine; switch ($this->lineNumberStyle) { - case self::LINE_COMMENTS: + case static::LINE_COMMENTS: $annotation->lines[] = '/* line ' . $line . ($file ? ', ' . $file : '') . ' */'; break; - case self::DEBUG_INFO: + case static::DEBUG_INFO: $annotation->lines[] = '@media -sass-debug-info{' . ($file ? 'filename{font-family:"' . $file . '"}' : '') . 'line{font-family:' . $line . '}}'; @@ -1583,7 +1583,7 @@ protected function compileChild($child, OutputBlock $out) $shouldSet = $isDefault && (($result = $this->get($name[1], false)) === null - || $result === self::$null); + || $result === static::$null); if (! $isDefault || $shouldSet) { $this->set($name[1], $this->reduce($value)); @@ -1611,7 +1611,7 @@ protected function compileChild($child, OutputBlock $out) if ($value[0] !== Type::T_NULL) { $value = $this->reduce($value); - if ($value[0] === Type::T_NULL || $value === self::$nullString) { + if ($value[0] === Type::T_NULL || $value === static::$nullString) { break; } } @@ -1637,7 +1637,7 @@ protected function compileChild($child, OutputBlock $out) case Type::T_FUNCTION: list(, $block) = $child; - $this->set(self::$namespaces[$block->type] . $block->name, $block); + $this->set(static::$namespaces[$block->type] . $block->name, $block); break; case Type::T_EXTEND: @@ -1685,7 +1685,7 @@ protected function compileChild($child, OutputBlock $out) list(,, $values) = $this->coerceList($item); foreach ($each->vars as $i => $var) { - $this->set($var, isset($values[$i]) ? $values[$i] : self::$null, true); + $this->set($var, isset($values[$i]) ? $values[$i] : static::$null, true); } } @@ -1794,7 +1794,7 @@ protected function compileChild($child, OutputBlock $out) // including a mixin list(, $name, $argValues, $content) = $child; - $mixin = $this->get(self::$namespaces['mixin'] . $name, false); + $mixin = $this->get(static::$namespaces['mixin'] . $name, false); if (! $mixin) { $this->throwError("Undefined mixin $name"); @@ -1813,7 +1813,7 @@ protected function compileChild($child, OutputBlock $out) if (isset($content)) { $content->scope = $callingScope; - $this->setRaw(self::$namespaces['special'] . 'content', $content, $this->env); + $this->setRaw(static::$namespaces['special'] . 'content', $content, $this->env); } if (isset($mixin->args)) { @@ -1830,8 +1830,8 @@ protected function compileChild($child, OutputBlock $out) break; case Type::T_MIXIN_CONTENT: - $content = $this->get(self::$namespaces['special'] . 'content', false, $this->getStoreEnv()) - ?: $this->get(self::$namespaces['special'] . 'content', false, $this->env); + $content = $this->get(static::$namespaces['special'] . 'content', false, $this->getStoreEnv()) + ?: $this->get(static::$namespaces['special'] . 'content', false, $this->env); if (! $content) { $content = new \stdClass(); @@ -1918,7 +1918,7 @@ protected function expToString($exp) */ protected function isTruthy($value) { - return $value !== self::$false && $value !== self::$null; + return $value !== static::$false && $value !== static::$null; } /** @@ -1973,7 +1973,7 @@ protected function reduce($value, $inExp = false) case Type::T_EXPRESSION: list(, $op, $left, $right, $inParens) = $value; - $opName = isset(self::$operatorNames[$op]) ? self::$operatorNames[$op] : $op; + $opName = isset(static::$operatorNames[$op]) ? static::$operatorNames[$op] : $op; $inExp = $inExp || $this->shouldEval($left) || $this->shouldEval($right); $left = $this->reduce($left, true); @@ -2089,11 +2089,11 @@ protected function reduce($value, $inExp = false) if ($op === 'not') { if ($inExp || $inParens) { - if ($exp === self::$false || $exp === self::$null) { - return self::$true; + if ($exp === static::$false || $exp === static::$null) { + return static::$true; } - return self::$false; + return static::$false; } $op = $op . ' '; @@ -2347,7 +2347,7 @@ protected function opAnd($left, $right, $shouldEval) return; } - if ($left !== self::$false and $left !== self::$null) { + if ($left !== static::$false and $left !== static::$null) { return $this->reduce($right, true); } @@ -2369,7 +2369,7 @@ protected function opOr($left, $right, $shouldEval) return; } - if ($left !== self::$false and $left !== self::$null) { + if ($left !== static::$false and $left !== static::$null) { return $left; } @@ -2600,7 +2600,7 @@ protected function opCmpNumberNumber($left, $right) */ public function toBool($thing) { - return $thing ? self::$true : self::$false; + return $thing ? static::$true : static::$false; } /** @@ -2883,7 +2883,7 @@ protected function joinSelectors($parent, $child) $newPart = []; foreach ($part as $p) { - if ($p === self::$selfSelector) { + if ($p === static::$selfSelector) { $setSelf = true; foreach ($parent as $i => $parentPart) { @@ -3102,7 +3102,7 @@ protected function setRaw($name, $value, Environment $env) public function get($name, $shouldThrow = true, Environment $env = null) { $normalizedName = $this->normalizeName($name); - $specialContentKey = self::$namespaces['special'] . 'content'; + $specialContentKey = static::$namespaces['special'] . 'content'; if (! isset($env)) { $env = $this->getStoreEnv(); @@ -3510,7 +3510,7 @@ protected function fileExists($name) */ protected function callScssFunction($name, $argValues, &$returnValue) { - $func = $this->get(self::$namespaces['function'] . $name, false); + $func = $this->get(static::$namespaces['function'] . $name, false); if (! $func) { return false; @@ -3539,7 +3539,7 @@ protected function callScssFunction($name, $argValues, &$returnValue) $this->popEnv(); - $returnValue = ! isset($ret) ? self::$defaultValue : $ret; + $returnValue = ! isset($ret) ? static::$defaultValue : $ret; return true; } @@ -3563,7 +3563,7 @@ protected function callNativeFunction($name, $args, &$returnValue) list($f, $prototype) = $this->userFunctions[$name]; } elseif (($f = $this->getBuiltinFunction($name)) && is_callable($f)) { $libName = $f[1]; - $prototype = isset(self::$$libName) ? self::$$libName : null; + $prototype = isset(static::$$libName) ? static::$$libName : null; } else { return false; } @@ -3788,7 +3788,7 @@ private function coerceValue($value) } if ($value === null) { - return self::$null; + return static::$null; } if (is_numeric($value)) { @@ -3796,7 +3796,7 @@ private function coerceValue($value) } if ($value === '') { - return self::$emptyString; + return static::$emptyString; } if (preg_match('/^(#([0-9a-f]{6})|#([0-9a-f]{3}))$/i', $value, $m)) { @@ -3838,11 +3838,11 @@ protected function coerceMap($item) return $item; } - if ($item === self::$emptyList) { - return self::$emptyMap; + if ($item === static::$emptyList) { + return static::$emptyMap; } - return [Type::T_MAP, [$item], [self::$null]]; + return [Type::T_MAP, [$item], [static::$null]]; } /** @@ -4212,7 +4212,7 @@ protected function libIndex($args) list($list, $value) = $args; if ($value[0] === Type::T_MAP) { - return self::$null; + return static::$null; } if ($list[0] === Type::T_MAP || @@ -4224,7 +4224,7 @@ protected function libIndex($args) } if ($list[0] !== Type::T_LIST) { - return self::$null; + return static::$null; } $values = []; @@ -4235,7 +4235,7 @@ protected function libIndex($args) $key = array_search($this->normalizeValue($value), $values); - return false === $key ? self::$null : $key + 1; + return false === $key ? static::$null : $key + 1; } protected static $libRgb = ['red', 'green', 'blue']; @@ -4805,7 +4805,7 @@ protected function libNth($args) $n += count($list[2]); } - return isset($list[2][$n]) ? $list[2][$n] : self::$defaultValue; + return isset($list[2][$n]) ? $list[2][$n] : static::$defaultValue; } protected static $libSetNth = ['list', 'n', 'value']; @@ -4843,7 +4843,7 @@ protected function libMapGet($args) } } - return self::$null; + return static::$null; } protected static $libMapKeys = ['map']; @@ -4994,7 +4994,7 @@ protected function libTypeOf($args) switch ($value[0]) { case Type::T_KEYWORD: - if ($value === self::$true || $value === self::$false) { + if ($value === static::$true || $value === static::$false) { return 'bool'; } @@ -5067,7 +5067,7 @@ protected function libStrIndex($args) $result = strpos($stringContent, $substringContent); - return $result === false ? self::$null : new Node\Number($result + 1, ''); + return $result === false ? static::$null : new Node\Number($result + 1, ''); } protected static $libStrInsert = ['string', 'insert', 'index']; @@ -5099,7 +5099,7 @@ protected function libStrLength($args) protected function libStrSlice($args) { if (isset($args[2]) && $args[2][1] == 0) { - return self::$nullString; + return static::$nullString; } $string = $this->coerceString($args[0]); @@ -5161,7 +5161,7 @@ protected function libFunctionExists($args) $name = $this->compileStringContent($string); // user defined functions - if ($this->has(self::$namespaces['function'] . $name)) { + if ($this->has(static::$namespaces['function'] . $name)) { return true; } @@ -5192,7 +5192,7 @@ protected function libMixinExists($args) $string = $this->coerceString($args[0]); $name = $this->compileStringContent($string); - return $this->has(self::$namespaces['mixin'] . $name); + return $this->has(static::$namespaces['mixin'] . $name); } protected static $libVariableExists = ['name']; @@ -5250,7 +5250,7 @@ protected function libUniqueId() protected static $libInspect = ['value']; protected function libInspect($args) { - if ($args[0] === self::$null) { + if ($args[0] === static::$null) { return [Type::T_KEYWORD, 'null']; } diff --git a/src/Node/Number.php b/src/Node/Number.php index a803a6ca..55fec292 100644 --- a/src/Node/Number.php +++ b/src/Node/Number.php @@ -110,7 +110,7 @@ public function coerce($units) $dimension = $this->dimension; - foreach (self::$unitTable['in'] as $unit => $conv) { + 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); @@ -265,7 +265,7 @@ public function unitStr() */ public function output(Compiler $compiler = null) { - $dimension = round($this->dimension, self::$precision); + $dimension = round($this->dimension, static::$precision); $units = array_filter($this->units, function ($unitSize) { return $unitSize; @@ -277,7 +277,7 @@ public function output(Compiler $compiler = null) $this->normalizeUnits($dimension, $units, 'in'); - $dimension = round($dimension, self::$precision); + $dimension = round($dimension, static::$precision); $units = array_filter($units, function ($unitSize) { return $unitSize; }); @@ -316,8 +316,8 @@ private function normalizeUnits(&$dimension, &$units, $baseUnit = 'in') $units = []; foreach ($this->units as $unit => $exp) { - if (isset(self::$unitTable[$baseUnit][$unit])) { - $factor = pow(self::$unitTable[$baseUnit][$unit], $exp); + if (isset(static::$unitTable[$baseUnit][$unit])) { + $factor = pow(static::$unitTable[$baseUnit][$unit], $exp); $unit = $baseUnit; $dimension /= $factor; diff --git a/src/Parser.php b/src/Parser.php index ed0621ea..9f28a591 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -83,17 +83,17 @@ public function __construct($sourceName, $sourceIndex = 0, $encoding = 'utf-8') $this->utf8 = ! $encoding || strtolower($encoding) === 'utf-8'; $this->patternModifiers = $this->utf8 ? 'Aisu' : 'Ais'; - if (empty(self::$operatorPattern)) { - self::$operatorPattern = '([*\/%+-]|[!=]\=|\>\=?|\<\=\>|\<\=?|and|or)'; + if (empty(static::$operatorPattern)) { + static::$operatorPattern = '([*\/%+-]|[!=]\=|\>\=?|\<\=\>|\<\=?|and|or)'; $commentSingle = '\/\/'; $commentMultiLeft = '\/\*'; $commentMultiRight = '\*\/'; - self::$commentPattern = $commentMultiLeft . '.*?' . $commentMultiRight; - self::$whitePattern = $this->utf8 - ? '/' . $commentSingle . '[^\n]*\s*|(' . self::$commentPattern . ')\s*|\s+/AisuS' - : '/' . $commentSingle . '[^\n]*\s*|(' . self::$commentPattern . ')\s*|\s+/AisS'; + static::$commentPattern = $commentMultiLeft . '.*?' . $commentMultiRight; + static::$whitePattern = $this->utf8 + ? '/' . $commentSingle . '[^\n]*\s*|(' . static::$commentPattern . ')\s*|\s+/AisuS' + : '/' . $commentSingle . '[^\n]*\s*|(' . static::$commentPattern . ')\s*|\s+/AisS'; } } @@ -563,9 +563,9 @@ protected function parseChunk() list($line, $column) = $this->getSourcePosition($s); - $statement[self::SOURCE_LINE] = $line; - $statement[self::SOURCE_COLUMN] = $column; - $statement[self::SOURCE_INDEX] = $this->sourceIndex; + $statement[static::SOURCE_LINE] = $line; + $statement[static::SOURCE_COLUMN] = $column; + $statement[static::SOURCE_INDEX] = $this->sourceIndex; $this->charset = $statement; } @@ -922,7 +922,7 @@ protected function whitespace() { $gotWhite = false; - while (preg_match(self::$whitePattern, $this->buffer, $m, null, $this->count)) { + while (preg_match(static::$whitePattern, $this->buffer, $m, null, $this->count)) { if (isset($m[1]) && empty($this->commentsSeen[$this->count])) { $this->appendComment([Type::T_COMMENT, $m[1]]); @@ -959,9 +959,9 @@ protected function append($statement, $pos = null) if ($pos !== null) { list($line, $column) = $this->getSourcePosition($pos); - $statement[self::SOURCE_LINE] = $line; - $statement[self::SOURCE_COLUMN] = $column; - $statement[self::SOURCE_INDEX] = $this->sourceIndex; + $statement[static::SOURCE_LINE] = $line; + $statement[static::SOURCE_COLUMN] = $column; + $statement[static::SOURCE_INDEX] = $this->sourceIndex; } $this->env->children[] = $statement; @@ -1249,13 +1249,13 @@ protected function expression(&$out) */ protected function expHelper($lhs, $minP) { - $operators = self::$operatorPattern; + $operators = static::$operatorPattern; $ss = $this->seek(); $whiteBefore = isset($this->buffer[$this->count - 1]) && ctype_space($this->buffer[$this->count - 1]); - while ($this->match($operators, $m, false) && self::$precedence[$m[1]] >= $minP) { + while ($this->match($operators, $m, false) && static::$precedence[$m[1]] >= $minP) { $whiteAfter = isset($this->buffer[$this->count]) && ctype_space($this->buffer[$this->count]); $varAfter = isset($this->buffer[$this->count]) && @@ -1275,8 +1275,8 @@ protected function expHelper($lhs, $minP) } // peek and see if rhs belongs to next operator - if ($this->peek($operators, $next) && self::$precedence[$next[1]] > self::$precedence[$op]) { - $rhs = $this->expHelper($rhs, self::$precedence[$next[1]]); + if ($this->peek($operators, $next) && static::$precedence[$next[1]] > static::$precedence[$op]) { + $rhs = $this->expHelper($rhs, static::$precedence[$next[1]]); } $lhs = [Type::T_EXPRESSION, $op, $lhs, $rhs, $this->inParens, $whiteBefore, $whiteAfter]; @@ -1812,7 +1812,7 @@ protected function openString($end, &$out, $nestingOpen = null) $oldWhite = $this->eatWhiteDefault; $this->eatWhiteDefault = false; - $patt = '(.*?)([\'"]|#\{|' . $this->pregQuote($end) . '|' . self::$commentPattern . ')'; + $patt = '(.*?)([\'"]|#\{|' . $this->pregQuote($end) . '|' . static::$commentPattern . ')'; $nestingLevel = 0; @@ -1946,7 +1946,7 @@ protected function propertyName(&$out) // match comment hack if (preg_match( - self::$whitePattern, + static::$whitePattern, $this->buffer, $m, null, diff --git a/src/Server.php b/src/Server.php index 221655ca..33d7b3de 100644 --- a/src/Server.php +++ b/src/Server.php @@ -457,7 +457,7 @@ public function __construct($dir, $cacheDir = null, $scss = null) */ public static function serveFrom($path) { - $server = new self($path); + $server = new static($path); $server->serve(); } } From bacbd7a0c03fa8af6bdba4fff41ffc13625608fa Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Thu, 5 Jan 2017 12:56:38 -0500 Subject: [PATCH 067/329] fixes #484 --- src/Compiler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compiler.php b/src/Compiler.php index df322273..10fee440 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -3496,7 +3496,7 @@ protected function handleImportLoop($name) */ protected function fileExists($name) { - return is_file($name); + return file_exists($name) && is_file($name); } /** From fe7e36b4250c916bf7e94f1e0ec8384fef75d617 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Thu, 5 Jan 2017 13:02:45 -0500 Subject: [PATCH 068/329] fixes #485 throw RangeException --- src/Exception/RangeException.php | 21 +++++++++++++++++++++ src/Util.php | 5 +++-- 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 src/Exception/RangeException.php diff --git a/src/Exception/RangeException.php b/src/Exception/RangeException.php new file mode 100644 index 00000000..22f46f54 --- /dev/null +++ b/src/Exception/RangeException.php @@ -0,0 +1,21 @@ + + */ +class RangeException extends \Exception +{ +} diff --git a/src/Util.php b/src/Util.php index 9f47c1d7..9e968d8a 100644 --- a/src/Util.php +++ b/src/Util.php @@ -12,6 +12,7 @@ namespace Leafo\ScssPhp; use Leafo\ScssPhp\Base\Range; +use Leafo\ScssPhp\Exception\RangeException; /** * Utilties @@ -31,7 +32,7 @@ class Util * * @return mixed `value` adjusted to fall within range, if it was outside by a floating-point margin. * - * @throws \Exception + * @throws \Leafo\ScssPhp\Exception\RangeException */ public static function checkRange($name, Range $range, $value, $unit = '') { @@ -50,6 +51,6 @@ public static function checkRange($name, Range $range, $value, $unit = '') return $range->last; } - throw new \Exception("$name {$val} must be between {$range->first} and {$range->last}$unit"); + throw new RangeException("$name {$val} must be between {$range->first} and {$range->last}$unit"); } } From e7aa77e74f31ab51dd72d95b40b6b5fc2ef46b9f Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Thu, 5 Jan 2017 13:05:38 -0500 Subject: [PATCH 069/329] Bump copyright year --- src/Base/Range.php | 2 +- src/Block.php | 2 +- src/Colors.php | 2 +- src/Compiler.php | 2 +- src/Compiler/Environment.php | 2 +- src/Exception/CompilerException.php | 2 +- src/Exception/ParserException.php | 2 +- src/Exception/RangeException.php | 2 +- src/Exception/ServerException.php | 2 +- src/Formatter.php | 2 +- src/Formatter/Compact.php | 2 +- src/Formatter/Compressed.php | 2 +- src/Formatter/Crunched.php | 2 +- src/Formatter/Debug.php | 2 +- src/Formatter/Expanded.php | 2 +- src/Formatter/Nested.php | 2 +- src/Formatter/OutputBlock.php | 2 +- src/Node.php | 2 +- src/Node/Number.php | 2 +- src/Parser.php | 2 +- src/Server.php | 2 +- src/Type.php | 2 +- src/Util.php | 2 +- src/Version.php | 2 +- 24 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/Base/Range.php b/src/Base/Range.php index a591d7b0..3f3a067d 100644 --- a/src/Base/Range.php +++ b/src/Base/Range.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2015 Leaf Corcoran + * @copyright 2017 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Block.php b/src/Block.php index 6b972a1b..a6b5f3f0 100644 --- a/src/Block.php +++ b/src/Block.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2015 Leaf Corcoran + * @copyright 2012-2017 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Colors.php b/src/Colors.php index ff48c199..61a71ab6 100644 --- a/src/Colors.php +++ b/src/Colors.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2015 Leaf Corcoran + * @copyright 2012-2017 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Compiler.php b/src/Compiler.php index 10fee440..36a0f7cc 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2015 Leaf Corcoran + * @copyright 2012-2017 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Compiler/Environment.php b/src/Compiler/Environment.php index d44bff76..b4b86e32 100644 --- a/src/Compiler/Environment.php +++ b/src/Compiler/Environment.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2015 Leaf Corcoran + * @copyright 2012-2017 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Exception/CompilerException.php b/src/Exception/CompilerException.php index 777e40ac..45fc1671 100644 --- a/src/Exception/CompilerException.php +++ b/src/Exception/CompilerException.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2015 Leaf Corcoran + * @copyright 2012-2017 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Exception/ParserException.php b/src/Exception/ParserException.php index fbe6388f..c0ee002d 100644 --- a/src/Exception/ParserException.php +++ b/src/Exception/ParserException.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2015 Leaf Corcoran + * @copyright 2012-2017 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Exception/RangeException.php b/src/Exception/RangeException.php index 22f46f54..47192ff5 100644 --- a/src/Exception/RangeException.php +++ b/src/Exception/RangeException.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2015 Leaf Corcoran + * @copyright 2012-2017 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Exception/ServerException.php b/src/Exception/ServerException.php index 5a878d2f..68d3a290 100644 --- a/src/Exception/ServerException.php +++ b/src/Exception/ServerException.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2015 Leaf Corcoran + * @copyright 2012-2017 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Formatter.php b/src/Formatter.php index 2770bb2d..0d2635f1 100644 --- a/src/Formatter.php +++ b/src/Formatter.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2015 Leaf Corcoran + * @copyright 2012-2017 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Formatter/Compact.php b/src/Formatter/Compact.php index 94abe329..aaf972b7 100644 --- a/src/Formatter/Compact.php +++ b/src/Formatter/Compact.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2015 Leaf Corcoran + * @copyright 2012-2017 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Formatter/Compressed.php b/src/Formatter/Compressed.php index df7bc75f..17aca54a 100644 --- a/src/Formatter/Compressed.php +++ b/src/Formatter/Compressed.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2015 Leaf Corcoran + * @copyright 2012-2017 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Formatter/Crunched.php b/src/Formatter/Crunched.php index ccba1333..0a89bc48 100644 --- a/src/Formatter/Crunched.php +++ b/src/Formatter/Crunched.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2015 Leaf Corcoran + * @copyright 2012-2017 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Formatter/Debug.php b/src/Formatter/Debug.php index 855742e7..321c5368 100644 --- a/src/Formatter/Debug.php +++ b/src/Formatter/Debug.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2015 Leaf Corcoran + * @copyright 2012-2017 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Formatter/Expanded.php b/src/Formatter/Expanded.php index 54db742f..dff17e6b 100644 --- a/src/Formatter/Expanded.php +++ b/src/Formatter/Expanded.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2015 Leaf Corcoran + * @copyright 2012-2017 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Formatter/Nested.php b/src/Formatter/Nested.php index 9fdb4dd0..c4ff803c 100644 --- a/src/Formatter/Nested.php +++ b/src/Formatter/Nested.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2015 Leaf Corcoran + * @copyright 2012-2017 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Formatter/OutputBlock.php b/src/Formatter/OutputBlock.php index bb8d99b4..88e86402 100644 --- a/src/Formatter/OutputBlock.php +++ b/src/Formatter/OutputBlock.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2015 Leaf Corcoran + * @copyright 2012-2017 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Node.php b/src/Node.php index e6ed178c..eb543c73 100644 --- a/src/Node.php +++ b/src/Node.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2015 Leaf Corcoran + * @copyright 2012-2017 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Node/Number.php b/src/Node/Number.php index 55fec292..d4f406fa 100644 --- a/src/Node/Number.php +++ b/src/Node/Number.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2015 Leaf Corcoran + * @copyright 2012-2017 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Parser.php b/src/Parser.php index 9f28a591..619b7ba8 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2015 Leaf Corcoran + * @copyright 2012-2017 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Server.php b/src/Server.php index 33d7b3de..e4caddb4 100644 --- a/src/Server.php +++ b/src/Server.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2015 Leaf Corcoran + * @copyright 2012-2017 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Type.php b/src/Type.php index 8c3886c8..2d659e4d 100644 --- a/src/Type.php +++ b/src/Type.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2015 Leaf Corcoran + * @copyright 2012-2017 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Util.php b/src/Util.php index 9e968d8a..b2a05db8 100644 --- a/src/Util.php +++ b/src/Util.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2015 Leaf Corcoran + * @copyright 2012-2017 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Version.php b/src/Version.php index 80cdeee5..dff3bd5b 100644 --- a/src/Version.php +++ b/src/Version.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2015 Leaf Corcoran + * @copyright 2012-2017 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * From d395f6f914e77031bbb822d55bc802e85441056e Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Tue, 10 Jan 2017 11:45:37 -0500 Subject: [PATCH 070/329] @import - implicit .scss extension when not specified; otherwise limit to explicit .css and .scss extension; mitigates #487 --- src/Compiler.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Compiler.php b/src/Compiler.php index 36a0f7cc..68003b90 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -3390,6 +3390,8 @@ public function findImport($url) $urls = [$url, preg_replace('/[^\/]+$/', '_\0', $url)]; } + $hasExtension = preg_match('/[.]s?css$/', $url); + foreach ($this->importPaths as $dir) { if (is_string($dir)) { // check urls for normal import paths @@ -3399,7 +3401,7 @@ public function findImport($url) . $full; if ($this->fileExists($file = $full . '.scss') || - $this->fileExists($file = $full) + ($hasExtension && $this->fileExists($file = $full)) ) { return $file; } From 562213cd803e42ea53b0735554794c4022d8db89 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Thu, 23 Feb 2017 00:07:33 -0500 Subject: [PATCH 071/329] Bump version --- src/Version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Version.php b/src/Version.php index dff3bd5b..2d6eabc1 100644 --- a/src/Version.php +++ b/src/Version.php @@ -18,5 +18,5 @@ */ class Version { - const VERSION = 'v0.6.6'; + const VERSION = 'v0.6.7'; } From ad205b8b7cdb066283a7cd2fd4b66fe55131cdef Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Thu, 23 Feb 2017 00:32:54 -0500 Subject: [PATCH 072/329] Server::serveFrom() removed --- src/Server.php | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/Server.php b/src/Server.php index e4caddb4..c3fa985d 100644 --- a/src/Server.php +++ b/src/Server.php @@ -449,15 +449,4 @@ public function __construct($dir, $cacheDir = null, $scss = null) date_default_timezone_set('UTC'); } } - - /** - * Helper method to serve compiled scss - * - * @param string $path Root path - */ - public static function serveFrom($path) - { - $server = new static($path); - $server->serve(); - } } From 3dc8ecfbf4900f2cc7b740ab98c8244d232a03d6 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Thu, 23 Feb 2017 00:59:07 -0500 Subject: [PATCH 073/329] Update .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index e5b70fb7..1a28f1ea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ php: - 5.5 - 5.6 - 7.0 + - 7.1 - nightly script: From d2cfeb60986784c7c09257486b00f35c49b8c99c Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Thu, 23 Feb 2017 01:05:26 -0500 Subject: [PATCH 074/329] Update travis.yml Disable php nightly (7.2) - broken build --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1a28f1ea..25e06b3e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ php: - 5.6 - 7.0 - 7.1 - - nightly +# - nightly script: - phpunit tests From b5db19b0dd98807279cea399917b38487ed4e8ba Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Fri, 24 Feb 2017 20:55:56 -0500 Subject: [PATCH 075/329] Add test for user function that returns null --- tests/ApiTest.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/ApiTest.php b/tests/ApiTest.php index 8d89b588..f39e7f62 100644 --- a/tests/ApiTest.php +++ b/tests/ApiTest.php @@ -38,6 +38,18 @@ public function testUserFunction() ); } + public function testUserFunctionNull() + { + $this->scss->registerFunction('get-null', function ($args) { + return Compiler::$null; + }); + + $this->assertEquals( + '', + $this->compile('result: get-null();') + ); + } + public function testUserFunctionKwargs() { $this->scss->registerFunction( From df07dde450669bc04081a7afb3ee68b8429c37fd Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Tue, 14 Mar 2017 07:04:41 -0400 Subject: [PATCH 076/329] Fix travis ci tests? --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 25e06b3e..df8c6adc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,10 +7,10 @@ php: - 5.6 - 7.0 - 7.1 -# - nightly + - nightly script: - - phpunit tests + - vendor/bin/phpunit tests branches: only: From 2b7ed3384a66ac5a69846c3d2e0eb204fb6cef34 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Tue, 14 Mar 2017 07:10:22 -0400 Subject: [PATCH 077/329] Travis: run composer install --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index df8c6adc..e0e9a57f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ php: - nightly script: + - composer install - vendor/bin/phpunit tests branches: From 3814a55a4efe56ac33eb586b97845a8e88093225 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Tue, 14 Mar 2017 08:28:16 -0400 Subject: [PATCH 078/329] fixes #505 - remove .phar build --- .gitignore | 2 +- Makefile | 3 --- box.json.dist | 12 ------------ composer.json | 4 +--- 4 files changed, 2 insertions(+), 19 deletions(-) delete mode 100644 box.json.dist diff --git a/.gitignore b/.gitignore index dbff826d..be6e5ecf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ .sass-cache +scss_cache composer.lock -pscss.phar /*.css /*.scss /_site/ diff --git a/Makefile b/Makefile index b42e4a2b..5115941c 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,3 @@ compat: standard: vendor/bin/phpcs --standard=PSR2 bin src tests *.php - -phar: - php -dphar.readonly=0 vendor/bin/box build -v diff --git a/box.json.dist b/box.json.dist deleted file mode 100644 index 63d13baf..00000000 --- a/box.json.dist +++ /dev/null @@ -1,12 +0,0 @@ -{ - "chmod": "0755", - "files": [ - "LICENSE.md", - "scss.inc.php" - ], - "directories": ["src"], - "main": "bin/pscss", - "output": "pscss.phar", - "compactors": "Herrera\\Box\\Compactor\\Php", - "stub": true -} diff --git a/composer.json b/composer.json index 112a6bde..95118a32 100644 --- a/composer.json +++ b/composer.json @@ -25,8 +25,7 @@ }, "require-dev": { "squizlabs/php_codesniffer": "~2.5", - "phpunit/phpunit": "~3.7", - "kherge/box": "~2.5" + "phpunit/phpunit": "~4.6" }, "bin": ["bin/pscss"], "archive": { @@ -35,7 +34,6 @@ "/.gitattributes", "/.gitignore", "/.travis.yml", - "/box.json.dist", "/phpunit.xml.dist", "/tests" ] From b6f1ea6baac258aacc3e44cd48df9b4b0dd95ef2 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Tue, 14 Mar 2017 09:04:34 -0400 Subject: [PATCH 079/329] Move Server class to example/ folder --- {src => example}/Server.php | 4 ++-- scss.inc.php | 1 - tests/ServerTest.php | 3 ++- 3 files changed, 4 insertions(+), 4 deletions(-) rename {src => example}/Server.php (98%) diff --git a/src/Server.php b/example/Server.php similarity index 98% rename from src/Server.php rename to example/Server.php index c3fa985d..8dc3c7b2 100644 --- a/src/Server.php +++ b/example/Server.php @@ -434,7 +434,7 @@ public function __construct($dir, $cacheDir = null, $scss = null) $this->cacheDir = $cacheDir; if (! is_dir($this->cacheDir)) { - mkdir($this->cacheDir, 0755, true); + throw new ServerException('Cache directory doesn\'t exist: ' . $cacheDir); } if (! isset($scss)) { @@ -446,7 +446,7 @@ public function __construct($dir, $cacheDir = null, $scss = null) $this->showErrorsAsCSS = false; if (! ini_get('date.timezone')) { - date_default_timezone_set('UTC'); + throw new ServerException('Default date.timezone not set'); } } } diff --git a/scss.inc.php b/scss.inc.php index b6892fec..d2ec2639 100644 --- a/scss.inc.php +++ b/scss.inc.php @@ -26,5 +26,4 @@ include_once __DIR__ . '/src/Type.php'; include_once __DIR__ . '/src/Util.php'; include_once __DIR__ . '/src/Version.php'; - include_once __DIR__ . '/src/Server.php'; } diff --git a/tests/ServerTest.php b/tests/ServerTest.php index 2cecdd97..7c7ef6a9 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -8,9 +8,10 @@ * * @link http://leafo.github.io/scssphp */ - namespace Leafo\ScssPhp\Tests; +require_once __DIR__ . '/../example/Server.php'; + use Leafo\ScssPhp\Server; /** From 53e86eae35448fbcce8f682ffcb9fa224cd40cc3 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Tue, 14 Mar 2017 10:58:24 -0400 Subject: [PATCH 080/329] Fix failing ServerTest --- tests/ServerTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/ServerTest.php b/tests/ServerTest.php index 7c7ef6a9..fcaea917 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -23,6 +23,10 @@ class ServerTest extends \PHPUnit_Framework_TestCase { public function testCheckedCachedCompile() { + if (! file_exists(__DIR__ . '/inputs/scss_cache')) { + mkdir(__DIR__ . '/inputs/scss_cache', 0755); + } + $server = new Server(__DIR__ . '/inputs/'); $css = $server->checkedCachedCompile(__DIR__ . '/inputs/import.scss', '/tmp/scss.css'); From 942c61055d53a893f79a7d34261d609b618a1ced Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Tue, 22 Aug 2017 07:20:58 -0400 Subject: [PATCH 081/329] Update scss.inc.php --- scss.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scss.inc.php b/scss.inc.php index d2ec2639..83d23a6b 100644 --- a/scss.inc.php +++ b/scss.inc.php @@ -3,7 +3,7 @@ throw new \Exception('scssphp requires PHP 5.4 or above'); } -if (! class_exists('scssc', false)) { +if (! class_exists('Leafo\ScssPhp\Version', false)) { include_once __DIR__ . '/src/Base/Range.php'; include_once __DIR__ . '/src/Block.php'; include_once __DIR__ . '/src/Colors.php'; From 494c09f0c08261265ddca4ca51c51670e01680c4 Mon Sep 17 00:00:00 2001 From: Marina Glancy Date: Fri, 29 Sep 2017 16:00:39 +0800 Subject: [PATCH 082/329] fixes #532 Substitute deprecated php function each() --- src/Node/Number.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Node/Number.php b/src/Node/Number.php index d4f406fa..442d57d5 100644 --- a/src/Node/Number.php +++ b/src/Node/Number.php @@ -290,7 +290,7 @@ public function output(Compiler $compiler = null) } reset($units); - list($unit, ) = each($units); + $unit = key($units); return (string) $dimension . $unit; } From 9eaf3a6db4d88ce2c265a89e3fc495fbec9bf7a6 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Fri, 13 Oct 2017 11:52:30 -0400 Subject: [PATCH 083/329] Bump to version 0.7.0 --- src/Version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Version.php b/src/Version.php index 2d6eabc1..dd7cd384 100644 --- a/src/Version.php +++ b/src/Version.php @@ -18,5 +18,5 @@ */ class Version { - const VERSION = 'v0.6.7'; + const VERSION = 'v0.7.0'; } From f79f49b9aebf7c1885a27f1152f2d58d1ba4b05a Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Fri, 13 Oct 2017 12:06:15 -0400 Subject: [PATCH 084/329] Workaround PHP 7.2 code sniff --- src/Parser.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Parser.php b/src/Parser.php index 619b7ba8..44043e65 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -2468,7 +2468,13 @@ private function getSourcePosition($pos) */ private function saveEncoding() { - if (ini_get('mbstring.func_overload') & 2) { + if (version_compare(PHP_VERSION, '7.2.0') >= 0) { + return; + } + + $iniDirective = 'mbstring' . '.func_overload'; // deprecated in PHP 7.2 + + if (ini_get($iniDirective) & 2) { $this->encoding = mb_internal_encoding(); mb_internal_encoding('iso-8859-1'); From 192f9b29d41ba0e2c610c2343da61bdde28f6436 Mon Sep 17 00:00:00 2001 From: Thomas Eiling Date: Fri, 13 Oct 2017 12:48:50 -0400 Subject: [PATCH 085/329] misc - fix some phpdoc comments and code styles --- src/Compiler.php | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index 68003b90..89119933 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -1181,7 +1181,7 @@ protected function flattenSelectorSingle($single) /** * Compile selector to string; self(&) should have been replaced by now * - * @param array $selector + * @param string|array $selector * * @return string */ @@ -1203,7 +1203,7 @@ protected function compileSelector($selector) /** * Compile selector part * - * @param arary $piece + * @param array $piece * * @return string */ @@ -1963,7 +1963,7 @@ protected function shouldEval($value) * @param array $value * @param boolean $inExp * - * @return array + * @return array|\Leafo\ScssPhp\Node\Number */ protected function reduce($value, $inExp = false) { @@ -2238,7 +2238,7 @@ public function normalizeValue($value) * @param array $left * @param array $right * - * @return array + * @return \Leafo\ScssPhp\Node\Number */ protected function opAddNumberNumber($left, $right) { @@ -2251,7 +2251,7 @@ protected function opAddNumberNumber($left, $right) * @param array $left * @param array $right * - * @return array + * @return \Leafo\ScssPhp\Node\Number */ protected function opMulNumberNumber($left, $right) { @@ -2264,7 +2264,7 @@ protected function opMulNumberNumber($left, $right) * @param array $left * @param array $right * - * @return array + * @return \Leafo\ScssPhp\Node\Number */ protected function opSubNumberNumber($left, $right) { @@ -2277,7 +2277,7 @@ protected function opSubNumberNumber($left, $right) * @param array $left * @param array $right * - * @return array + * @return array|\Leafo\ScssPhp\Node\Number */ protected function opDivNumberNumber($left, $right) { @@ -2294,7 +2294,7 @@ protected function opDivNumberNumber($left, $right) * @param array $left * @param array $right * - * @return array + * @return \Leafo\ScssPhp\Node\Number */ protected function opModNumberNumber($left, $right) { @@ -2580,7 +2580,7 @@ protected function opLtNumberNumber($left, $right) * @param array $left * @param array $right * - * @return array + * @return \Leafo\ScssPhp\Node\Number */ protected function opCmpNumberNumber($left, $right) { @@ -3505,7 +3505,7 @@ protected function fileExists($name) * Call SCSS @function * * @param string $name - * @param array $args + * @param array $argValues * @param array $returnValue * * @return boolean Returns true if returnValue is set; otherwise, false @@ -3777,7 +3777,7 @@ protected function applyArguments($argDef, $argValues) * * @param mixed $value * - * @return array + * @return array|\Leafo\ScssPhp\Node\Number */ private function coerceValue($value) { @@ -3850,7 +3850,8 @@ protected function coerceMap($item) /** * Coerce something to list * - * @param array $item + * @param array $item + * @param string $delim * * @return array */ @@ -5210,6 +5211,8 @@ protected function libVariableExists($args) * Workaround IE7's content counter bug. * * @param array $args + * + * @return array */ protected function libCounter($args) { From b413ff279f5f0ba5938e1315a8068a06643c9443 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Fri, 13 Oct 2017 13:29:38 -0400 Subject: [PATCH 086/329] Change default precision to 10 (introduced in sass 3.5.0) --- bin/pscss | 2 +- src/Node/Number.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/pscss b/bin/pscss index 4ec061b8..70a2be3c 100755 --- a/bin/pscss +++ b/bin/pscss @@ -76,7 +76,7 @@ Options include: -i=path Set import path --iso8859-1 Use iso8859-1 encoding instead of utf-8 (default utf-8) --line-numbers Annotate selectors with comments referring to the source file and line number - -p=precision Set decimal number precision (default 5) + -p=precision Set decimal number precision (default 10) -T Dump formatted parse tree -v, --version Print the version diff --git a/src/Node/Number.php b/src/Node/Number.php index 442d57d5..5faedfdf 100644 --- a/src/Node/Number.php +++ b/src/Node/Number.php @@ -31,7 +31,7 @@ class Number extends Node implements \ArrayAccess /** * @var integer */ - static public $precision = 5; + static public $precision = 10; /** * @see http://www.w3.org/TR/2012/WD-css3-values-20120308/ From 75c9fb79ae362a84e89736c2812fc022332e0f5a Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Sat, 14 Oct 2017 13:29:08 -0400 Subject: [PATCH 087/329] Remove setlocale() to mitigate Windows side-effects --- src/Compiler.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index 89119933..0d67c525 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -165,9 +165,6 @@ public function __construct() */ public function compile($code, $path = null) { - $locale = setlocale(LC_NUMERIC, 0); - setlocale(LC_NUMERIC, 'C'); - $this->indentLevel = -1; $this->commentsSeen = []; $this->extends = []; @@ -196,8 +193,6 @@ public function compile($code, $path = null) $out = $this->formatter->format($this->scope); - setlocale(LC_NUMERIC, $locale); - return $out; } From 9b3c1ff4eab71cdda612646fc94cfba0de9b6672 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Sat, 14 Oct 2017 13:33:24 -0400 Subject: [PATCH 088/329] Use number_format to output locale-independent floats --- src/Node/Number.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Node/Number.php b/src/Node/Number.php index 5faedfdf..df1b79cc 100644 --- a/src/Node/Number.php +++ b/src/Node/Number.php @@ -292,7 +292,7 @@ public function output(Compiler $compiler = null) reset($units); $unit = key($units); - return (string) $dimension . $unit; + return preg_replace('/[.]0*$/', '', number_format($dimension, static::$precision)) . $unit; } /** From 3cbdd6330958420b949fd19ef24472edfd3ee517 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Sat, 14 Oct 2017 14:31:52 -0400 Subject: [PATCH 089/329] Trim trailing zeros --- src/Node/Number.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Node/Number.php b/src/Node/Number.php index df1b79cc..59eb811a 100644 --- a/src/Node/Number.php +++ b/src/Node/Number.php @@ -291,8 +291,9 @@ public function output(Compiler $compiler = null) reset($units); $unit = key($units); - - return preg_replace('/[.]0*$/', '', number_format($dimension, static::$precision)) . $unit; + $dimension = number_format($dimension, static::$precision, '.', ''); + + return (static::$precision ? rtrim($dimension, '0') : $dimension) . $unit; } /** From db5273cd3a33cc0fb1b1fbba85dbb00deb61446b Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Sat, 14 Oct 2017 14:35:20 -0400 Subject: [PATCH 090/329] Trim trailing decimal point. --- src/Node/Number.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Node/Number.php b/src/Node/Number.php index 59eb811a..acfdaf29 100644 --- a/src/Node/Number.php +++ b/src/Node/Number.php @@ -293,7 +293,7 @@ public function output(Compiler $compiler = null) $unit = key($units); $dimension = number_format($dimension, static::$precision, '.', ''); - return (static::$precision ? rtrim($dimension, '0') : $dimension) . $unit; + return (static::$precision ? rtrim($dimension, '.0') : $dimension) . $unit; } /** From c0ec63ff8eaff626ddeee1245b9119c82990c0ff Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Sat, 14 Oct 2017 14:40:55 -0400 Subject: [PATCH 091/329] Fix previous edit from my phone. =P --- src/Node/Number.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Node/Number.php b/src/Node/Number.php index acfdaf29..3dcdd2ca 100644 --- a/src/Node/Number.php +++ b/src/Node/Number.php @@ -293,7 +293,7 @@ public function output(Compiler $compiler = null) $unit = key($units); $dimension = number_format($dimension, static::$precision, '.', ''); - return (static::$precision ? rtrim($dimension, '.0') : $dimension) . $unit; + return (static::$precision ? rtrim(rtrim($dimension, '0'), '.') : $dimension) . $unit; } /** From f735beeb2b8926f4d361d2c51bbefbc5271fbdfc Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Sat, 14 Oct 2017 14:46:23 -0400 Subject: [PATCH 092/329] Fix unit test (1/2) --- tests/outputs/operators.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/outputs/operators.css b/tests/outputs/operators.css index fb492c82..50aaa8c0 100644 --- a/tests/outputs/operators.css +++ b/tests/outputs/operators.css @@ -6,7 +6,7 @@ body { color: 5px; top: 1.5em; left: -1cm; - top: 6.29921; } + top: 6.2992125984; } div { color: false; @@ -19,7 +19,7 @@ div { color: 1; } #units { - test: 2.5748in; + test: 2.5748031496in; test: 13mm; test: 4em; test: 11mm; @@ -169,7 +169,7 @@ div { margin: 0 -2em; } div { - *margin-left: 2.07447%; } + *margin-left: 2.0744680851%; } .foo { width: 12.5%; } From 69cb0ca734665c9a9ea41dd3e3d6f7a65dfdd93d Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Sat, 14 Oct 2017 14:48:01 -0400 Subject: [PATCH 093/329] Fix unit test (2/2) --- tests/outputs_numbered/operators.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/outputs_numbered/operators.css b/tests/outputs_numbered/operators.css index c3ea3d1d..ad4d678e 100644 --- a/tests/outputs_numbered/operators.css +++ b/tests/outputs_numbered/operators.css @@ -7,7 +7,7 @@ body { color: 5px; top: 1.5em; left: -1cm; - top: 6.29921; } + top: 6.2992125984; } /* line 15, inputs/operators.scss */ div { color: false; @@ -20,7 +20,7 @@ div { color: 1; } /* line 29, inputs/operators.scss */ #units { - test: 2.5748in; + test: 2.5748031496in; test: 13mm; test: 4em; test: 11mm; @@ -170,7 +170,7 @@ div { margin: 0 -2em; } /* line 184, inputs/operators.scss */ div { - *margin-left: 2.07447%; } + *margin-left: 2.0744680851%; } /* line 190, inputs/operators.scss */ .foo { width: 12.5%; } From 4f605a51462c85cf6df5bb45460483a138e04025 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Sat, 14 Oct 2017 17:35:01 -0400 Subject: [PATCH 094/329] Bump version to 0.7.2 --- src/Version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Version.php b/src/Version.php index dd7cd384..0dd95fe6 100644 --- a/src/Version.php +++ b/src/Version.php @@ -18,5 +18,5 @@ */ class Version { - const VERSION = 'v0.7.0'; + const VERSION = 'v0.7.2'; } From c96edd1bedd3ba3e8ebeaf5ddd1f8669fb6f5625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20FRAN=C3=87OIS?= Date: Thu, 9 Nov 2017 11:16:12 +0100 Subject: [PATCH 095/329] add inline sourceMaps support --- src/Block.php | 5 + src/Compiler.php | 49 +++++- src/Formatter.php | 77 ++++++++- src/Formatter/Compressed.php | 4 +- src/Formatter/Crunched.php | 4 +- src/Formatter/Debug.php | 16 +- src/Formatter/Expanded.php | 4 +- src/Formatter/Nested.php | 20 ++- src/Formatter/OutputBlock.php | 15 ++ src/Parser.php | 1 + src/SourceMap/Base64VLQEncoder.php | 174 +++++++++++++++++++ src/SourceMap/SourceMapGenerator.php | 241 +++++++++++++++++++++++++++ 12 files changed, 579 insertions(+), 31 deletions(-) create mode 100644 src/SourceMap/Base64VLQEncoder.php create mode 100644 src/SourceMap/SourceMapGenerator.php diff --git a/src/Block.php b/src/Block.php index a6b5f3f0..87cfd6d8 100644 --- a/src/Block.php +++ b/src/Block.php @@ -28,6 +28,11 @@ class Block */ public $parent; + /** + * @var string; + */ + public $sourceName; + /** * @var integer */ diff --git a/src/Compiler.php b/src/Compiler.php index 0d67c525..a677760d 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -18,6 +18,7 @@ use Leafo\ScssPhp\Exception\CompilerException; use Leafo\ScssPhp\Formatter\OutputBlock; use Leafo\ScssPhp\Node; +use Leafo\ScssPhp\SourceMap\SourceMapGenerator; use Leafo\ScssPhp\Type; use Leafo\ScssPhp\Parser; use Leafo\ScssPhp\Util; @@ -64,6 +65,9 @@ class Compiler const WITH_SUPPORTS = 4; const WITH_ALL = 7; + const SOURCE_MAP_NONE = 0; + const SOURCE_MAP_INLINE = 1; + /** * @var array */ @@ -120,11 +124,16 @@ class Compiler protected $encoding = null; protected $lineNumberStyle = null; + protected $sourceMap = self::SOURCE_MAP_NONE; + protected $sourceMapOptions = []; + + /** @var string|Formatter */ protected $formatter = 'Leafo\ScssPhp\Formatter\Nested'; protected $rootEnv; protected $rootBlock; + /** @var Environment */ protected $env; protected $scope; protected $storeEnv; @@ -191,8 +200,21 @@ public function compile($code, $path = null) $this->compileRoot($tree); $this->popEnv(); - $out = $this->formatter->format($this->scope); + $sourceMapGenerator = null; + if($this->sourceMap && $this->sourceMap !== self::SOURCE_MAP_NONE) { + $sourceMapGenerator = new SourceMapGenerator($this->sourceMapOptions); + } + $out = $this->formatter->format($this->scope, $sourceMapGenerator); + if($this->sourceMap && $this->sourceMap !== self::SOURCE_MAP_NONE) { + $sourceMap = $sourceMapGenerator->generateJson(); + + $sourceMapUrl = null; + if($this->sourceMap == self::SOURCE_MAP_INLINE) { + $sourceMapUrl = sprintf('data:application/json,%s', self::encodeURIComponent($sourceMap)); + } + $out .= sprintf('/*# sourceMappingURL=%s */', $sourceMapUrl); + } return $out; } @@ -274,6 +296,9 @@ protected function makeOutputBlock($type, $selectors = null) $out->parent = $this->scope; $out->selectors = $selectors; $out->depth = $this->env->depth; + $out->sourceName = $this->env->block->sourceName; + $out->sourceLine = $this->env->block->sourceLine; + $out->sourceColumn = $this->env->block->sourceColumn; return $out; } @@ -656,6 +681,7 @@ protected function compileMedia(Block $media) if ($needsWrap) { $wrapped = new Block; + $wrapped->sourceName = $media->sourceName; $wrapped->sourceIndex = $media->sourceIndex; $wrapped->sourceLine = $media->sourceLine; $wrapped->sourceColumn = $media->sourceColumn; @@ -729,6 +755,7 @@ protected function compileAtRoot(Block $block) // wrap inline selector if ($block->selector) { $wrapped = new Block; + $wrapped->sourceName = $block->sourceName; $wrapped->sourceIndex = $block->sourceIndex; $wrapped->sourceLine = $block->sourceLine; $wrapped->sourceColumn = $block->sourceColumn; @@ -785,6 +812,7 @@ private function spliceTree($envs, Block $block, $without) } $b = new Block; + $b->sourceName = $e->block->sourceName; $b->sourceIndex = $e->block->sourceIndex; $b->sourceLine = $e->block->sourceLine; $b->sourceColumn = $e->block->sourceColumn; @@ -1076,6 +1104,13 @@ protected function evalSelectors($selectors) return $selectors; } + /** + * @param array $sourceMapOptions + */ + public function setSourceMapOptions($sourceMapOptions) { + $this->sourceMapOptions = $sourceMapOptions; + } + /** * Evaluate selector * @@ -3299,6 +3334,13 @@ public function setLineNumberStyle($lineNumberStyle) $this->lineNumberStyle = $lineNumberStyle; } + /** + * @param int $sourceMap + */ + public function setSourceMap($sourceMap) { + $this->sourceMap = $sourceMap; + } + /** * Register function * @@ -5256,4 +5298,9 @@ protected function libInspect($args) return $args[0]; } + + public static function encodeURIComponent($string){ + $revert = array('%21' => '!', '%2A' => '*', '%27' => "'", '%28' => '(', '%29' => ')'); + return strtr(rawurlencode($string), $revert); + } } diff --git a/src/Formatter.php b/src/Formatter.php index 0d2635f1..487b6612 100644 --- a/src/Formatter.php +++ b/src/Formatter.php @@ -12,6 +12,7 @@ namespace Leafo\ScssPhp; use Leafo\ScssPhp\Formatter\OutputBlock; +use Leafo\ScssPhp\SourceMap\SourceMapGenerator; /** * Base formatter @@ -56,10 +57,31 @@ abstract class Formatter public $assignSeparator; /** - * @var boolea + * @var boolean */ public $keepSemicolons; + /** + * @var OutputBlock; + */ + protected $currentBlock; + + + /** + * @var int + */ + protected $currentLine; + + /** + * @var int; + */ + protected $currentColumn; + + /** + * @var SourceMapGenerator + */ + protected $sourceMapGenerator; + /** * Initialize formatter * @@ -123,10 +145,10 @@ protected function blockLines(OutputBlock $block) $glue = $this->break . $inner; - echo $inner . implode($glue, $block->lines); + $this->write($inner . implode($glue, $block->lines)); if (! empty($block->children)) { - echo $this->break; + $this->write($this->break); } } @@ -139,9 +161,9 @@ protected function blockSelectors(OutputBlock $block) { $inner = $this->indentStr(); - echo $inner + $this->write($inner . implode($this->tagSeparator, $block->selectors) - . $this->open . $this->break; + . $this->open . $this->break); } /** @@ -167,6 +189,8 @@ protected function block(OutputBlock $block) return; } + $this->currentBlock = $block; + $pre = $this->indentStr(); if (! empty($block->selectors)) { @@ -187,10 +211,10 @@ protected function block(OutputBlock $block) $this->indentLevel--; if (empty($block->children)) { - echo $this->break; + $this->write($this->break); } - echo $pre . $this->close . $this->break; + $this->write($pre . $this->close . $this->break); } } @@ -201,10 +225,19 @@ protected function block(OutputBlock $block) * * @param \Leafo\ScssPhp\Formatter\OutputBlock $block An abstract syntax tree * + * @param SourceMapGenerator|null $sourceMapGenerator * @return string + * @internal param bool $collectSourceMap */ - public function format(OutputBlock $block) + public function format(OutputBlock $block, SourceMapGenerator $sourceMapGenerator = null) { + if($sourceMapGenerator) { + $this->currentLine = 1; + $this->currentColumn = 0; + $this->sourceMapGenerator = $sourceMapGenerator; + } else { + $this->sourceMapGenerator = null; + } ob_start(); $this->block($block); @@ -213,4 +246,32 @@ public function format(OutputBlock $block) return $out; } + + /** + * @param $str + */ + protected function write($str) { + if($this->sourceMapGenerator) { + $this->sourceMapGenerator->addMapping( + $this->currentLine, + $this->currentColumn, + $this->currentBlock->sourceLine, + $this->currentBlock->sourceColumn, + $this->currentBlock->sourceName + ); + + $lines = explode("\n", $str); + $lineCount = count($lines); + $this->currentLine += $lineCount-1; + + $lastLine = array_pop($lines); + if($lineCount == 1) { + $this->currentColumn += mb_strlen($lastLine); + } else { + $this->currentColumn = mb_strlen($lastLine); + } + } + + echo $str; + } } diff --git a/src/Formatter/Compressed.php b/src/Formatter/Compressed.php index 17aca54a..69a67850 100644 --- a/src/Formatter/Compressed.php +++ b/src/Formatter/Compressed.php @@ -53,10 +53,10 @@ public function blockLines(OutputBlock $block) } } - echo $inner . implode($glue, $block->lines); + $this->write( $inner . implode($glue, $block->lines)); if (! empty($block->children)) { - echo $this->break; + $this->write( $this->break); } } } diff --git a/src/Formatter/Crunched.php b/src/Formatter/Crunched.php index 0a89bc48..43d63833 100644 --- a/src/Formatter/Crunched.php +++ b/src/Formatter/Crunched.php @@ -51,10 +51,10 @@ public function blockLines(OutputBlock $block) } } - echo $inner . implode($glue, $block->lines); + $this->write($inner . implode($glue, $block->lines)); if (! empty($block->children)) { - echo $this->break; + $this->write($this->break); } } } diff --git a/src/Formatter/Debug.php b/src/Formatter/Debug.php index 321c5368..cb29641a 100644 --- a/src/Formatter/Debug.php +++ b/src/Formatter/Debug.php @@ -52,13 +52,13 @@ protected function blockLines(OutputBlock $block) $indent = $this->indentStr(); if (empty($block->lines)) { - echo "{$indent}block->lines: []\n"; + $this->write("{$indent}block->lines: []\n"); return; } foreach ($block->lines as $index => $line) { - echo "{$indent}block->lines[{$index}]: $line\n"; + $this->write( "{$indent}block->lines[{$index}]: $line\n"); } } @@ -70,13 +70,13 @@ protected function blockSelectors(OutputBlock $block) $indent = $this->indentStr(); if (empty($block->selectors)) { - echo "{$indent}block->selectors: []\n"; + $this->write( "{$indent}block->selectors: []\n"); return; } foreach ($block->selectors as $index => $selector) { - echo "{$indent}block->selectors[{$index}]: $selector\n"; + $this->write( "{$indent}block->selectors[{$index}]: $selector\n"); } } @@ -88,7 +88,7 @@ protected function blockChildren(OutputBlock $block) $indent = $this->indentStr(); if (empty($block->children)) { - echo "{$indent}block->children: []\n"; + $this->write( "{$indent}block->children: []\n"); return; } @@ -109,8 +109,10 @@ protected function block(OutputBlock $block) { $indent = $this->indentStr(); - echo "{$indent}block->type: {$block->type}\n" . - "{$indent}block->depth: {$block->depth}\n"; + $this->write( "{$indent}block->type: {$block->type}\n" . + "{$indent}block->depth: {$block->depth}\n"); + + $this->currentBlock = $block; $this->blockSelectors($block); $this->blockLines($block); diff --git a/src/Formatter/Expanded.php b/src/Formatter/Expanded.php index dff17e6b..0449787d 100644 --- a/src/Formatter/Expanded.php +++ b/src/Formatter/Expanded.php @@ -59,10 +59,10 @@ protected function blockLines(OutputBlock $block) } } - echo $inner . implode($glue, $block->lines); + $this->write($inner . implode($glue, $block->lines)); if (empty($block->selectors) || ! empty($block->children)) { - echo $this->break; + $this->write($this->break); } } } diff --git a/src/Formatter/Nested.php b/src/Formatter/Nested.php index c4ff803c..48e19ef7 100644 --- a/src/Formatter/Nested.php +++ b/src/Formatter/Nested.php @@ -12,7 +12,6 @@ namespace Leafo\ScssPhp\Formatter; use Leafo\ScssPhp\Formatter; -use Leafo\ScssPhp\Formatter\OutputBlock; /** * Nested formatter @@ -66,10 +65,10 @@ protected function blockLines(OutputBlock $block) } } - echo $inner . implode($glue, $block->lines); + $this->write( $inner . implode($glue, $block->lines)); if (! empty($block->children)) { - echo $this->break; + $this->write( $this->break); } } @@ -80,9 +79,9 @@ protected function blockSelectors(OutputBlock $block) { $inner = $this->indentStr(); - echo $inner + $this->write( $inner . implode($this->tagSeparator, $block->selectors) - . $this->open . $this->break; + . $this->open . $this->break); } /** @@ -94,13 +93,13 @@ protected function blockChildren(OutputBlock $block) $this->block($child); if ($i < count($block->children) - 1) { - echo $this->break; + $this->write( $this->break); if (isset($block->children[$i + 1])) { $next = $block->children[$i + 1]; if ($next->depth === max($block->depth, 1) && $child->depth >= $next->depth) { - echo $this->break; + $this->write( $this->break); } } } @@ -120,6 +119,9 @@ protected function block(OutputBlock $block) return; } + $this->currentBlock = $block; + + $this->depth = $block->depth; if (! empty($block->selectors)) { @@ -139,11 +141,11 @@ protected function block(OutputBlock $block) if (! empty($block->selectors)) { $this->indentLevel--; - echo $this->close; + $this->write( $this->close); } if ($block->type === 'root') { - echo $this->break; + $this->write( $this->break); } } diff --git a/src/Formatter/OutputBlock.php b/src/Formatter/OutputBlock.php index 88e86402..7d233a8d 100644 --- a/src/Formatter/OutputBlock.php +++ b/src/Formatter/OutputBlock.php @@ -47,4 +47,19 @@ class OutputBlock * @var \Leafo\ScssPhp\Formatter\OutputBlock */ public $parent; + + /** + * @var string + */ + public $sourceName; + + /** + * @var int + */ + public $sourceLine; + + /** + * @var int + */ + public $sourceColumn; } diff --git a/src/Parser.php b/src/Parser.php index 44043e65..cc0a51df 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -708,6 +708,7 @@ protected function pushBlock($selectors, $pos = 0) list($line, $column) = $this->getSourcePosition($pos); $b = new Block; + $b->sourceName = $this->sourceName; $b->sourceLine = $line; $b->sourceColumn = $column; $b->sourceIndex = $this->sourceIndex; diff --git a/src/SourceMap/Base64VLQEncoder.php b/src/SourceMap/Base64VLQEncoder.php new file mode 100644 index 00000000..14652fbe --- /dev/null +++ b/src/SourceMap/Base64VLQEncoder.php @@ -0,0 +1,174 @@ + 0, 'B' => 1, 'C' => 2, 'D' => 3, 'E' => 4, 'F' => 5, 'G' => 6, + 'H' => 7,'I' => 8, 'J' => 9, 'K' => 10, 'L' => 11, 'M' => 12, 'N' => 13, + 'O' => 14, 'P' => 15, 'Q' => 16, 'R' => 17, 'S' => 18, 'T' => 19, 'U' => 20, + 'V' => 21, 'W' => 22, 'X' => 23, 'Y' => 24, 'Z' => 25, 'a' => 26, 'b' => 27, + 'c' => 28, 'd' => 29, 'e' => 30, 'f' => 31, 'g' => 32, 'h' => 33, 'i' => 34, + 'j' => 35, 'k' => 36, 'l' => 37, 'm' => 38, 'n' => 39, 'o' => 40, 'p' => 41, + 'q' => 42, 'r' => 43, 's' => 44, 't' => 45, 'u' => 46, 'v' => 47, 'w' => 48, + 'x' => 49, 'y' => 50, 'z' => 51, 0 => 52, 1 => 53, 2 => 54, 3 => 55, 4 => 56, + 5 => 57, 6 => 58, 7 => 59, 8 => 60, 9 => 61, '+' => 62, '/' => 63, + ); + /** + * Integer to char map + * + * @var array + */ + private $intToCharMap = array( + 0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D', 4 => 'E', 5 => 'F', 6 => 'G', + 7 => 'H', 8 => 'I', 9 => 'J', 10 => 'K', 11 => 'L', 12 => 'M', 13 => 'N', + 14 => 'O', 15 => 'P', 16 => 'Q', 17 => 'R', 18 => 'S', 19 => 'T', 20 => 'U', + 21 => 'V', 22 => 'W', 23 => 'X', 24 => 'Y', 25 => 'Z', 26 => 'a', 27 => 'b', + 28 => 'c', 29 => 'd', 30 => 'e', 31 => 'f', 32 => 'g', 33 => 'h', 34 => 'i', + 35 => 'j', 36 => 'k', 37 => 'l', 38 => 'm', 39 => 'n', 40 => 'o', 41 => 'p', + 42 => 'q', 43 => 'r', 44 => 's', 45 => 't', 46 => 'u', 47 => 'v', 48 => 'w', + 49 => 'x', 50 => 'y', 51 => 'z', 52 => '0', 53 => '1', 54 => '2', 55 => '3', + 56 => '4', 57 => '5', 58 => '6', 59 => '7', 60 => '8', 61 => '9', 62 => '+', + 63 => '/', + ); + /** + * Constructor + */ + public function __construct(){ + // I leave it here for future reference + // foreach(str_split('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/') as $i => $char) + // { + // $this->charToIntMap[$char] = $i; + // $this->intToCharMap[$i] = $char; + // } + } + /** + * Convert from a two-complement value to a value where the sign bit is + * is placed in the least significant bit. For example, as decimals: + * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) + * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) + * We generate the value for 32 bit machines, hence -2147483648 becomes 1, not 4294967297, + * even on a 64 bit machine. + * @param string $aValue + */ + public function toVLQSigned($aValue){ + return 0xffffffff & ($aValue < 0 ? ((-$aValue) << 1) + 1 : ($aValue << 1) + 0); + } + /** + * Convert to a two-complement value from a value where the sign bit is + * is placed in the least significant bit. For example, as decimals: + * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 + * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 + * We assume that the value was generated with a 32 bit machine in mind. + * Hence + * 1 becomes -2147483648 + * even on a 64 bit machine. + * @param integer $aValue + */ + public function fromVLQSigned($aValue){ + return $aValue & 1 ? $this->zeroFill(~$aValue + 2, 1) | (-1 - 0x7fffffff) : $this->zeroFill($aValue, 1); + } + /** + * Return the base 64 VLQ encoded value. + * + * @param string $aValue The value to encode + * @return string The encoded value + */ + public function encode($aValue){ + $encoded = ''; + $vlq = $this->toVLQSigned($aValue); + do + { + $digit = $vlq & $this->mask; + $vlq = $this->zeroFill($vlq, $this->shift); + if($vlq > 0){ + $digit |= $this->continuationBit; + } + $encoded .= $this->base64Encode($digit); + } while($vlq > 0); + return $encoded; + } + /** + * Return the value decoded from base 64 VLQ. + * + * @param string $encoded The encoded value to decode + * @return integer The decoded value + */ + public function decode($encoded){ + $vlq = 0; + $i = 0; + do + { + $digit = $this->base64Decode($encoded[$i]); + $vlq |= ($digit & $this->mask) << ($i * $this->shift); + $i++; + } while($digit & $this->continuationBit); + return $this->fromVLQSigned($vlq); + } + /** + * Right shift with zero fill. + * + * @param integer $a number to shift + * @param integer $b number of bits to shift + * @return integer + */ + public function zeroFill($a, $b){ + return ($a >= 0) ? ($a >> $b) : ($a >> $b) & (PHP_INT_MAX >> ($b - 1)); + } + /** + * Encode single 6-bit digit as base64. + * + * @param integer $number + * @return string + * @throws Exception If the number is invalid + */ + public function base64Encode($number){ + if($number < 0 || $number > 63){ + throw new Exception(sprintf('Invalid number "%s" given. Must be between 0 and 63.', $number)); + } + return $this->intToCharMap[$number]; + } + /** + * Decode single 6-bit digit from base64 + * + * @param string $char + * @return number + * @throws Exception If the number is invalid + */ + public function base64Decode($char){ + if(!array_key_exists($char, $this->charToIntMap)){ + throw new Exception(sprintf('Invalid base 64 digit "%s" given.', $char)); + } + return $this->charToIntMap[$char]; + } +} diff --git a/src/SourceMap/SourceMapGenerator.php b/src/SourceMap/SourceMapGenerator.php new file mode 100644 index 00000000..3d21f4fe --- /dev/null +++ b/src/SourceMap/SourceMapGenerator.php @@ -0,0 +1,241 @@ + '', + // an optional name of the generated code that this source map is associated with. + 'sourceMapFilename' => null, + // url of the map + 'sourceMapURL' => null, + // absolute path to a file to write the map to + 'sourceMapWriteTo' => null, + // output source contents? + 'outputSourceFiles' => false, + // base path for filename normalization + 'sourceMapRootpath' => '', + // base path for filename normalization + 'sourceMapBasepath' => '' + ); + + /** + * The base64 VLQ encoder + * + * @var Base64VLQEncoder + */ + protected $encoder; + /** + * Array of mappings + * + * @var array + */ + protected $mappings = array(); + + /** + * Array of contents map + * + * @var array + */ + protected $contentsMap = array(); + /** + * File to content map + * + * @var array + */ + protected $sources = array(); + protected $source_keys = array(); + /** + * @var array + */ + private $options; + + public function __construct(array $options = []) { + $this->options = array_merge($this->defaultOptions, $options); + $this->encoder = new Base64VLQEncoder(); + } + + /** + * Adds a mapping + * + * @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) { + $this->mappings[] = array( + 'generated_line' => $generatedLine, + 'generated_column' => $generatedColumn, + 'original_line' => $originalLine, + 'original_column' => $originalColumn, + 'source_file' => $sourceFile + ); + + $this->sources[$sourceFile] = $sourceFile; + } + + /** + * Generates the JSON source map + * + * @return string + * @see https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit# + */ + public function generateJson() { + $sourceMap = array(); + $mappings = $this->generateMappings(); + // File version (always the first entry in the object) and must be a positive integer. + $sourceMap['version'] = self::VERSION; + // An optional name of the generated code that this source map is associated with. + $file = $this->options['sourceMapFilename']; + if($file) { + $sourceMap['file'] = $file; + } + // An optional source root, useful for relocating source files on a server or removing repeated values in the 'sources' entry. This value is prepended to the individual entries in the 'source' field. + $root = $this->options['sourceRoot']; + if($root) { + $sourceMap['sourceRoot'] = $root; + } + // A list of original sources used by the 'mappings' entry. + $sourceMap['sources'] = array(); + foreach($this->sources as $source_uri => $source_filename) { + $sourceMap['sources'][] = $this->normalizeFilename($source_filename); + } + // A list of symbol names used by the 'mappings' entry. + $sourceMap['names'] = array(); + // A string with the encoded mapping data. + $sourceMap['mappings'] = $mappings; + if($this->options['outputSourceFiles']) { + // An optional list of source content, useful when the 'source' can't be hosted. + // The contents are listed in the same order as the sources above. + // 'null' may be used if some original sources should be retrieved by name. + $sourceMap['sourcesContent'] = $this->getSourcesContent(); + } + // less.js compat fixes + if(count($sourceMap['sources']) && empty($sourceMap['sourceRoot'])) { + unset($sourceMap['sourceRoot']); + } + return json_encode($sourceMap); + } + + /** + * Returns the sources contents + * + * @return array|null + */ + protected function getSourcesContent() { + if(empty($this->sources)) { + return null; + } + $content = array(); + foreach($this->sources as $sourceFile) { + $content[] = file_get_contents($sourceFile); + } + return $content; + } + + /** + * Generates the mappings string + * + * @return string + */ + public function generateMappings() { + if(!count($this->mappings)) { + return ''; + } + $this->source_keys = array_flip(array_keys($this->sources)); + // group mappings by generated line number. + $groupedMap = $groupedMapEncoded = array(); + foreach($this->mappings as $m) { + $groupedMap[$m['generated_line']][] = $m; + } + ksort($groupedMap); + $lastGeneratedLine = $lastOriginalIndex = $lastOriginalLine = $lastOriginalColumn = 0; + foreach($groupedMap as $lineNumber => $line_map) { + while(++$lastGeneratedLine < $lineNumber) { + $groupedMapEncoded[] = ';'; + } + $lineMapEncoded = array(); + $lastGeneratedColumn = 0; + foreach($line_map as $m) { + $mapEncoded = $this->encoder->encode($m['generated_column'] - $lastGeneratedColumn); + $lastGeneratedColumn = $m['generated_column']; + // find the index + if($m['source_file']) { + $index = $this->findFileIndex($m['source_file']); + if($index !== false) { + $mapEncoded .= $this->encoder->encode($index - $lastOriginalIndex); + $lastOriginalIndex = $index; + // lines are stored 0-based in SourceMap spec version 3 + $mapEncoded .= $this->encoder->encode($m['original_line'] - 1 - $lastOriginalLine); + $lastOriginalLine = $m['original_line'] - 1; + $mapEncoded .= $this->encoder->encode($m['original_column'] - $lastOriginalColumn); + $lastOriginalColumn = $m['original_column']; + } + } + $lineMapEncoded[] = $mapEncoded; + } + $groupedMapEncoded[] = implode(',', $lineMapEncoded) . ';'; + } + return rtrim(implode($groupedMapEncoded), ';'); + } + + /** + * Finds the index for the filename + * + * @param string $filename + * @return integer|false + */ + protected function findFileIndex($filename) { + return $this->source_keys[$filename]; + } + + protected function normalizeFilename($filename) { + $filename = $this->fixWindowsPath($filename); + $rootpath = $this->options['sourceMapRootpath']; + $basePath = $this->options['sourceMapBasepath']; + // "Trim" the 'sourceMapBasepath' from the output filename. + if(strpos($filename, $basePath) === 0) { + $filename = substr($filename, strlen($basePath)); + } + // Remove extra leading path separators. + if(strpos($filename, '\\') === 0 || strpos($filename, '/') === 0) { + $filename = substr($filename, 1); + } + return $rootpath . $filename; + } + + /** + * fix windows paths + * @param string $path + * @param bool $addEndSlash + * @return string + */ + public function fixWindowsPath($path, $addEndSlash = false) { + $slash = ($addEndSlash) ? '/' : ''; + if(!empty($path)) { + $path = str_replace('\\', '/', $path); + $path = rtrim($path, '/') . $slash; + } + return $path; + } +} From 87c8b53442f0be9c8dd33cbac2308842dd240240 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20FRAN=C3=87OIS?= Date: Thu, 9 Nov 2017 13:37:18 +0100 Subject: [PATCH 096/329] inline sourceMaps: fix off-by-one column in source maps --- src/Formatter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Formatter.php b/src/Formatter.php index 487b6612..7939113b 100644 --- a/src/Formatter.php +++ b/src/Formatter.php @@ -256,7 +256,7 @@ protected function write($str) { $this->currentLine, $this->currentColumn, $this->currentBlock->sourceLine, - $this->currentBlock->sourceColumn, + $this->currentBlock->sourceColumn - 1, //columns from parser are off by one $this->currentBlock->sourceName ); From ce6c958bc90b729467b010d35fece984e6edec44 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Thu, 14 Dec 2017 12:34:12 -0500 Subject: [PATCH 097/329] Remove trailing whitespace --- src/Node/Number.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Node/Number.php b/src/Node/Number.php index 3dcdd2ca..efa83f5b 100644 --- a/src/Node/Number.php +++ b/src/Node/Number.php @@ -292,7 +292,7 @@ public function output(Compiler $compiler = null) reset($units); $unit = key($units); $dimension = number_format($dimension, static::$precision, '.', ''); - + return (static::$precision ? rtrim(rtrim($dimension, '0'), '.') : $dimension) . $unit; } From eb4ab3f9be1d7fe854017c3bf97a3ca8c27730fb Mon Sep 17 00:00:00 2001 From: dleffler Date: Fri, 15 Dec 2017 12:42:20 -0500 Subject: [PATCH 098/329] Adds File based source map (in addition to inline source map) - SOURCE_MAP_FILE, using code from less.php; ONLY if there is output from the scss file. --- scss.inc.php | 4 ++++ src/Compiler.php | 5 ++++- src/SourceMap/SourceMapGenerator.php | 24 ++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/scss.inc.php b/scss.inc.php index 83d23a6b..77303ba3 100644 --- a/scss.inc.php +++ b/scss.inc.php @@ -11,6 +11,7 @@ include_once __DIR__ . '/src/Compiler/Environment.php'; include_once __DIR__ . '/src/Exception/CompilerException.php'; include_once __DIR__ . '/src/Exception/ParserException.php'; + include_once __DIR__ . '/src/Exception/RangeException.php'; //exp include_once __DIR__ . '/src/Exception/ServerException.php'; include_once __DIR__ . '/src/Formatter.php'; include_once __DIR__ . '/src/Formatter/Compact.php'; @@ -23,6 +24,9 @@ include_once __DIR__ . '/src/Node.php'; include_once __DIR__ . '/src/Node/Number.php'; include_once __DIR__ . '/src/Parser.php'; +// include_once __DIR__ . '/src/example/Server.php'; + include_once __DIR__ . '/src/SourceMap/Base64VLQEncoder.php'; + include_once __DIR__ . '/src/SourceMap/SourceMapGenerator.php'; include_once __DIR__ . '/src/Type.php'; include_once __DIR__ . '/src/Util.php'; include_once __DIR__ . '/src/Version.php'; diff --git a/src/Compiler.php b/src/Compiler.php index a677760d..2dc50531 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -67,6 +67,7 @@ class Compiler const SOURCE_MAP_NONE = 0; const SOURCE_MAP_INLINE = 1; + const SOURCE_MAP_FILE = 2; /** * @var array @@ -205,12 +206,14 @@ public function compile($code, $path = null) $sourceMapGenerator = new SourceMapGenerator($this->sourceMapOptions); } $out = $this->formatter->format($this->scope, $sourceMapGenerator); - if($this->sourceMap && $this->sourceMap !== self::SOURCE_MAP_NONE) { + if(!empty($out) && $this->sourceMap && $this->sourceMap !== self::SOURCE_MAP_NONE) { $sourceMap = $sourceMapGenerator->generateJson(); $sourceMapUrl = null; if($this->sourceMap == self::SOURCE_MAP_INLINE) { $sourceMapUrl = sprintf('data:application/json,%s', self::encodeURIComponent($sourceMap)); + } elseif ($this->sourceMap == self::SOURCE_MAP_FILE) { + $sourceMapUrl = $sourceMapGenerator->saveMap($sourceMap); } $out .= sprintf('/*# sourceMappingURL=%s */', $sourceMapUrl); diff --git a/src/SourceMap/SourceMapGenerator.php b/src/SourceMap/SourceMapGenerator.php index 3d21f4fe..300a5a08 100644 --- a/src/SourceMap/SourceMapGenerator.php +++ b/src/SourceMap/SourceMapGenerator.php @@ -8,6 +8,8 @@ namespace Leafo\ScssPhp\SourceMap; +use Leafo\ScssPhp\Exception\CompilerException; + class SourceMapGenerator { /** * What version of source map does the generator generate? @@ -94,6 +96,28 @@ public function addMapping($generatedLine, $generatedColumn, $originalLine, $ori $this->sources[$sourceFile] = $sourceFile; } + /** + * Saves the source map to a file + * + * @param string $file The absolute path to a file + * @param string $content The content to write + * @throws Exception If the file could not be saved + */ + public function saveMap($content){ + $file = $this->options['sourceMapWriteTo']; + $dir = dirname($file); + // directory does not exist + if( !is_dir($dir) ){ + // FIXME: create the dir automatically? + throw new CompilerException(sprintf('The directory "%s" does not exist. Cannot save the source map.', $dir)); + } + // FIXME: proper saving, with dir write check! + if(file_put_contents($file, $content) === false){ + throw new CompilerException(sprintf('Cannot save the source map to "%s"', $file)); + } + return $this->options['sourceMapURL']; + } + /** * Generates the JSON source map * From 201b8978143ac913f00ab5a04a11cf2ba7151091 Mon Sep 17 00:00:00 2001 From: dleffler Date: Fri, 15 Dec 2017 12:42:58 -0500 Subject: [PATCH 099/329] Adds cachedCompile function to Server example (taken/modified from less.php) --- example/Server.php | 63 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/example/Server.php b/example/Server.php index 8dc3c7b2..a6e8b986 100644 --- a/example/Server.php +++ b/example/Server.php @@ -416,6 +416,69 @@ public function checkedCachedCompile($in, $out, $force = false) return $css; } + /** + * Execute scssphp on a .scss file or a scssphp cache structure + * + * The scssphp cache structure contains information about a specific + * scss file having been parsed. It can be used as a hint for future + * calls to determine whether or not a rebuild is required. + * + * The cache structure contains two important keys that may be used + * externally: + * + * compiled: The final compiled CSS + * updated: The time (in seconds) the CSS was last compiled + * + * The cache structure is a plain-ol' PHP associative array and can + * be serialized and unserialized without a hitch. + * + * @param mixed $in Input + * @param bool $force Force rebuild? + * @return array scssphp cache structure + */ + public function cachedCompile($in, $force = false) { + // assume no root + $root = null; + + if (is_string($in)) { + $root = $in; + } elseif (is_array($in) and isset($in['root'])) { + if ($force or ! isset($in['files'])) { + // If we are forcing a recompile or if for some reason the + // structure does not contain any file information we should + // specify the root to trigger a rebuild. + $root = $in['root']; + } elseif (isset($in['files']) and is_array($in['files'])) { + foreach ($in['files'] as $fname => $ftime ) { + if (!file_exists($fname) or filemtime($fname) > $ftime) { + // One of the files we knew about previously has changed + // so we should look at our incoming root again. + $root = $in['root']; + break; + } + } + } + } else { + // TODO: Throw an exception? We got neither a string nor something + // that looks like a compatible lessphp cache structure. + return null; + } + + if ($root !== null) { + // If we have a root value which means we should rebuild. + $out = array(); + $out['root'] = $root; + $out['compiled'] = $this->compileFile($root); + $out['files'] = $this->scss->getParsedFiles(); + $out['updated'] = time(); + return $out; + } else { + // No changes, pass back the structure + // we were given initially. + return $in; + } + } + /** * Constructor * From 89d9dabd18f8f068c62d7d0949da0c608ae5ed94 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Mon, 18 Dec 2017 17:32:42 -0500 Subject: [PATCH 100/329] Coding style (phpcs) cleanup --- Makefile | 2 +- example/Server.php | 124 +++++++++--------- scss.inc.php | 3 +- src/Block.php | 2 +- src/Compiler.php | 48 +++++-- src/Formatter.php | 27 ++-- src/Formatter/Compressed.php | 4 +- src/Formatter/Debug.php | 10 +- src/Formatter/Nested.php | 14 +- src/Formatter/OutputBlock.php | 4 +- src/SourceMap/Base64VLQEncoder.php | 136 ++++++++++++-------- src/SourceMap/SourceMapGenerator.php | 186 ++++++++++++++++++--------- src/Util.php | 8 +- tests/ServerTest.php | 1 + 14 files changed, 342 insertions(+), 227 deletions(-) diff --git a/Makefile b/Makefile index 5115941c..fb50ffdb 100644 --- a/Makefile +++ b/Makefile @@ -5,4 +5,4 @@ compat: TEST_SCSS_COMPAT=1 vendor/bin/phpunit --colors tests | tail -2 standard: - vendor/bin/phpcs --standard=PSR2 bin src tests *.php + vendor/bin/phpcs --standard=PSR2 bin src example tests *.php diff --git a/example/Server.php b/example/Server.php index a6e8b986..a8dc0457 100644 --- a/example/Server.php +++ b/example/Server.php @@ -417,67 +417,69 @@ public function checkedCachedCompile($in, $out, $force = false) } /** - * Execute scssphp on a .scss file or a scssphp cache structure - * - * The scssphp cache structure contains information about a specific - * scss file having been parsed. It can be used as a hint for future - * calls to determine whether or not a rebuild is required. - * - * The cache structure contains two important keys that may be used - * externally: - * - * compiled: The final compiled CSS - * updated: The time (in seconds) the CSS was last compiled - * - * The cache structure is a plain-ol' PHP associative array and can - * be serialized and unserialized without a hitch. - * - * @param mixed $in Input - * @param bool $force Force rebuild? - * @return array scssphp cache structure - */ - public function cachedCompile($in, $force = false) { - // assume no root - $root = null; - - if (is_string($in)) { - $root = $in; - } elseif (is_array($in) and isset($in['root'])) { - if ($force or ! isset($in['files'])) { - // If we are forcing a recompile or if for some reason the - // structure does not contain any file information we should - // specify the root to trigger a rebuild. - $root = $in['root']; - } elseif (isset($in['files']) and is_array($in['files'])) { - foreach ($in['files'] as $fname => $ftime ) { - if (!file_exists($fname) or filemtime($fname) > $ftime) { - // One of the files we knew about previously has changed - // so we should look at our incoming root again. - $root = $in['root']; - break; - } - } - } - } else { - // TODO: Throw an exception? We got neither a string nor something - // that looks like a compatible lessphp cache structure. - return null; - } - - if ($root !== null) { - // If we have a root value which means we should rebuild. - $out = array(); - $out['root'] = $root; - $out['compiled'] = $this->compileFile($root); - $out['files'] = $this->scss->getParsedFiles(); - $out['updated'] = time(); - return $out; - } else { - // No changes, pass back the structure - // we were given initially. - return $in; - } - } + * Execute scssphp on a .scss file or a scssphp cache structure + * + * The scssphp cache structure contains information about a specific + * scss file having been parsed. It can be used as a hint for future + * calls to determine whether or not a rebuild is required. + * + * The cache structure contains two important keys that may be used + * externally: + * + * compiled: The final compiled CSS + * updated: The time (in seconds) the CSS was last compiled + * + * The cache structure is a plain-ol' PHP associative array and can + * be serialized and unserialized without a hitch. + * + * @param mixed $in Input + * @param boolean $force Force rebuild? + * + * @return array scssphp cache structure + */ + public function cachedCompile($in, $force = false) + { + // assume no root + $root = null; + + if (is_string($in)) { + $root = $in; + } elseif (is_array($in) and isset($in['root'])) { + if ($force or ! isset($in['files'])) { + // If we are forcing a recompile or if for some reason the + // structure does not contain any file information we should + // specify the root to trigger a rebuild. + $root = $in['root']; + } elseif (isset($in['files']) and is_array($in['files'])) { + foreach ($in['files'] as $fname => $ftime) { + if (! file_exists($fname) or filemtime($fname) > $ftime) { + // One of the files we knew about previously has changed + // so we should look at our incoming root again. + $root = $in['root']; + break; + } + } + } + } else { + // TODO: Throw an exception? We got neither a string nor something + // that looks like a compatible lessphp cache structure. + return null; + } + + if ($root !== null) { + // If we have a root value which means we should rebuild. + $out = array(); + $out['root'] = $root; + $out['compiled'] = $this->compileFile($root); + $out['files'] = $this->scss->getParsedFiles(); + $out['updated'] = time(); + return $out; + } else { + // No changes, pass back the structure + // we were given initially. + return $in; + } + } /** * Constructor diff --git a/scss.inc.php b/scss.inc.php index 77303ba3..13c84bf5 100644 --- a/scss.inc.php +++ b/scss.inc.php @@ -11,7 +11,7 @@ include_once __DIR__ . '/src/Compiler/Environment.php'; include_once __DIR__ . '/src/Exception/CompilerException.php'; include_once __DIR__ . '/src/Exception/ParserException.php'; - include_once __DIR__ . '/src/Exception/RangeException.php'; //exp + include_once __DIR__ . '/src/Exception/RangeException.php'; include_once __DIR__ . '/src/Exception/ServerException.php'; include_once __DIR__ . '/src/Formatter.php'; include_once __DIR__ . '/src/Formatter/Compact.php'; @@ -24,7 +24,6 @@ include_once __DIR__ . '/src/Node.php'; include_once __DIR__ . '/src/Node/Number.php'; include_once __DIR__ . '/src/Parser.php'; -// include_once __DIR__ . '/src/example/Server.php'; include_once __DIR__ . '/src/SourceMap/Base64VLQEncoder.php'; include_once __DIR__ . '/src/SourceMap/SourceMapGenerator.php'; include_once __DIR__ . '/src/Type.php'; diff --git a/src/Block.php b/src/Block.php index 87cfd6d8..fc21e5a4 100644 --- a/src/Block.php +++ b/src/Block.php @@ -29,7 +29,7 @@ class Block public $parent; /** - * @var string; + * @var string */ public $sourceName; diff --git a/src/Compiler.php b/src/Compiler.php index 2dc50531..64399b2a 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -128,13 +128,17 @@ class Compiler protected $sourceMap = self::SOURCE_MAP_NONE; protected $sourceMapOptions = []; - /** @var string|Formatter */ + /** + * @var string|\Leafo\ScssPhp\Formatter + */ protected $formatter = 'Leafo\ScssPhp\Formatter\Nested'; protected $rootEnv; protected $rootBlock; - /** @var Environment */ + /** + * @var \Leafo\ScssPhp\Compiler\Environment + */ protected $env; protected $scope; protected $storeEnv; @@ -202,22 +206,30 @@ public function compile($code, $path = null) $this->popEnv(); $sourceMapGenerator = null; - if($this->sourceMap && $this->sourceMap !== self::SOURCE_MAP_NONE) { + + if ($this->sourceMap && $this->sourceMap !== self::SOURCE_MAP_NONE) { $sourceMapGenerator = new SourceMapGenerator($this->sourceMapOptions); } + $out = $this->formatter->format($this->scope, $sourceMapGenerator); - if(!empty($out) && $this->sourceMap && $this->sourceMap !== self::SOURCE_MAP_NONE) { - $sourceMap = $sourceMapGenerator->generateJson(); + if (! empty($out) && $this->sourceMap && $this->sourceMap !== self::SOURCE_MAP_NONE) { + $sourceMap = $sourceMapGenerator->generateJson(); $sourceMapUrl = null; - if($this->sourceMap == self::SOURCE_MAP_INLINE) { - $sourceMapUrl = sprintf('data:application/json,%s', self::encodeURIComponent($sourceMap)); - } elseif ($this->sourceMap == self::SOURCE_MAP_FILE) { - $sourceMapUrl = $sourceMapGenerator->saveMap($sourceMap); + + switch ($this->sourceMap) { + case self::SOURCE_MAP_INLINE: + $sourceMapUrl = sprintf('data:application/json,%s', self::encodeURIComponent($sourceMap)); + break; + + case self::SOURCE_MAP_FILE: + $sourceMapUrl = $sourceMapGenerator->saveMap($sourceMap); + break; } $out .= sprintf('/*# sourceMappingURL=%s */', $sourceMapUrl); } + return $out; } @@ -1110,7 +1122,8 @@ protected function evalSelectors($selectors) /** * @param array $sourceMapOptions */ - public function setSourceMapOptions($sourceMapOptions) { + public function setSourceMapOptions($sourceMapOptions) + { $this->sourceMapOptions = $sourceMapOptions; } @@ -1959,7 +1972,7 @@ protected function isTruthy($value) * * @param string $value * - * @return bool + * @return boolean */ protected function isImmediateRelationshipCombinator($value) { @@ -3338,9 +3351,14 @@ public function setLineNumberStyle($lineNumberStyle) } /** - * @param int $sourceMap + * Set source map option + * + * @api + * + * @param integer $sourceMap */ - public function setSourceMap($sourceMap) { + public function setSourceMap($sourceMap) + { $this->sourceMap = $sourceMap; } @@ -5302,8 +5320,10 @@ protected function libInspect($args) return $args[0]; } - public static function encodeURIComponent($string){ + public static function encodeURIComponent($string) + { $revert = array('%21' => '!', '%2A' => '*', '%27' => "'", '%28' => '(', '%29' => ')'); + return strtr(rawurlencode($string), $revert); } } diff --git a/src/Formatter.php b/src/Formatter.php index 7939113b..68d20c88 100644 --- a/src/Formatter.php +++ b/src/Formatter.php @@ -62,18 +62,18 @@ abstract class Formatter public $keepSemicolons; /** - * @var OutputBlock; + * @var \Leafo\ScssPhp\Formatter\OutputBlock */ protected $currentBlock; /** - * @var int + * @var integer */ protected $currentLine; /** - * @var int; + * @var integer */ protected $currentColumn; @@ -231,13 +231,14 @@ protected function block(OutputBlock $block) */ public function format(OutputBlock $block, SourceMapGenerator $sourceMapGenerator = null) { - if($sourceMapGenerator) { + $this->sourceMapGenerator = null; + + if ($sourceMapGenerator) { $this->currentLine = 1; $this->currentColumn = 0; $this->sourceMapGenerator = $sourceMapGenerator; - } else { - $this->sourceMapGenerator = null; } + ob_start(); $this->block($block); @@ -248,10 +249,11 @@ public function format(OutputBlock $block, SourceMapGenerator $sourceMapGenerato } /** - * @param $str + * @param string $str */ - protected function write($str) { - if($this->sourceMapGenerator) { + protected function write($str) + { + if ($this->sourceMapGenerator) { $this->sourceMapGenerator->addMapping( $this->currentLine, $this->currentColumn, @@ -265,11 +267,8 @@ protected function write($str) { $this->currentLine += $lineCount-1; $lastLine = array_pop($lines); - if($lineCount == 1) { - $this->currentColumn += mb_strlen($lastLine); - } else { - $this->currentColumn = mb_strlen($lastLine); - } + + $this->currentColumn = ($lineCount === 1 ? $this->currentColumn : 0) + strlen($lastLine); } echo $str; diff --git a/src/Formatter/Compressed.php b/src/Formatter/Compressed.php index 69a67850..21cbf28e 100644 --- a/src/Formatter/Compressed.php +++ b/src/Formatter/Compressed.php @@ -53,10 +53,10 @@ public function blockLines(OutputBlock $block) } } - $this->write( $inner . implode($glue, $block->lines)); + $this->write($inner . implode($glue, $block->lines)); if (! empty($block->children)) { - $this->write( $this->break); + $this->write($this->break); } } } diff --git a/src/Formatter/Debug.php b/src/Formatter/Debug.php index cb29641a..b31c8c7a 100644 --- a/src/Formatter/Debug.php +++ b/src/Formatter/Debug.php @@ -58,7 +58,7 @@ protected function blockLines(OutputBlock $block) } foreach ($block->lines as $index => $line) { - $this->write( "{$indent}block->lines[{$index}]: $line\n"); + $this->write("{$indent}block->lines[{$index}]: $line\n"); } } @@ -70,13 +70,13 @@ protected function blockSelectors(OutputBlock $block) $indent = $this->indentStr(); if (empty($block->selectors)) { - $this->write( "{$indent}block->selectors: []\n"); + $this->write("{$indent}block->selectors: []\n"); return; } foreach ($block->selectors as $index => $selector) { - $this->write( "{$indent}block->selectors[{$index}]: $selector\n"); + $this->write("{$indent}block->selectors[{$index}]: $selector\n"); } } @@ -88,7 +88,7 @@ protected function blockChildren(OutputBlock $block) $indent = $this->indentStr(); if (empty($block->children)) { - $this->write( "{$indent}block->children: []\n"); + $this->write("{$indent}block->children: []\n"); return; } @@ -109,7 +109,7 @@ protected function block(OutputBlock $block) { $indent = $this->indentStr(); - $this->write( "{$indent}block->type: {$block->type}\n" . + $this->write("{$indent}block->type: {$block->type}\n" . "{$indent}block->depth: {$block->depth}\n"); $this->currentBlock = $block; diff --git a/src/Formatter/Nested.php b/src/Formatter/Nested.php index 48e19ef7..7573a596 100644 --- a/src/Formatter/Nested.php +++ b/src/Formatter/Nested.php @@ -65,10 +65,10 @@ protected function blockLines(OutputBlock $block) } } - $this->write( $inner . implode($glue, $block->lines)); + $this->write($inner . implode($glue, $block->lines)); if (! empty($block->children)) { - $this->write( $this->break); + $this->write($this->break); } } @@ -79,7 +79,7 @@ protected function blockSelectors(OutputBlock $block) { $inner = $this->indentStr(); - $this->write( $inner + $this->write($inner . implode($this->tagSeparator, $block->selectors) . $this->open . $this->break); } @@ -93,13 +93,13 @@ protected function blockChildren(OutputBlock $block) $this->block($child); if ($i < count($block->children) - 1) { - $this->write( $this->break); + $this->write($this->break); if (isset($block->children[$i + 1])) { $next = $block->children[$i + 1]; if ($next->depth === max($block->depth, 1) && $child->depth >= $next->depth) { - $this->write( $this->break); + $this->write($this->break); } } } @@ -141,11 +141,11 @@ protected function block(OutputBlock $block) if (! empty($block->selectors)) { $this->indentLevel--; - $this->write( $this->close); + $this->write($this->close); } if ($block->type === 'root') { - $this->write( $this->break); + $this->write($this->break); } } diff --git a/src/Formatter/OutputBlock.php b/src/Formatter/OutputBlock.php index 7d233a8d..e4092175 100644 --- a/src/Formatter/OutputBlock.php +++ b/src/Formatter/OutputBlock.php @@ -54,12 +54,12 @@ class OutputBlock public $sourceName; /** - * @var int + * @var integer */ public $sourceLine; /** - * @var int + * @var integer */ public $sourceColumn; } diff --git a/src/SourceMap/Base64VLQEncoder.php b/src/SourceMap/Base64VLQEncoder.php index 14652fbe..d1d1ed2a 100644 --- a/src/SourceMap/Base64VLQEncoder.php +++ b/src/SourceMap/Base64VLQEncoder.php @@ -1,140 +1,167 @@ + * @author Nicolas FRANÇOIS + */ +class Base64VLQEncoder +{ /** * Shift * * @var integer */ private $shift = 5; + /** * Mask * * @var integer */ private $mask = 0x1F; // == (1 << shift) == 0b00011111 + /** * Continuation bit * * @var integer */ private $continuationBit = 0x20; // == (mask - 1 ) == 0b00100000 + /** * Char to integer map * * @var array */ private $charToIntMap = array( - 'A' => 0, 'B' => 1, 'C' => 2, 'D' => 3, 'E' => 4, 'F' => 5, 'G' => 6, - 'H' => 7,'I' => 8, 'J' => 9, 'K' => 10, 'L' => 11, 'M' => 12, 'N' => 13, - 'O' => 14, 'P' => 15, 'Q' => 16, 'R' => 17, 'S' => 18, 'T' => 19, 'U' => 20, - 'V' => 21, 'W' => 22, 'X' => 23, 'Y' => 24, 'Z' => 25, 'a' => 26, 'b' => 27, - 'c' => 28, 'd' => 29, 'e' => 30, 'f' => 31, 'g' => 32, 'h' => 33, 'i' => 34, - 'j' => 35, 'k' => 36, 'l' => 37, 'm' => 38, 'n' => 39, 'o' => 40, 'p' => 41, - 'q' => 42, 'r' => 43, 's' => 44, 't' => 45, 'u' => 46, 'v' => 47, 'w' => 48, - 'x' => 49, 'y' => 50, 'z' => 51, 0 => 52, 1 => 53, 2 => 54, 3 => 55, 4 => 56, - 5 => 57, 6 => 58, 7 => 59, 8 => 60, 9 => 61, '+' => 62, '/' => 63, + 'A' => 0, 'B' => 1, 'C' => 2, 'D' => 3, 'E' => 4, 'F' => 5, 'G' => 6, 'H' => 7, + 'I' => 8, 'J' => 9, 'K' => 10, 'L' => 11, 'M' => 12, 'N' => 13, 'O' => 14, 'P' => 15, + 'Q' => 16, 'R' => 17, 'S' => 18, 'T' => 19, 'U' => 20, 'V' => 21, 'W' => 22, 'X' => 23, + 'Y' => 24, 'Z' => 25, 'a' => 26, 'b' => 27, 'c' => 28, 'd' => 29, 'e' => 30, 'f' => 31, + 'g' => 32, 'h' => 33, 'i' => 34, 'j' => 35, 'k' => 36, 'l' => 37, 'm' => 38, 'n' => 39, + 'o' => 40, 'p' => 41, 'q' => 42, 'r' => 43, 's' => 44, 't' => 45, 'u' => 46, 'v' => 47, + 'w' => 48, 'x' => 49, 'y' => 50, 'z' => 51, 0 => 52, 1 => 53, 2 => 54, 3 => 55, + 4 => 56, 5 => 57, 6 => 58, 7 => 59, 8 => 60, 9 => 61, '+' => 62, '/' => 63, ); + /** * Integer to char map * * @var array */ private $intToCharMap = array( - 0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D', 4 => 'E', 5 => 'F', 6 => 'G', - 7 => 'H', 8 => 'I', 9 => 'J', 10 => 'K', 11 => 'L', 12 => 'M', 13 => 'N', - 14 => 'O', 15 => 'P', 16 => 'Q', 17 => 'R', 18 => 'S', 19 => 'T', 20 => 'U', - 21 => 'V', 22 => 'W', 23 => 'X', 24 => 'Y', 25 => 'Z', 26 => 'a', 27 => 'b', - 28 => 'c', 29 => 'd', 30 => 'e', 31 => 'f', 32 => 'g', 33 => 'h', 34 => 'i', - 35 => 'j', 36 => 'k', 37 => 'l', 38 => 'm', 39 => 'n', 40 => 'o', 41 => 'p', - 42 => 'q', 43 => 'r', 44 => 's', 45 => 't', 46 => 'u', 47 => 'v', 48 => 'w', - 49 => 'x', 50 => 'y', 51 => 'z', 52 => '0', 53 => '1', 54 => '2', 55 => '3', - 56 => '4', 57 => '5', 58 => '6', 59 => '7', 60 => '8', 61 => '9', 62 => '+', - 63 => '/', + 0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D', 4 => 'E', 5 => 'F', 6 => 'G', 7 => 'H', + 8 => 'I', 9 => 'J', 10 => 'K', 11 => 'L', 12 => 'M', 13 => 'N', 14 => 'O', 15 => 'P', + 16 => 'Q', 17 => 'R', 18 => 'S', 19 => 'T', 20 => 'U', 21 => 'V', 22 => 'W', 23 => 'X', + 24 => 'Y', 25 => 'Z', 26 => 'a', 27 => 'b', 28 => 'c', 29 => 'd', 30 => 'e', 31 => 'f', + 32 => 'g', 33 => 'h', 34 => 'i', 35 => 'j', 36 => 'k', 37 => 'l', 38 => 'm', 39 => 'n', + 40 => 'o', 41 => 'p', 42 => 'q', 43 => 'r', 44 => 's', 45 => 't', 46 => 'u', 47 => 'v', + 48 => 'w', 49 => 'x', 50 => 'y', 51 => 'z', 52 => '0', 53 => '1', 54 => '2', 55 => '3', + 56 => '4', 57 => '5', 58 => '6', 59 => '7', 60 => '8', 61 => '9', 62 => '+', 63 => '/', ); + /** * Constructor */ - public function __construct(){ + public function __construct() + { // I leave it here for future reference - // foreach(str_split('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/') as $i => $char) + // foreach (str_split('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/') as $i => $char) // { - // $this->charToIntMap[$char] = $i; - // $this->intToCharMap[$i] = $char; + // $this->charToIntMap[$char] = $i; + // $this->intToCharMap[$i] = $char; // } } + /** * Convert from a two-complement value to a value where the sign bit is - * is placed in the least significant bit. For example, as decimals: - * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) - * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) + * is placed in the least significant bit. For example, as decimals: + * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) + * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) * We generate the value for 32 bit machines, hence -2147483648 becomes 1, not 4294967297, * even on a 64 bit machine. * @param string $aValue */ - public function toVLQSigned($aValue){ + public function toVLQSigned($aValue) + { return 0xffffffff & ($aValue < 0 ? ((-$aValue) << 1) + 1 : ($aValue << 1) + 0); } + /** * Convert to a two-complement value from a value where the sign bit is * is placed in the least significant bit. For example, as decimals: - * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 - * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 + * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 + * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 * We assume that the value was generated with a 32 bit machine in mind. * Hence - * 1 becomes -2147483648 + * 1 becomes -2147483648 * even on a 64 bit machine. * @param integer $aValue */ - public function fromVLQSigned($aValue){ + public function fromVLQSigned($aValue) + { return $aValue & 1 ? $this->zeroFill(~$aValue + 2, 1) | (-1 - 0x7fffffff) : $this->zeroFill($aValue, 1); } + /** * Return the base 64 VLQ encoded value. * * @param string $aValue The value to encode * @return string The encoded value */ - public function encode($aValue){ + public function encode($aValue) + { $encoded = ''; $vlq = $this->toVLQSigned($aValue); - do - { + + do { $digit = $vlq & $this->mask; $vlq = $this->zeroFill($vlq, $this->shift); - if($vlq > 0){ + + if ($vlq > 0) { $digit |= $this->continuationBit; } + $encoded .= $this->base64Encode($digit); - } while($vlq > 0); + } while ($vlq > 0); + return $encoded; } + /** * Return the value decoded from base 64 VLQ. * * @param string $encoded The encoded value to decode * @return integer The decoded value */ - public function decode($encoded){ + public function decode($encoded) + { $vlq = 0; $i = 0; - do - { + + do { $digit = $this->base64Decode($encoded[$i]); $vlq |= ($digit & $this->mask) << ($i * $this->shift); $i++; - } while($digit & $this->continuationBit); + } while ($digit & $this->continuationBit); + return $this->fromVLQSigned($vlq); } + /** * Right shift with zero fill. * @@ -142,9 +169,11 @@ public function decode($encoded){ * @param integer $b number of bits to shift * @return integer */ - public function zeroFill($a, $b){ + public function zeroFill($a, $b) + { return ($a >= 0) ? ($a >> $b) : ($a >> $b) & (PHP_INT_MAX >> ($b - 1)); } + /** * Encode single 6-bit digit as base64. * @@ -152,12 +181,15 @@ public function zeroFill($a, $b){ * @return string * @throws Exception If the number is invalid */ - public function base64Encode($number){ - if($number < 0 || $number > 63){ + public function base64Encode($number) + { + if ($number < 0 || $number > 63) { throw new Exception(sprintf('Invalid number "%s" given. Must be between 0 and 63.', $number)); } + return $this->intToCharMap[$number]; } + /** * Decode single 6-bit digit from base64 * @@ -165,10 +197,12 @@ public function base64Encode($number){ * @return number * @throws Exception If the number is invalid */ - public function base64Decode($char){ - if(!array_key_exists($char, $this->charToIntMap)){ + public function base64Decode($char) + { + if (! array_key_exists($char, $this->charToIntMap)) { throw new Exception(sprintf('Invalid base 64 digit "%s" given.', $char)); } + return $this->charToIntMap[$char]; } } diff --git a/src/SourceMap/SourceMapGenerator.php b/src/SourceMap/SourceMapGenerator.php index 300a5a08..31905b10 100644 --- a/src/SourceMap/SourceMapGenerator.php +++ b/src/SourceMap/SourceMapGenerator.php @@ -1,20 +1,33 @@ + * @author Nicolas FRANÇOIS + */ +class SourceMapGenerator +{ /** * What version of source map does the generator generate? */ const VERSION = 3; + /** * Array of default options * @@ -25,16 +38,22 @@ class SourceMapGenerator { // on a server or removing repeated values in the 'sources' entry. // This value is prepended to the individual entries in the 'source' field. 'sourceRoot' => '', + // an optional name of the generated code that this source map is associated with. 'sourceMapFilename' => null, + // url of the map 'sourceMapURL' => null, + // absolute path to a file to write the map to 'sourceMapWriteTo' => null, + // output source contents? 'outputSourceFiles' => false, + // base path for filename normalization 'sourceMapRootpath' => '', + // base path for filename normalization 'sourceMapBasepath' => '' ); @@ -42,9 +61,10 @@ class SourceMapGenerator { /** * The base64 VLQ encoder * - * @var Base64VLQEncoder + * @var \Leafo\ScssPhp\SourceMap\Base64VLQEncoder */ protected $encoder; + /** * Array of mappings * @@ -58,6 +78,7 @@ class SourceMapGenerator { * @var array */ protected $contentsMap = array(); + /** * File to content map * @@ -65,12 +86,14 @@ class SourceMapGenerator { */ protected $sources = array(); protected $source_keys = array(); + /** * @var array */ private $options; - public function __construct(array $options = []) { + public function __construct(array $options = []) + { $this->options = array_merge($this->defaultOptions, $options); $this->encoder = new Base64VLQEncoder(); } @@ -84,7 +107,8 @@ public function __construct(array $options = []) { * @param integer $originalColumn The column number in original file * @param string $sourceFile The original source file */ - public function addMapping($generatedLine, $generatedColumn, $originalLine, $originalColumn, $sourceFile) { + public function addMapping($generatedLine, $generatedColumn, $originalLine, $originalColumn, $sourceFile) + { $this->mappings[] = array( 'generated_line' => $generatedLine, 'generated_column' => $generatedColumn, @@ -97,26 +121,30 @@ public function addMapping($generatedLine, $generatedColumn, $originalLine, $ori } /** - * Saves the source map to a file - * - * @param string $file The absolute path to a file - * @param string $content The content to write - * @throws Exception If the file could not be saved - */ - public function saveMap($content){ - $file = $this->options['sourceMapWriteTo']; - $dir = dirname($file); - // directory does not exist - if( !is_dir($dir) ){ - // FIXME: create the dir automatically? - throw new CompilerException(sprintf('The directory "%s" does not exist. Cannot save the source map.', $dir)); - } - // FIXME: proper saving, with dir write check! - if(file_put_contents($file, $content) === false){ - throw new CompilerException(sprintf('Cannot save the source map to "%s"', $file)); - } - return $this->options['sourceMapURL']; - } + * Saves the source map to a file + * + * @param string $file The absolute path to a file + * @param string $content The content to write + * @throws Exception If the file could not be saved + */ + public function saveMap($content) + { + $file = $this->options['sourceMapWriteTo']; + $dir = dirname($file); + + // directory does not exist + if (! is_dir($dir)) { + // FIXME: create the dir automatically? + throw new CompilerException(sprintf('The directory "%s" does not exist. Cannot save the source map.', $dir)); + } + + // FIXME: proper saving, with dir write check! + if (file_put_contents($file, $content) === false) { + throw new CompilerException(sprintf('Cannot save the source map to "%s"', $file)); + } + + return $this->options['sourceMapURL']; + } /** * Generates the JSON source map @@ -124,40 +152,44 @@ public function saveMap($content){ * @return string * @see https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit# */ - public function generateJson() { + public function generateJson() + { $sourceMap = array(); - $mappings = $this->generateMappings(); + $mappings = $this->generateMappings(); + // File version (always the first entry in the object) and must be a positive integer. $sourceMap['version'] = self::VERSION; + // An optional name of the generated code that this source map is associated with. $file = $this->options['sourceMapFilename']; - if($file) { + + if ($file) { $sourceMap['file'] = $file; } - // An optional source root, useful for relocating source files on a server or removing repeated values in the 'sources' entry. This value is prepended to the individual entries in the 'source' field. + + // An optional source root, useful for relocating source files on a server or removing repeated values in the + // 'sources' entry. This value is prepended to the individual entries in the 'source' field. $root = $this->options['sourceRoot']; - if($root) { - $sourceMap['sourceRoot'] = $root; - } - // A list of original sources used by the 'mappings' entry. - $sourceMap['sources'] = array(); - foreach($this->sources as $source_uri => $source_filename) { - $sourceMap['sources'][] = $this->normalizeFilename($source_filename); + + if ($root) { + $sourceMap['names'] = array(); } - // A list of symbol names used by the 'mappings' entry. - $sourceMap['names'] = array(); + // A string with the encoded mapping data. $sourceMap['mappings'] = $mappings; - if($this->options['outputSourceFiles']) { + + if ($this->options['outputSourceFiles']) { // An optional list of source content, useful when the 'source' can't be hosted. // The contents are listed in the same order as the sources above. // 'null' may be used if some original sources should be retrieved by name. $sourceMap['sourcesContent'] = $this->getSourcesContent(); } + // less.js compat fixes - if(count($sourceMap['sources']) && empty($sourceMap['sourceRoot'])) { + if (count($sourceMap['sources']) && empty($sourceMap['sourceRoot'])) { unset($sourceMap['sourceRoot']); } + return json_encode($sourceMap); } @@ -166,14 +198,18 @@ public function generateJson() { * * @return array|null */ - protected function getSourcesContent() { - if(empty($this->sources)) { + protected function getSourcesContent() + { + if (empty($this->sources)) { return null; } + $content = array(); - foreach($this->sources as $sourceFile) { + + foreach ($this->sources as $sourceFile) { $content[] = file_get_contents($sourceFile); } + return $content; } @@ -182,31 +218,41 @@ protected function getSourcesContent() { * * @return string */ - public function generateMappings() { - if(!count($this->mappings)) { + public function generateMappings() + { + if (! count($this->mappings)) { return ''; } + $this->source_keys = array_flip(array_keys($this->sources)); + // group mappings by generated line number. $groupedMap = $groupedMapEncoded = array(); - foreach($this->mappings as $m) { + + foreach ($this->mappings as $m) { $groupedMap[$m['generated_line']][] = $m; } + ksort($groupedMap); $lastGeneratedLine = $lastOriginalIndex = $lastOriginalLine = $lastOriginalColumn = 0; - foreach($groupedMap as $lineNumber => $line_map) { - while(++$lastGeneratedLine < $lineNumber) { + + foreach ($groupedMap as $lineNumber => $line_map) { + while (++$lastGeneratedLine < $lineNumber) { $groupedMapEncoded[] = ';'; } + $lineMapEncoded = array(); $lastGeneratedColumn = 0; - foreach($line_map as $m) { + + foreach ($line_map as $m) { $mapEncoded = $this->encoder->encode($m['generated_column'] - $lastGeneratedColumn); $lastGeneratedColumn = $m['generated_column']; + // find the index - if($m['source_file']) { + if ($m['source_file']) { $index = $this->findFileIndex($m['source_file']); - if($index !== false) { + + if ($index !== false) { $mapEncoded .= $this->encoder->encode($index - $lastOriginalIndex); $lastOriginalIndex = $index; // lines are stored 0-based in SourceMap spec version 3 @@ -216,10 +262,13 @@ public function generateMappings() { $lastOriginalColumn = $m['original_column']; } } + $lineMapEncoded[] = $mapEncoded; } + $groupedMapEncoded[] = implode(',', $lineMapEncoded) . ';'; } + return rtrim(implode($groupedMapEncoded), ';'); } @@ -227,39 +276,50 @@ public function generateMappings() { * Finds the index for the filename * * @param string $filename + * * @return integer|false */ - protected function findFileIndex($filename) { + protected function findFileIndex($filename) + { return $this->source_keys[$filename]; } - protected function normalizeFilename($filename) { + protected function normalizeFilename($filename) + { $filename = $this->fixWindowsPath($filename); $rootpath = $this->options['sourceMapRootpath']; $basePath = $this->options['sourceMapBasepath']; + // "Trim" the 'sourceMapBasepath' from the output filename. - if(strpos($filename, $basePath) === 0) { + if (strpos($filename, $basePath) === 0) { $filename = substr($filename, strlen($basePath)); } + // Remove extra leading path separators. - if(strpos($filename, '\\') === 0 || strpos($filename, '/') === 0) { + if (strpos($filename, '\\') === 0 || strpos($filename, '/') === 0) { $filename = substr($filename, 1); } + return $rootpath . $filename; } /** - * fix windows paths - * @param string $path - * @param bool $addEndSlash + * Fix windows paths + * + * @param string $path + * @param boolean $addEndSlash + * * @return string */ - public function fixWindowsPath($path, $addEndSlash = false) { + public function fixWindowsPath($path, $addEndSlash = false) + { $slash = ($addEndSlash) ? '/' : ''; - if(!empty($path)) { + + if (! empty($path)) { $path = str_replace('\\', '/', $path); $path = rtrim($path, '/') . $slash; } + return $path; } } diff --git a/src/Util.php b/src/Util.php index b2a05db8..f5aca7a4 100644 --- a/src/Util.php +++ b/src/Util.php @@ -25,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 $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 \Leafo\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. * diff --git a/tests/ServerTest.php b/tests/ServerTest.php index fcaea917..290d8fbf 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -8,6 +8,7 @@ * * @link http://leafo.github.io/scssphp */ + namespace Leafo\ScssPhp\Tests; require_once __DIR__ . '/../example/Server.php'; From 266913f8bf86b0e6a144e75225c82dc12652bedc Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Tue, 19 Dec 2017 16:24:54 -0500 Subject: [PATCH 101/329] More coding style tweaks --- src/Compiler.php | 57 +++++++++++++--------------- src/Formatter.php | 8 ++-- src/Formatter/Nested.php | 1 + src/Parser.php | 2 +- src/SourceMap/Base64VLQEncoder.php | 19 +++++++--- src/SourceMap/SourceMapGenerator.php | 14 ++++--- src/Util.php | 16 +++++++- 7 files changed, 69 insertions(+), 48 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index 64399b2a..f12cf7ee 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -65,9 +65,9 @@ class Compiler const WITH_SUPPORTS = 4; const WITH_ALL = 7; - const SOURCE_MAP_NONE = 0; + const SOURCE_MAP_NONE = 0; const SOURCE_MAP_INLINE = 1; - const SOURCE_MAP_FILE = 2; + const SOURCE_MAP_FILE = 2; /** * @var array @@ -219,7 +219,7 @@ public function compile($code, $path = null) switch ($this->sourceMap) { case self::SOURCE_MAP_INLINE: - $sourceMapUrl = sprintf('data:application/json,%s', self::encodeURIComponent($sourceMap)); + $sourceMapUrl = sprintf('data:application/json,%s', Util::encodeURIComponent($sourceMap)); break; case self::SOURCE_MAP_FILE: @@ -305,14 +305,14 @@ protected function pushExtends($target, $origin, $block) protected function makeOutputBlock($type, $selectors = null) { $out = new OutputBlock; - $out->type = $type; - $out->lines = []; - $out->children = []; - $out->parent = $this->scope; - $out->selectors = $selectors; - $out->depth = $this->env->depth; - $out->sourceName = $this->env->block->sourceName; - $out->sourceLine = $this->env->block->sourceLine; + $out->type = $type; + $out->lines = []; + $out->children = []; + $out->parent = $this->scope; + $out->selectors = $selectors; + $out->depth = $this->env->depth; + $out->sourceName = $this->env->block->sourceName; + $out->sourceLine = $this->env->block->sourceLine; $out->sourceColumn = $this->env->block->sourceColumn; return $out; @@ -696,7 +696,7 @@ protected function compileMedia(Block $media) if ($needsWrap) { $wrapped = new Block; - $wrapped->sourceName = $media->sourceName; + $wrapped->sourceName = $media->sourceName; $wrapped->sourceIndex = $media->sourceIndex; $wrapped->sourceLine = $media->sourceLine; $wrapped->sourceColumn = $media->sourceColumn; @@ -1119,14 +1119,6 @@ protected function evalSelectors($selectors) return $selectors; } - /** - * @param array $sourceMapOptions - */ - public function setSourceMapOptions($sourceMapOptions) - { - $this->sourceMapOptions = $sourceMapOptions; - } - /** * Evaluate selector * @@ -3351,7 +3343,7 @@ public function setLineNumberStyle($lineNumberStyle) } /** - * Set source map option + * Enable/disable source maps * * @api * @@ -3362,6 +3354,18 @@ public function setSourceMap($sourceMap) $this->sourceMap = $sourceMap; } + /** + * Set source map options + * + * @api + * + * @param array $sourceMapOptions + */ + public function setSourceMapOptions($sourceMapOptions) + { + $this->sourceMapOptions = $sourceMapOptions; + } + /** * Register function * @@ -5188,7 +5192,7 @@ protected function libToLowerCase($args) $string = $this->coerceString($args[0]); $stringContent = $this->compileStringContent($string); - $string[2] = [mb_strtolower($stringContent)]; + $string[2] = [function_exists('mb_strtolower') ? mb_strtolower($stringContent) : strtolower($stringContent)]; return $string; } @@ -5199,7 +5203,7 @@ protected function libToUpperCase($args) $string = $this->coerceString($args[0]); $stringContent = $this->compileStringContent($string); - $string[2] = [mb_strtoupper($stringContent)]; + $string[2] = [function_exists('mb_strtoupper') ? mb_strtoupper($stringContent) : strtoupper($stringContent)]; return $string; } @@ -5319,11 +5323,4 @@ protected function libInspect($args) return $args[0]; } - - public static function encodeURIComponent($string) - { - $revert = array('%21' => '!', '%2A' => '*', '%27' => "'", '%28' => '(', '%29' => ')'); - - return strtr(rawurlencode($string), $revert); - } } diff --git a/src/Formatter.php b/src/Formatter.php index 68d20c88..4d2fdd08 100644 --- a/src/Formatter.php +++ b/src/Formatter.php @@ -66,7 +66,6 @@ abstract class Formatter */ protected $currentBlock; - /** * @var integer */ @@ -78,7 +77,7 @@ abstract class Formatter protected $currentColumn; /** - * @var SourceMapGenerator + * @var \Leafo\ScssPhp\SourceMap\SourceMapGenerator */ protected $sourceMapGenerator; @@ -223,11 +222,10 @@ protected function block(OutputBlock $block) * * @api * - * @param \Leafo\ScssPhp\Formatter\OutputBlock $block An abstract syntax tree + * @param \Leafo\ScssPhp\Formatter\OutputBlock $block An abstract syntax tree + * @param \Leafo\ScssPhp\SourceMap\SourceMapGenerator|null $sourceMapGenerator Optional source map generator * - * @param SourceMapGenerator|null $sourceMapGenerator * @return string - * @internal param bool $collectSourceMap */ public function format(OutputBlock $block, SourceMapGenerator $sourceMapGenerator = null) { diff --git a/src/Formatter/Nested.php b/src/Formatter/Nested.php index 7573a596..626fec13 100644 --- a/src/Formatter/Nested.php +++ b/src/Formatter/Nested.php @@ -12,6 +12,7 @@ namespace Leafo\ScssPhp\Formatter; use Leafo\ScssPhp\Formatter; +use Leafo\ScssPhp\Formatter\OutputBlock; /** * Nested formatter diff --git a/src/Parser.php b/src/Parser.php index cc0a51df..ccac0d3f 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -708,7 +708,7 @@ protected function pushBlock($selectors, $pos = 0) list($line, $column) = $this->getSourcePosition($pos); $b = new Block; - $b->sourceName = $this->sourceName; + $b->sourceName = $this->sourceName; $b->sourceLine = $line; $b->sourceColumn = $column; $b->sourceIndex = $this->sourceIndex; diff --git a/src/SourceMap/Base64VLQEncoder.php b/src/SourceMap/Base64VLQEncoder.php index d1d1ed2a..435a7c60 100644 --- a/src/SourceMap/Base64VLQEncoder.php +++ b/src/SourceMap/Base64VLQEncoder.php @@ -94,6 +94,7 @@ public function __construct() * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) * We generate the value for 32 bit machines, hence -2147483648 becomes 1, not 4294967297, * even on a 64 bit machine. + * * @param string $aValue */ public function toVLQSigned($aValue) @@ -110,6 +111,7 @@ public function toVLQSigned($aValue) * Hence * 1 becomes -2147483648 * even on a 64 bit machine. + * * @param integer $aValue */ public function fromVLQSigned($aValue) @@ -121,6 +123,7 @@ public function fromVLQSigned($aValue) * Return the base 64 VLQ encoded value. * * @param string $aValue The value to encode + * * @return string The encoded value */ public function encode($aValue) @@ -146,6 +149,7 @@ public function encode($aValue) * Return the value decoded from base 64 VLQ. * * @param string $encoded The encoded value to decode + * * @return integer The decoded value */ public function decode($encoded) @@ -167,6 +171,7 @@ public function decode($encoded) * * @param integer $a number to shift * @param integer $b number of bits to shift + * * @return integer */ public function zeroFill($a, $b) @@ -178,13 +183,15 @@ public function zeroFill($a, $b) * Encode single 6-bit digit as base64. * * @param integer $number + * * @return string - * @throws Exception If the number is invalid + * + * @throws \Exception If the number is invalid */ public function base64Encode($number) { if ($number < 0 || $number > 63) { - throw new Exception(sprintf('Invalid number "%s" given. Must be between 0 and 63.', $number)); + throw new \Exception(sprintf('Invalid number "%s" given. Must be between 0 and 63.', $number)); } return $this->intToCharMap[$number]; @@ -194,13 +201,15 @@ public function base64Encode($number) * Decode single 6-bit digit from base64 * * @param string $char - * @return number - * @throws Exception If the number is invalid + * + * @return integer + * + * @throws \Exception If the number is invalid */ public function base64Decode($char) { if (! array_key_exists($char, $this->charToIntMap)) { - throw new Exception(sprintf('Invalid base 64 digit "%s" given.', $char)); + throw new \Exception(sprintf('Invalid base 64 digit "%s" given.', $char)); } return $this->charToIntMap[$char]; diff --git a/src/SourceMap/SourceMapGenerator.php b/src/SourceMap/SourceMapGenerator.php index 31905b10..cbfaa7cf 100644 --- a/src/SourceMap/SourceMapGenerator.php +++ b/src/SourceMap/SourceMapGenerator.php @@ -101,11 +101,11 @@ public function __construct(array $options = []) /** * Adds a mapping * - * @param integer $generatedLine The line number in generated file + * @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 + * @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) { @@ -123,9 +123,10 @@ public function addMapping($generatedLine, $generatedColumn, $originalLine, $ori /** * Saves the source map to a file * - * @param string $file The absolute path to a file + * @param string $file The absolute path to a file * @param string $content The content to write - * @throws Exception If the file could not be saved + * + * @throws \Leafo\ScssPhp\Exception\CompilerException If the file could not be saved */ public function saveMap($content) { @@ -150,6 +151,7 @@ public function saveMap($content) * Generates the JSON source map * * @return string + * * @see https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit# */ public function generateJson() diff --git a/src/Util.php b/src/Util.php index f5aca7a4..d49b265c 100644 --- a/src/Util.php +++ b/src/Util.php @@ -15,7 +15,7 @@ use Leafo\ScssPhp\Exception\RangeException; /** - * Utilties + * Utilty functions * * @author Anthon Pang */ @@ -53,4 +53,18 @@ public static function checkRange($name, Range $range, $value, $unit = '') throw new RangeException("$name {$val} must be between {$range->first} and {$range->last}$unit"); } + + /** + * Encode URI component + * + * @param string $string + * + * @return string + */ + public static function encodeURIComponent($string) + { + $revert = array('%21' => '!', '%2A' => '*', '%27' => "'", '%28' => '(', '%29' => ')'); + + return strtr(rawurlencode($string), $revert); + } } From f92d3e46cf98f1ba7a6af0d8ceee1beeaff75827 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Tue, 19 Dec 2017 16:31:11 -0500 Subject: [PATCH 102/329] Version bump to v0.7.3; fixed #135 --- src/Version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Version.php b/src/Version.php index 0dd95fe6..e9c0218c 100644 --- a/src/Version.php +++ b/src/Version.php @@ -18,5 +18,5 @@ */ class Version { - const VERSION = 'v0.7.2'; + const VERSION = 'v0.7.3'; } From b373570479027fa226afec3762852e54ee560bdd Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Tue, 19 Dec 2017 16:45:24 -0500 Subject: [PATCH 103/329] Add --sourcemap flag to bin/pscss --- bin/pscss | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/bin/pscss b/bin/pscss index 70a2be3c..be1cb51c 100755 --- a/bin/pscss +++ b/bin/pscss @@ -32,6 +32,7 @@ $debugInfo = false; $lineNumbers = false; $ignoreErrors = false; $encoding = false; +$sourceMap = false; /** * Parse argument @@ -77,6 +78,7 @@ Options include: --iso8859-1 Use iso8859-1 encoding instead of utf-8 (default utf-8) --line-numbers Annotate selectors with comments referring to the source file and line number -p=precision Set decimal number precision (default 10) + --sourcemap Create source map file -T Dump formatted parse tree -v, --version Print the version @@ -108,6 +110,11 @@ EOT; continue; } + if ($argv[$i] === '--sourcemap') { + $sourceMap = true; + continue; + } + if ($argv[$i] === '-T') { $dumpTree = true; continue; @@ -193,6 +200,10 @@ if ($style) { $scss->setFormatter('Leafo\\ScssPhp\\Formatter\\' . ucfirst($style)); } +if ($sourceMap) { + $scss->setSourceMap(Compiler::SOURCE_MAP_FILE); +} + if ($encoding) { $scss->setEncoding($encoding); } From 1e862d7f28bbcce159e3c75eee8069e059f95563 Mon Sep 17 00:00:00 2001 From: dleffler Date: Wed, 20 Dec 2017 09:08:18 -0500 Subject: [PATCH 104/329] Fix/restore working source map generation in 0.7.3 --- src/SourceMap/SourceMapGenerator.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/SourceMap/SourceMapGenerator.php b/src/SourceMap/SourceMapGenerator.php index cbfaa7cf..3a55851a 100644 --- a/src/SourceMap/SourceMapGenerator.php +++ b/src/SourceMap/SourceMapGenerator.php @@ -174,9 +174,17 @@ public function generateJson() $root = $this->options['sourceRoot']; if ($root) { +// $sourceMap['sourceRoot'] = $root; + // A list of symbol names used by the 'mappings' entry. $sourceMap['names'] = array(); } + // A list of original sources used by the 'mappings' entry. + $sourceMap['sources'] = array(); + foreach($this->sources as $source_uri => $source_filename) { + $sourceMap['sources'][] = $this->normalizeFilename($source_filename); + } + // A string with the encoded mapping data. $sourceMap['mappings'] = $mappings; From e8e4df7c5447165638ac255bd86a08b093bc9fb0 Mon Sep 17 00:00:00 2001 From: dleffler Date: Wed, 20 Dec 2017 16:03:15 -0500 Subject: [PATCH 105/329] Regression fix last push to fix 0.7.3 source maps --- src/SourceMap/SourceMapGenerator.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/SourceMap/SourceMapGenerator.php b/src/SourceMap/SourceMapGenerator.php index 3a55851a..c0f96dab 100644 --- a/src/SourceMap/SourceMapGenerator.php +++ b/src/SourceMap/SourceMapGenerator.php @@ -172,11 +172,9 @@ public function generateJson() // An optional source root, useful for relocating source files on a server or removing repeated values in the // 'sources' entry. This value is prepended to the individual entries in the 'source' field. $root = $this->options['sourceRoot']; - if ($root) { -// $sourceMap['sourceRoot'] = $root; + $sourceMap['sourceRoot'] = $root; // A list of symbol names used by the 'mappings' entry. - $sourceMap['names'] = array(); } // A list of original sources used by the 'mappings' entry. @@ -184,6 +182,7 @@ public function generateJson() foreach($this->sources as $source_uri => $source_filename) { $sourceMap['sources'][] = $this->normalizeFilename($source_filename); } + $sourceMap['names'] = array(); // A string with the encoded mapping data. $sourceMap['mappings'] = $mappings; From 045f3087bcb7a293ca2f6da02109fa17d20834a5 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 20 Dec 2017 19:17:12 -0500 Subject: [PATCH 106/329] Update SourceMapGenerator.php --- src/SourceMap/SourceMapGenerator.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/SourceMap/SourceMapGenerator.php b/src/SourceMap/SourceMapGenerator.php index c0f96dab..08e06168 100644 --- a/src/SourceMap/SourceMapGenerator.php +++ b/src/SourceMap/SourceMapGenerator.php @@ -172,16 +172,19 @@ public function generateJson() // An optional source root, useful for relocating source files on a server or removing repeated values in the // 'sources' entry. This value is prepended to the individual entries in the 'source' field. $root = $this->options['sourceRoot']; + if ($root) { $sourceMap['sourceRoot'] = $root; - // A list of symbol names used by the 'mappings' entry. } // A list of original sources used by the 'mappings' entry. $sourceMap['sources'] = array(); - foreach($this->sources as $source_uri => $source_filename) { + + foreach ($this->sources as $source_uri => $source_filename) { $sourceMap['sources'][] = $this->normalizeFilename($source_filename); } + + // A list of symbol names used by the 'mappings' entry. $sourceMap['names'] = array(); // A string with the encoded mapping data. From d7296256bd1bfacb8bd24e69030fd5e187181835 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 20 Dec 2017 19:18:53 -0500 Subject: [PATCH 107/329] Version bump --- src/Version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Version.php b/src/Version.php index e9c0218c..6d07d5ab 100644 --- a/src/Version.php +++ b/src/Version.php @@ -18,5 +18,5 @@ */ class Version { - const VERSION = 'v0.7.3'; + const VERSION = 'v0.7.4'; } From 11f556571b2d4d531a6215398f39e313e48d1aa2 Mon Sep 17 00:00:00 2001 From: dleffler Date: Mon, 5 Feb 2018 09:23:38 -0500 Subject: [PATCH 108/329] Add option to pass a custom SourceMapGenerator object --- src/Compiler.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index f12cf7ee..35a3f866 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -207,8 +207,13 @@ public function compile($code, $path = null) $sourceMapGenerator = null; - if ($this->sourceMap && $this->sourceMap !== self::SOURCE_MAP_NONE) { - $sourceMapGenerator = new SourceMapGenerator($this->sourceMapOptions); + if ($this->sourceMap) { + if (is_object($this->sourceMap) && is_a($this->sourceMap, 'SourceMapGenerator')) { + $sourceMapGenerator = $this->sourceMap; + $this->sourceMap = self::SOURCE_MAP_FILE; + } elseif ($this->sourceMap !== self::SOURCE_MAP_NONE) { + $sourceMapGenerator = new SourceMapGenerator($this->sourceMapOptions); + } } $out = $this->formatter->format($this->scope, $sourceMapGenerator); From a73e32a5e110a8de9919939b3f5371d44c1299b5 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Tue, 6 Feb 2018 03:14:51 -0500 Subject: [PATCH 109/329] is_a() -> instanceof --- src/Compiler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compiler.php b/src/Compiler.php index 35a3f866..03c94d9a 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -208,7 +208,7 @@ public function compile($code, $path = null) $sourceMapGenerator = null; if ($this->sourceMap) { - if (is_object($this->sourceMap) && is_a($this->sourceMap, 'SourceMapGenerator')) { + if (is_object($this->sourceMap) && $this->sourceMap instanceof SourceMapGenerator) { $sourceMapGenerator = $this->sourceMap; $this->sourceMap = self::SOURCE_MAP_FILE; } elseif ($this->sourceMap !== self::SOURCE_MAP_NONE) { From 593b92929c3f0e9d82c84ace7d29e8550e386413 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Tue, 6 Feb 2018 03:19:06 -0500 Subject: [PATCH 110/329] No side-effect in abs(), ceil(), floor(), round(); fixes #551 --- src/Compiler.php | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index 03c94d9a..8da8be77 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -4740,36 +4740,32 @@ protected function libPercentage($args) protected function libRound($args) { $num = $args[0]; - $num[1] = round($num[1]); - return $num; + return new Node\Number(round($num[1]), $num[2]); } protected static $libFloor = ['value']; protected function libFloor($args) { $num = $args[0]; - $num[1] = floor($num[1]); - return $num; + return new Node\Number(floor($num[1]), $num[2]); } protected static $libCeil = ['value']; protected function libCeil($args) { $num = $args[0]; - $num[1] = ceil($num[1]); - return $num; + return new Node\Number(ceil($num[1]), $num[2]); } protected static $libAbs = ['value']; protected function libAbs($args) { $num = $args[0]; - $num[1] = abs($num[1]); - return $num; + return new Node\Number(abs($num[1]), $num[2]); } protected function libMin($args) From d3801706dbf2423a380b7815383c0cbc9203c58a Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Tue, 6 Feb 2018 03:50:15 -0500 Subject: [PATCH 111/329] `@for` with units; fixes #548 --- src/Compiler.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index 8da8be77..d46d5332 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -1772,9 +1772,18 @@ protected function compileChild($child, OutputBlock $out) list(, $for) = $child; $start = $this->reduce($for->start, true); + $end = $this->reduce($for->end, true); + + if ( ! ($start[2] == $end[2] || $end->unitless())) { + $this->throwError('Incompatible units: "%s" and "%s".', $start->unitStr(), $end->unitStr()); + + break; + } + + $unit = $start[2]; $start = $start[1]; - $end = $this->reduce($for->end, true); - $end = $end[1]; + $end = $end[1]; + $d = $start < $end ? 1 : -1; for (;;) { @@ -1784,7 +1793,7 @@ protected function compileChild($child, OutputBlock $out) break; } - $this->set($for->var, new Node\Number($start, '')); + $this->set($for->var, new Node\Number($start, $unit)); $start += $d; $ret = $this->compileChildren($for->children, $out); From a4b566f0571f63a2cc00ee03025f6a498092383f Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Tue, 6 Feb 2018 04:03:48 -0500 Subject: [PATCH 112/329] Update docblocks --- src/Base/Range.php | 2 +- src/Block.php | 2 +- src/Colors.php | 2 +- src/Compiler.php | 4 ++-- src/Compiler/Environment.php | 2 +- src/Exception/CompilerException.php | 2 +- src/Exception/ParserException.php | 2 +- src/Exception/RangeException.php | 2 +- src/Exception/ServerException.php | 2 +- src/Formatter.php | 2 +- src/Formatter/Compact.php | 2 +- src/Formatter/Compressed.php | 2 +- src/Formatter/Crunched.php | 2 +- src/Formatter/Debug.php | 2 +- src/Formatter/Expanded.php | 2 +- src/Formatter/Nested.php | 2 +- src/Formatter/OutputBlock.php | 2 +- src/Node.php | 2 +- src/Node/Number.php | 2 +- src/Parser.php | 2 +- src/SourceMap/Base64VLQEncoder.php | 2 +- src/SourceMap/SourceMapGenerator.php | 2 +- src/Type.php | 2 +- src/Util.php | 2 +- src/Version.php | 2 +- 25 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/Base/Range.php b/src/Base/Range.php index 3f3a067d..8bcc6ecf 100644 --- a/src/Base/Range.php +++ b/src/Base/Range.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2017 Leaf Corcoran + * @copyright 2015-2018 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Block.php b/src/Block.php index fc21e5a4..a6ef8e03 100644 --- a/src/Block.php +++ b/src/Block.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2017 Leaf Corcoran + * @copyright 2012-2018 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Colors.php b/src/Colors.php index 61a71ab6..2314ea58 100644 --- a/src/Colors.php +++ b/src/Colors.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2017 Leaf Corcoran + * @copyright 2012-2018 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Compiler.php b/src/Compiler.php index d46d5332..292e960e 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2017 Leaf Corcoran + * @copyright 2012-2018 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * @@ -1774,7 +1774,7 @@ protected function compileChild($child, OutputBlock $out) $start = $this->reduce($for->start, true); $end = $this->reduce($for->end, true); - if ( ! ($start[2] == $end[2] || $end->unitless())) { + if (! ($start[2] == $end[2] || $end->unitless())) { $this->throwError('Incompatible units: "%s" and "%s".', $start->unitStr(), $end->unitStr()); break; diff --git a/src/Compiler/Environment.php b/src/Compiler/Environment.php index b4b86e32..fe309dd3 100644 --- a/src/Compiler/Environment.php +++ b/src/Compiler/Environment.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2017 Leaf Corcoran + * @copyright 2012-2018 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Exception/CompilerException.php b/src/Exception/CompilerException.php index 45fc1671..7ca2e2b3 100644 --- a/src/Exception/CompilerException.php +++ b/src/Exception/CompilerException.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2017 Leaf Corcoran + * @copyright 2012-2018 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Exception/ParserException.php b/src/Exception/ParserException.php index c0ee002d..6d64335f 100644 --- a/src/Exception/ParserException.php +++ b/src/Exception/ParserException.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2017 Leaf Corcoran + * @copyright 2012-2018 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Exception/RangeException.php b/src/Exception/RangeException.php index 47192ff5..3ba6bf14 100644 --- a/src/Exception/RangeException.php +++ b/src/Exception/RangeException.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2017 Leaf Corcoran + * @copyright 2012-2018 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Exception/ServerException.php b/src/Exception/ServerException.php index 68d3a290..d0ed0842 100644 --- a/src/Exception/ServerException.php +++ b/src/Exception/ServerException.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2017 Leaf Corcoran + * @copyright 2012-2018 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Formatter.php b/src/Formatter.php index 4d2fdd08..b4f90aa9 100644 --- a/src/Formatter.php +++ b/src/Formatter.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2017 Leaf Corcoran + * @copyright 2012-2018 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Formatter/Compact.php b/src/Formatter/Compact.php index aaf972b7..4efa1a08 100644 --- a/src/Formatter/Compact.php +++ b/src/Formatter/Compact.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2017 Leaf Corcoran + * @copyright 2012-2018 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Formatter/Compressed.php b/src/Formatter/Compressed.php index 21cbf28e..1faa7e11 100644 --- a/src/Formatter/Compressed.php +++ b/src/Formatter/Compressed.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2017 Leaf Corcoran + * @copyright 2012-2018 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Formatter/Crunched.php b/src/Formatter/Crunched.php index 43d63833..42d77b5f 100644 --- a/src/Formatter/Crunched.php +++ b/src/Formatter/Crunched.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2017 Leaf Corcoran + * @copyright 2012-2018 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Formatter/Debug.php b/src/Formatter/Debug.php index b31c8c7a..bfcbf41a 100644 --- a/src/Formatter/Debug.php +++ b/src/Formatter/Debug.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2017 Leaf Corcoran + * @copyright 2012-2018 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Formatter/Expanded.php b/src/Formatter/Expanded.php index 0449787d..d8c1e887 100644 --- a/src/Formatter/Expanded.php +++ b/src/Formatter/Expanded.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2017 Leaf Corcoran + * @copyright 2012-2018 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Formatter/Nested.php b/src/Formatter/Nested.php index 626fec13..8f72206f 100644 --- a/src/Formatter/Nested.php +++ b/src/Formatter/Nested.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2017 Leaf Corcoran + * @copyright 2012-2018 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Formatter/OutputBlock.php b/src/Formatter/OutputBlock.php index e4092175..5eb589c9 100644 --- a/src/Formatter/OutputBlock.php +++ b/src/Formatter/OutputBlock.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2017 Leaf Corcoran + * @copyright 2012-2018 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Node.php b/src/Node.php index eb543c73..b9f7945a 100644 --- a/src/Node.php +++ b/src/Node.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2017 Leaf Corcoran + * @copyright 2012-2018 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Node/Number.php b/src/Node/Number.php index efa83f5b..42c16803 100644 --- a/src/Node/Number.php +++ b/src/Node/Number.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2017 Leaf Corcoran + * @copyright 2012-2018 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Parser.php b/src/Parser.php index ccac0d3f..6fdea3e2 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2017 Leaf Corcoran + * @copyright 2012-2018 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/SourceMap/Base64VLQEncoder.php b/src/SourceMap/Base64VLQEncoder.php index 435a7c60..1189ce0e 100644 --- a/src/SourceMap/Base64VLQEncoder.php +++ b/src/SourceMap/Base64VLQEncoder.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2017 Leaf Corcoran + * @copyright 2012-2018 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/SourceMap/SourceMapGenerator.php b/src/SourceMap/SourceMapGenerator.php index 08e06168..70b47cdc 100644 --- a/src/SourceMap/SourceMapGenerator.php +++ b/src/SourceMap/SourceMapGenerator.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2017 Leaf Corcoran + * @copyright 2012-2018 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Type.php b/src/Type.php index 2d659e4d..e84c47e4 100644 --- a/src/Type.php +++ b/src/Type.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2017 Leaf Corcoran + * @copyright 2012-2018 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Util.php b/src/Util.php index d49b265c..7526e020 100644 --- a/src/Util.php +++ b/src/Util.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2017 Leaf Corcoran + * @copyright 2012-2018 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * diff --git a/src/Version.php b/src/Version.php index 6d07d5ab..2bda80ff 100644 --- a/src/Version.php +++ b/src/Version.php @@ -2,7 +2,7 @@ /** * SCSSPHP * - * @copyright 2012-2017 Leaf Corcoran + * @copyright 2012-2018 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * From 8b538d828bbb75276974605c4a1a435e939da74e Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Thu, 8 Feb 2018 21:04:21 -0500 Subject: [PATCH 113/329] Bump version --- src/Version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Version.php b/src/Version.php index 2bda80ff..3b8dcd00 100644 --- a/src/Version.php +++ b/src/Version.php @@ -18,5 +18,5 @@ */ class Version { - const VERSION = 'v0.7.4'; + const VERSION = 'v0.7.5'; } From 9410cbb398d17b096ce4bdd533f1712a651aca3d Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 28 Feb 2018 23:06:40 -0500 Subject: [PATCH 114/329] Fixes #559 - mix() fix --- src/Compiler.php | 2 +- tests/inputs/functions.scss | 9 ++++++++- tests/outputs/functions.css | 3 +++ tests/outputs_numbered/functions.css | 3 +++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index 292e960e..698d4d89 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -4526,7 +4526,7 @@ protected function libMix($args) ]; if ($firstAlpha != 1.0 || $secondAlpha != 1.0) { - $new[] = $firstAlpha * $weight + $secondAlpha * ($weight - 1); + $new[] = $firstAlpha * $weight + $secondAlpha * (1 - $weight); } return $this->fixColor($new); diff --git a/tests/inputs/functions.scss b/tests/inputs/functions.scss index bf3edf1f..9ebd544f 100644 --- a/tests/inputs/functions.scss +++ b/tests/inputs/functions.scss @@ -165,4 +165,11 @@ $str: 'global'; div { margin: mapping(one two); @include test(); -} \ No newline at end of file +} + +$a: rgba(#000, 0.5); +$b: rgba(#fff, 0.75); + +.test { + color: mix($a, $b); +} diff --git a/tests/outputs/functions.css b/tests/outputs/functions.css index aa0bebbb..e89beb8f 100644 --- a/tests/outputs/functions.css +++ b/tests/outputs/functions.css @@ -49,3 +49,6 @@ p { div { margin: 1px 1px 2px 2px; padding: 1px 1px 2px 2px; } + +.test { + color: rgba(159, 159, 159, 0.625); } diff --git a/tests/outputs_numbered/functions.css b/tests/outputs_numbered/functions.css index 6583ff05..6841fa05 100644 --- a/tests/outputs_numbered/functions.css +++ b/tests/outputs_numbered/functions.css @@ -51,3 +51,6 @@ p { div { margin: 1px 1px 2px 2px; padding: 1px 1px 2px 2px; } +/* line 173, inputs/functions.scss */ +.test { + color: rgba(159, 159, 159, 0.625); } From 847f9f2d6cb64042ed6ca91938f8aa7d20dcadba Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Thu, 19 Apr 2018 11:42:23 -0400 Subject: [PATCH 115/329] fixes #568 example/Server: set default timezone to UTC --- example/Server.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/example/Server.php b/example/Server.php index a8dc0457..6ea97018 100644 --- a/example/Server.php +++ b/example/Server.php @@ -207,7 +207,7 @@ protected function compile($in, $out) $elapsed = round((microtime(true) - $start), 4); $v = Version::VERSION; - $t = date('r'); + $t = gmdate('r'); $css = "/* compiled by scssphp $v on $t (${elapsed}s) */\n\n" . $css; $etag = md5($css); @@ -329,7 +329,7 @@ public function serve($salt = '') try { list($css, $etag) = $this->compile($input, $output); - $lastModified = gmdate('D, d M Y H:i:s', filemtime($output)) . ' GMT'; + $lastModified = gmdate('r', filemtime($output)); header('Last-Modified: ' . $lastModified); header('Content-type: text/css'); @@ -371,7 +371,7 @@ public function serve($salt = '') return; } - $lastModified = gmdate('D, d M Y H:i:s', $mtime) . ' GMT'; + $lastModified = gmdate('r', $mtime); header('Last-Modified: ' . $lastModified); echo file_get_contents($output); @@ -510,8 +510,6 @@ public function __construct($dir, $cacheDir = null, $scss = null) $this->scss = $scss; $this->showErrorsAsCSS = false; - if (! ini_get('date.timezone')) { - throw new ServerException('Default date.timezone not set'); - } + date_default_timezone_set('UTC'); } } From 53bb5275a7e3fad3676f1e01f3014d39a0c6d675 Mon Sep 17 00:00:00 2001 From: AzJezz Date: Sun, 29 Apr 2018 16:32:07 +0100 Subject: [PATCH 116/329] Update Compiler.php --- src/Compiler.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index 698d4d89..32e9b774 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -316,10 +316,15 @@ protected function makeOutputBlock($type, $selectors = null) $out->parent = $this->scope; $out->selectors = $selectors; $out->depth = $this->env->depth; - $out->sourceName = $this->env->block->sourceName; - $out->sourceLine = $this->env->block->sourceLine; - $out->sourceColumn = $this->env->block->sourceColumn; - + if($this->env->block instanceof Block) { + $out->sourceName = $this->env->block->sourceName; + $out->sourceLine = $this->env->block->sourceLine; + $out->sourceColumn = $this->env->block->sourceColumn; + } else { + $out->sourceName = null; + $out->sourceLine = null; + $out->sourceColum = null; + } return $out; } From ddebe1a68a53c4b8524c03f8cb2c24174cb028dc Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Fri, 18 May 2018 14:48:28 -0400 Subject: [PATCH 117/329] Fix #573 --- src/Compiler.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index 32e9b774..1aad621b 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -2699,7 +2699,9 @@ public function compileValue($value) $b = round($b); if (count($value) === 5 && $value[4] !== 1) { // rgba - return 'rgba(' . $r . ', ' . $g . ', ' . $b . ', ' . $value[4] . ')'; + $a = new Node\Number($value[4]); + + return 'rgba(' . $r . ', ' . $g . ', ' . $b . ', ' . $a . ')'; } $h = sprintf('#%02x%02x%02x', $r, $g, $b); @@ -4336,7 +4338,7 @@ protected function libRgb($args) protected function libRgba($args) { if ($color = $this->coerceColor($args[0])) { - $num = ! isset($args[1]) ? $args[3] : $args[1]; + $num = isset($args[3]) ? $args[3] : $args[1]; $alpha = $this->assertNumber($num); $color[4] = $alpha; From 57292fba51af83b0e812bc1cb31c7816b3f61936 Mon Sep 17 00:00:00 2001 From: Tim Elsass Date: Sun, 20 May 2018 00:52:50 -0400 Subject: [PATCH 118/329] Fix #575 --- src/Compiler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compiler.php b/src/Compiler.php index 1aad621b..746c6422 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -2699,7 +2699,7 @@ public function compileValue($value) $b = round($b); if (count($value) === 5 && $value[4] !== 1) { // rgba - $a = new Node\Number($value[4]); + $a = new Node\Number($value[4],''); return 'rgba(' . $r . ', ' . $g . ', ' . $b . ', ' . $a . ')'; } From 04482345fc0dd1b5305bcd5032ac4deb8a9ebbeb Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Sun, 20 May 2018 10:11:19 -0400 Subject: [PATCH 119/329] Update Compiler.php --- src/Compiler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compiler.php b/src/Compiler.php index 746c6422..b727f178 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -2699,7 +2699,7 @@ public function compileValue($value) $b = round($b); if (count($value) === 5 && $value[4] !== 1) { // rgba - $a = new Node\Number($value[4],''); + $a = new Node\Number($value[4], ''); return 'rgba(' . $r . ', ' . $g . ', ' . $b . ', ' . $a . ')'; } From 1a819c3b926c251891ede7c6bd12d91e403dc384 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 23 May 2018 18:05:54 -0400 Subject: [PATCH 120/329] Fix phpcs warnings --- src/Compiler.php | 4 ++-- src/Parser.php | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index b727f178..bfda455f 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -316,14 +316,14 @@ protected function makeOutputBlock($type, $selectors = null) $out->parent = $this->scope; $out->selectors = $selectors; $out->depth = $this->env->depth; - if($this->env->block instanceof Block) { + if ($this->env->block instanceof Block) { $out->sourceName = $this->env->block->sourceName; $out->sourceLine = $this->env->block->sourceLine; $out->sourceColumn = $this->env->block->sourceColumn; } else { $out->sourceName = null; $out->sourceLine = null; - $out->sourceColum = null; + $out->sourceColum = null; } return $out; } diff --git a/src/Parser.php b/src/Parser.php index 6fdea3e2..b8bfdc36 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -1302,6 +1302,21 @@ protected function value(&$out) { $s = $this->seek(); + if ($this->literal('url(') && $this->match('data:image\/([a-z0-9+-]+);base64,', $m, false)) { + $len = strspn($this->buffer, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwyxz0123456789+/=', $this->count); + + $this->count += $len; + + if ($this->literal(')')) { + $content = substr($this->buffer, $s, $this->count - $s); + $out = [Type::T_KEYWORD, $content]; + + return true; + } + } + + $this->seek($s); + if ($this->literal('not', false) && $this->whitespace() && $this->value($inner)) { $out = [Type::T_UNARY, 'not', $inner, $this->inParens]; From e94a5c21addf8541a710d5ac6507532118ba3295 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 23 May 2018 18:12:08 -0400 Subject: [PATCH 121/329] Refs #527 - parsing base64 --- src/Parser.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Parser.php b/src/Parser.php index b8bfdc36..de86f094 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -1302,7 +1302,7 @@ protected function value(&$out) { $s = $this->seek(); - if ($this->literal('url(') && $this->match('data:image\/([a-z0-9+-]+);base64,', $m, false)) { + if ($this->literal('url(') && $this->match('data:([a-z]+)\/([a-z0-9.+-]+);base64,', $m, false)) { $len = strspn($this->buffer, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwyxz0123456789+/=', $this->count); $this->count += $len; From deaf1dede19347fed905931ad80b495b077e4220 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 23 May 2018 21:33:11 -0400 Subject: [PATCH 122/329] Fix typo --- src/Compiler.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Compiler.php b/src/Compiler.php index bfda455f..72df991e 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -316,6 +316,7 @@ protected function makeOutputBlock($type, $selectors = null) $out->parent = $this->scope; $out->selectors = $selectors; $out->depth = $this->env->depth; + if ($this->env->block instanceof Block) { $out->sourceName = $this->env->block->sourceName; $out->sourceLine = $this->env->block->sourceLine; @@ -323,8 +324,9 @@ protected function makeOutputBlock($type, $selectors = null) } else { $out->sourceName = null; $out->sourceLine = null; - $out->sourceColum = null; + $out->sourceColumn = null; } + return $out; } From 585f6ae84de62ffecf69c23805f25d78d7e4b794 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 23 May 2018 22:18:53 -0400 Subject: [PATCH 123/329] Bump version --- src/Version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Version.php b/src/Version.php index 3b8dcd00..c8a56a5b 100644 --- a/src/Version.php +++ b/src/Version.php @@ -18,5 +18,5 @@ */ class Version { - const VERSION = 'v0.7.5'; + const VERSION = 'v0.7.6'; } From 0b94ebc2b0e61e797bfc0cb74acab5f3e95a09fd Mon Sep 17 00:00:00 2001 From: Stephan Date: Sun, 10 Jun 2018 01:09:50 +0200 Subject: [PATCH 124/329] Actually merge maps instead of just concatenating --- src/Compiler.php | 12 +++++++++++- tests/inputs/map.scss | 5 +++-- tests/outputs/map.css | 4 ++++ tests/outputs_numbered/map.css | 10 ++++++++-- 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index 72df991e..8551f001 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -4985,7 +4985,17 @@ protected function libMapMerge($args) $map1 = $this->assertMap($args[0]); $map2 = $this->assertMap($args[1]); - return [Type::T_MAP, array_merge($map1[1], $map2[1]), array_merge($map1[2], $map2[2])]; + foreach ($map2[1] as $i2 => $key2) { + foreach ($map1[1] as $i1 => $key1) { + if ($this->compileStringContent($this->coerceString($key1)) === $this->compileStringContent($this->coerceString($key2))) { + $map1[2][$i1] = $map2[2][$i2]; + continue 2; + } + } + $map1[1][] = $map2[1][$i2]; + $map1[2][] = $map2[2][$i2]; + } + return $map1; } protected static $libKeywords = ['args']; diff --git a/tests/inputs/map.scss b/tests/inputs/map.scss index 0fb6be19..7f8adeba 100644 --- a/tests/inputs/map.scss +++ b/tests/inputs/map.scss @@ -25,9 +25,10 @@ div { bar: nth(nth($map, 1), 1); } -$color: ("black" : #000000); +$color: ("black" : #000000, "grey" : #777777); +$color2: ("grey" : #888888, "white" : #ffffff); -@each $color_name, $color_value in $color { +@each $color_name, $color_value in map_merge( $color, $color2 ) { .#{$color_name} { background-color: $color_value !important; } diff --git a/tests/outputs/map.css b/tests/outputs/map.css index 9c38094a..a8898915 100644 --- a/tests/outputs/map.css +++ b/tests/outputs/map.css @@ -12,6 +12,10 @@ div { bar: color; } .black { background-color: #000 !important; } + .grey { + background-color: #888 !important; } + .white { + background-color: #fff !important; } div { a: 1; diff --git a/tests/outputs_numbered/map.css b/tests/outputs_numbered/map.css index 16de52b9..23c144fb 100644 --- a/tests/outputs_numbered/map.css +++ b/tests/outputs_numbered/map.css @@ -11,10 +11,16 @@ div { div { foo: color black; bar: color; } -/* line 31, inputs/map.scss */ +/* line 32, inputs/map.scss */ .black { background-color: #000 !important; } -/* line 52, inputs/map.scss */ +/* line 32, inputs/map.scss */ +.grey { + background-color: #888 !important; } +/* line 32, inputs/map.scss */ +.white { + background-color: #fff !important; } +/* line 53, inputs/map.scss */ div { a: 1; b: 2; From 4963903c0a88db128026f1a78de205a7153d4b48 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Tue, 19 Jun 2018 18:06:25 -0400 Subject: [PATCH 125/329] #569 attempt to fix call() with ellipsis --- src/Compiler.php | 38 +++++++++++++++++++++-------- tests/inputs/builtins.scss | 20 +++++++++++++++ tests/outputs/builtins.css | 12 +++++++++ tests/outputs_numbered/builtins.css | 12 +++++++++ 4 files changed, 72 insertions(+), 10 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index 72df991e..7d8db736 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -3655,7 +3655,7 @@ protected function callNativeFunction($name, $args, &$returnValue) return false; } - list($sorted, $kwargs) = $this->sortArgs($prototype, $args); + @list($sorted, $kwargs) = $this->sortArgs($prototype, $args); if ($name !== 'if' && $name !== 'call') { foreach ($sorted as &$val) { @@ -3714,7 +3714,7 @@ protected function sortArgs($prototype, $args) $key = $key[1]; if (empty($key)) { - $posArgs[] = $value; + $posArgs[] = empty($arg[2]) ? $value : $arg; } else { $keyArgs[$key] = $value; } @@ -4266,20 +4266,38 @@ protected function libCall($args, $kwargs) { $name = $this->compileStringContent($this->coerceString($this->reduce(array_shift($args), true))); - $args = array_map( - function ($a) { - return [null, $a, false]; - }, - $args - ); + $posArgs = []; + + foreach ($args as $arg) { + if (empty($arg[0])) { + if ($arg[2] === true) { + $tmp = $this->reduce($arg[1]); + + if ($tmp[0] === Type::T_LIST) { + foreach ($tmp[2] as $item) { + $posArgs[] = [null, $item, false]; + } + } else { + $posArgs[] = [null, $tmp, true]; + } + + continue; + } + + $posArgs[] = [null, $this->reduce($arg), false]; + continue; + } + + $posArgs[] = [null, $arg, false]; + } if (count($kwargs)) { foreach ($kwargs as $key => $value) { - $args[] = [[Type::T_VARIABLE, $key], $value, false]; + $posArgs[] = [[Type::T_VARIABLE, $key], $value, false]; } } - return $this->reduce([Type::T_FUNCTION_CALL, $name, $args]); + return $this->reduce([Type::T_FUNCTION_CALL, $name, $posArgs]); } protected static $libIf = ['condition', 'if-true', 'if-false']; diff --git a/tests/inputs/builtins.scss b/tests/inputs/builtins.scss index a80db5b1..00cd3c63 100644 --- a/tests/inputs/builtins.scss +++ b/tests/inputs/builtins.scss @@ -216,3 +216,23 @@ $type: text; div.unquote-test { a: unquote('[type=\'#{$type}\']'); } + +.does-compile-1 { + color: call(lighten, #000, 40%); +} + +.does-compile-2 { + $color: #000; + $percent: 40%; + color: call(lighten, $color, $percent); +} + +.does-compile-3 { + $args: (#000, 40%); + color: call(lighten, nth($args, 1), nth($args, 2)); +} + +.does-compile-4 { + $args: (#000, 40%); + color: call(lighten, $args...); +} diff --git a/tests/outputs/builtins.css b/tests/outputs/builtins.css index 50e2a82e..db43727d 100644 --- a/tests/outputs/builtins.css +++ b/tests/outputs/builtins.css @@ -159,3 +159,15 @@ div.call-tests { div.unquote-test { a: [type='text']; } + +.does-compile-1 { + color: #666; } + +.does-compile-2 { + color: #666; } + +.does-compile-3 { + color: #666; } + +.does-compile-4 { + color: #666; } diff --git a/tests/outputs_numbered/builtins.css b/tests/outputs_numbered/builtins.css index 722c6af4..e84d727c 100644 --- a/tests/outputs_numbered/builtins.css +++ b/tests/outputs_numbered/builtins.css @@ -160,3 +160,15 @@ div.call-tests { /* line 216, inputs/builtins.scss */ div.unquote-test { a: [type='text']; } +/* line 220, inputs/builtins.scss */ +.does-compile-1 { + color: #666; } +/* line 224, inputs/builtins.scss */ +.does-compile-2 { + color: #666; } +/* line 230, inputs/builtins.scss */ +.does-compile-3 { + color: #666; } +/* line 235, inputs/builtins.scss */ +.does-compile-4 { + color: #666; } From 3d3fd508102242ab5744b91e51ff78e262db9467 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Tue, 19 Jun 2018 23:10:38 -0400 Subject: [PATCH 126/329] refs #548 - treat 0 as a special unitless number --- src/Compiler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compiler.php b/src/Compiler.php index 7d8db736..62d125d8 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -4856,7 +4856,7 @@ protected function getNormalizedNumbers($args) if (null === $unit) { $unit = $number[2]; $originalUnit = $item->unitStr(); - } elseif ($unit !== $number[2]) { + } elseif ($number[1] && $unit !== $number[2]) { $this->throwError('Incompatible units: "%s" and "%s".', $originalUnit, $item->unitStr()); break; } From 1d656f8c02a3a69404bba6b28ec4e06edddf0f49 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Sat, 21 Jul 2018 21:22:08 -0400 Subject: [PATCH 127/329] refs #578 peephole optimization --- src/Compiler.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Compiler.php b/src/Compiler.php index 414e4401..637f1c1c 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -5004,15 +5004,19 @@ protected function libMapMerge($args) $map2 = $this->assertMap($args[1]); foreach ($map2[1] as $i2 => $key2) { + $key = $this->compileStringContent($this->coerceString($key2)); + foreach ($map1[1] as $i1 => $key1) { - if ($this->compileStringContent($this->coerceString($key1)) === $this->compileStringContent($this->coerceString($key2))) { + if ($key === $this->compileStringContent($this->coerceString($key1))) { $map1[2][$i1] = $map2[2][$i2]; continue 2; } } + $map1[1][] = $map2[1][$i2]; $map1[2][] = $map2[2][$i2]; } + return $map1; } From b72d613f682b714f498412483aff353cde977c00 Mon Sep 17 00:00:00 2001 From: Jiong Ye Date: Fri, 17 Aug 2018 16:24:08 -0400 Subject: [PATCH 128/329] leafo/scssphp#581 generate inline sourcemap in commandline --- bin/pscss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/pscss b/bin/pscss index be1cb51c..ce80e6a9 100755 --- a/bin/pscss +++ b/bin/pscss @@ -201,7 +201,7 @@ if ($style) { } if ($sourceMap) { - $scss->setSourceMap(Compiler::SOURCE_MAP_FILE); + $scss->setSourceMap(Compiler::SOURCE_MAP_INLINE); } if ($encoding) { From a7be38d3dabb6d3c15e28073541163428ad819ab Mon Sep 17 00:00:00 2001 From: Bastian Rihm Date: Thu, 30 Aug 2018 14:43:47 +0200 Subject: [PATCH 129/329] #515 Fix backslash escape --- src/Parser.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Parser.php b/src/Parser.php index de86f094..748d38ae 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -1737,6 +1737,8 @@ protected function string(&$out) $content[] = $m[2] . '"'; } elseif ($this->literal("'", false)) { $content[] = $m[2] . "'"; + } elseif ($this->literal("\\", false)) { + $content[] = $m[2] . "\\"; } else { $content[] = $m[2]; } @@ -1753,7 +1755,9 @@ protected function string(&$out) $delim = '"'; foreach ($content as &$string) { - if ($string === "\\'") { + if ($string === "\\\\") { + $string = "\\"; + } elseif ($string === "\\'") { $string = "'"; } elseif ($string === '\\"') { $string = '"'; From 0b589890bfbdd2e14d272f78d9d49038c051f12c Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Tue, 24 Jul 2018 10:47:05 -0400 Subject: [PATCH 130/329] Bump version --- src/Version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Version.php b/src/Version.php index c8a56a5b..ec0fee6f 100644 --- a/src/Version.php +++ b/src/Version.php @@ -18,5 +18,5 @@ */ class Version { - const VERSION = 'v0.7.6'; + const VERSION = 'v0.7.8'; } From 2a88d3e9ba903e1568cda7cd33add91d093a639c Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 26 Sep 2018 16:46:29 -0400 Subject: [PATCH 131/329] Update unit tests (fixes #515) --- tests/inputs/builtins.scss | 1 + tests/outputs/builtins.css | 1 + tests/outputs_numbered/builtins.css | 27 ++++++++++++++------------- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/tests/inputs/builtins.scss b/tests/inputs/builtins.scss index 00cd3c63..c75a854e 100644 --- a/tests/inputs/builtins.scss +++ b/tests/inputs/builtins.scss @@ -78,6 +78,7 @@ color: quote("I do?"); color: str_index(abc, b); color: str_insert(string, insert, 2); + color: str_insert(string, "\\", 2); color: str_length(string); color: str_slice(string, 2, 4); color: str-slice(string, 2, 0); diff --git a/tests/outputs/builtins.css b/tests/outputs/builtins.css index db43727d..94f29b4e 100644 --- a/tests/outputs/builtins.css +++ b/tests/outputs/builtins.css @@ -53,6 +53,7 @@ color: "I do?"; color: 2; color: sinserttring; + color: s\\tring; color: 6; color: tri; color: trin; diff --git a/tests/outputs_numbered/builtins.css b/tests/outputs_numbered/builtins.css index e84d727c..559b6a30 100644 --- a/tests/outputs_numbered/builtins.css +++ b/tests/outputs_numbered/builtins.css @@ -54,6 +54,7 @@ color: "I do?"; color: 2; color: sinserttring; + color: s\\tring; color: 6; color: tri; color: trin; @@ -74,7 +75,7 @@ color: st; color: string; color: strin; } -/* line 105, inputs/builtins.scss */ +/* line 106, inputs/builtins.scss */ #number { color: 250%; color: 50%; @@ -86,7 +87,7 @@ width: 200%; bottom: 10px; padding: 3em 1in 96px 72pt; } -/* line 119, inputs/builtins.scss */ +/* line 120, inputs/builtins.scss */ #list { len: 3; len: 1; @@ -108,7 +109,7 @@ cool: great job one two three; zip: 1px solid, 2px dashed; zip: 1px solid red, 2px dashed green; } -/* line 155, inputs/builtins.scss */ +/* line 156, inputs/builtins.scss */ #introspection { t: number; t: string; @@ -128,47 +129,47 @@ c: true; c: false; c: true; } -/* line 179, inputs/builtins.scss */ +/* line 180, inputs/builtins.scss */ #if { color: yes; color: no; color: yes; color: yes; } -/* line 186, inputs/builtins.scss */ +/* line 187, inputs/builtins.scss */ .transparent { r: 0; g: 0; b: 0; a: 0; } -/* line 193, inputs/builtins.scss */ +/* line 194, inputs/builtins.scss */ .alpha { a: 1; a: 1; a: 1; a: 0.5; a: alpha(currentColor); } -/* line 202, inputs/builtins.scss */ +/* line 203, inputs/builtins.scss */ #exists { a: true; b: true; c: false; } -/* line 209, inputs/builtins.scss */ +/* line 210, inputs/builtins.scss */ div.call-tests { a: #0a64ff; b: #0058ef; c: b; } -/* line 216, inputs/builtins.scss */ +/* line 217, inputs/builtins.scss */ div.unquote-test { a: [type='text']; } -/* line 220, inputs/builtins.scss */ +/* line 221, inputs/builtins.scss */ .does-compile-1 { color: #666; } -/* line 224, inputs/builtins.scss */ +/* line 225, inputs/builtins.scss */ .does-compile-2 { color: #666; } -/* line 230, inputs/builtins.scss */ +/* line 231, inputs/builtins.scss */ .does-compile-3 { color: #666; } -/* line 235, inputs/builtins.scss */ +/* line 236, inputs/builtins.scss */ .does-compile-4 { color: #666; } From f893748cd4482051bc503064c6a4396b10280957 Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Wed, 26 Sep 2018 17:15:59 -0400 Subject: [PATCH 132/329] Add Base64VLQ encoder test (refs #600) --- tests/Base64VLQTest.php | 54 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 tests/Base64VLQTest.php diff --git a/tests/Base64VLQTest.php b/tests/Base64VLQTest.php new file mode 100644 index 00000000..21b373b8 --- /dev/null +++ b/tests/Base64VLQTest.php @@ -0,0 +1,54 @@ + + */ +class Base64VLQTest extends \PHPUnit_Framework_TestCase +{ + /** + * Test encode + * + * param string $expected + * param string $value + * + * @dataProvider getEncode + */ + public function testEncode($expected, $value) + { + $encoder = new Base64VLQEncoder; + + $this->assertEquals($expected, $encoder->encode($value)); + } + + /** + * Data provider for testEncode + * + * @return array + */ + public static function getEncode() + { + return [ + ['A', 0], + ['C', 1], + ['D', -1], + ['2H', 123], + ['qxmvrH', 123456789], + ['+/////D', 2147483647], // 2^31-1 + ]; + } +} From 0fcbdf599f9f8289d033f327532b6a2230b1d77f Mon Sep 17 00:00:00 2001 From: Anthon Pang Date: Sun, 30 Sep 2018 20:57:13 -0400 Subject: [PATCH 133/329] Fixes #600 - change Base64 VLQ encoder/decoder implementtion --- scss.inc.php | 3 +- src/SourceMap/Base64.php | 184 +++++++++++++++++++++++++++ src/SourceMap/Base64VLQ.php | 137 ++++++++++++++++++++ src/SourceMap/SourceMapGenerator.php | 4 +- tests/Base64VLQTest.php | 4 +- 5 files changed, 327 insertions(+), 5 deletions(-) create mode 100644 src/SourceMap/Base64.php create mode 100644 src/SourceMap/Base64VLQ.php diff --git a/scss.inc.php b/scss.inc.php index 13c84bf5..d75ecb55 100644 --- a/scss.inc.php +++ b/scss.inc.php @@ -24,7 +24,8 @@ include_once __DIR__ . '/src/Node.php'; include_once __DIR__ . '/src/Node/Number.php'; include_once __DIR__ . '/src/Parser.php'; - include_once __DIR__ . '/src/SourceMap/Base64VLQEncoder.php'; + include_once __DIR__ . '/src/SourceMap/Base64.php'; + include_once __DIR__ . '/src/SourceMap/Base64VLQ.php'; include_once __DIR__ . '/src/SourceMap/SourceMapGenerator.php'; include_once __DIR__ . '/src/Type.php'; include_once __DIR__ . '/src/Util.php'; diff --git a/src/SourceMap/Base64.php b/src/SourceMap/Base64.php new file mode 100644 index 00000000..9d17e6f0 --- /dev/null +++ b/src/SourceMap/Base64.php @@ -0,0 +1,184 @@ + + */ +class Base64 +{ + /** + * @var array + */ + private static $encodingMap = array ( + 0 => 'A', + 1 => 'B', + 2 => 'C', + 3 => 'D', + 4 => 'E', + 5 => 'F', + 6 => 'G', + 7 => 'H', + 8 => 'I', + 9 => 'J', + 10 => 'K', + 11 => 'L', + 12 => 'M', + 13 => 'N', + 14 => 'O', + 15 => 'P', + 16 => 'Q', + 17 => 'R', + 18 => 'S', + 19 => 'T', + 20 => 'U', + 21 => 'V', + 22 => 'W', + 23 => 'X', + 24 => 'Y', + 25 => 'Z', + 26 => 'a', + 27 => 'b', + 28 => 'c', + 29 => 'd', + 30 => 'e', + 31 => 'f', + 32 => 'g', + 33 => 'h', + 34 => 'i', + 35 => 'j', + 36 => 'k', + 37 => 'l', + 38 => 'm', + 39 => 'n', + 40 => 'o', + 41 => 'p', + 42 => 'q', + 43 => 'r', + 44 => 's', + 45 => 't', + 46 => 'u', + 47 => 'v', + 48 => 'w', + 49 => 'x', + 50 => 'y', + 51 => 'z', + 52 => '0', + 53 => '1', + 54 => '2', + 55 => '3', + 56 => '4', + 57 => '5', + 58 => '6', + 59 => '7', + 60 => '8', + 61 => '9', + 62 => '+', + 63 => '/', + ); + + /** + * @var array + */ + private static $decodingMap = array( + 'A' => 0, + 'B' => 1, + 'C' => 2, + 'D' => 3, + 'E' => 4, + 'F' => 5, + 'G' => 6, + 'H' => 7, + 'I' => 8, + 'J' => 9, + 'K' => 10, + 'L' => 11, + 'M' => 12, + 'N' => 13, + 'O' => 14, + 'P' => 15, + 'Q' => 16, + 'R' => 17, + 'S' => 18, + 'T' => 19, + 'U' => 20, + 'V' => 21, + 'W' => 22, + 'X' => 23, + 'Y' => 24, + 'Z' => 25, + 'a' => 26, + 'b' => 27, + 'c' => 28, + 'd' => 29, + 'e' => 30, + 'f' => 31, + 'g' => 32, + 'h' => 33, + 'i' => 34, + 'j' => 35, + 'k' => 36, + 'l' => 37, + 'm' => 38, + 'n' => 39, + 'o' => 40, + 'p' => 41, + 'q' => 42, + 'r' => 43, + 's' => 44, + 't' => 45, + 'u' => 46, + 'v' => 47, + 'w' => 48, + 'x' => 49, + 'y' => 50, + 'z' => 51, + 0 => 52, + 1 => 53, + 2 => 54, + 3 => 55, + 4 => 56, + 5 => 57, + 6 => 58, + 7 => 59, + 8 => 60, + 9 => 61, + '+' => 62, + '/' => 63, + ); + + /** + * Convert to base64 + * + * @param integer $value + * + * @return string + */ + public static function encode($value) + { + return self::$encodingMap[$value]; + } + + /** + * Convert from base64 + * + * @param string $value + * + * @return integer + */ + public static function decode($value) + { + return self::$decodingMap[$value]; + } +} diff --git a/src/SourceMap/Base64VLQ.php b/src/SourceMap/Base64VLQ.php new file mode 100644 index 00000000..6de3b5ee --- /dev/null +++ b/src/SourceMap/Base64VLQ.php @@ -0,0 +1,137 @@ + + * @author Anthon Pang + */ +class Base64VLQ +{ + // A Base64 VLQ digit can represent 5 bits, so it is base-32. + const VLQ_BASE_SHIFT = 5; + + // A mask of bits for a VLQ digit (11111), 31 decimal. + const VLQ_BASE_MASK = 31; + + // The continuation bit is the 6th bit. + const VLQ_CONTINUATION_BIT = 32; + + /** + * Returns the VLQ encoded value. + * + * @param integer $value + * + * @return string + */ + public static function encode($value) + { + $encoded = ''; + $vlq = self::toVLQSigned($value); + + do { + $digit = $vlq & self::VLQ_BASE_MASK; + $vlq >>= self::VLQ_BASE_SHIFT; + + if ($vlq > 0) { + $digit |= self::VLQ_CONTINUATION_BIT; + } + + $encoded .= Base64::encode($digit); + } while ($vlq > 0); + + return $encoded; + } + + /** + * Decodes VLQValue. + * + * @param string $str + * @param integer $index + * + * @return integer + */ + public static function decode($str, &$index) + { + $result = 0; + $shift = 0; + + do { + $c = $str[$index++]; + $digit = Base64::decode($c); + $continuation = ($digit & self::VLQ_CONTINUATION_BIT) != 0; + $digit &= self::VLQ_BASE_MASK; + $result = $result + ($digit << $shift); + $shift = $shift + self::VLQ_BASE_SHIFT; + } while ($continuation); + + return self::fromVLQSigned($result); + } + + /** + * Converts from a two-complement value to a value where the sign bit is + * is placed in the least significant bit. For example, as decimals: + * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) + * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) + * + * @param integer $value + * + * @return integer + */ + private static function toVLQSigned($value) + { + if ($value < 0) { + return ((-$value) << 1) + 1; + } + + return ($value << 1) + 0; + } + + /** + * Converts to a two-complement value from a value where the sign bit is + * is placed in the least significant bit. For example, as decimals: + * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 + * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 + * + * @param integer $value + * + * @return integer + */ + private static function fromVLQSigned($value) + { + $negate = ($value & 1) === 1; + $value = $value >> 1; + + return $negate ? -$value : $value; + } +} diff --git a/src/SourceMap/SourceMapGenerator.php b/src/SourceMap/SourceMapGenerator.php index 70b47cdc..6e969cae 100644 --- a/src/SourceMap/SourceMapGenerator.php +++ b/src/SourceMap/SourceMapGenerator.php @@ -61,7 +61,7 @@ class SourceMapGenerator /** * The base64 VLQ encoder * - * @var \Leafo\ScssPhp\SourceMap\Base64VLQEncoder + * @var \Leafo\ScssPhp\SourceMap\Base64VLQ */ protected $encoder; @@ -95,7 +95,7 @@ class SourceMapGenerator public function __construct(array $options = []) { $this->options = array_merge($this->defaultOptions, $options); - $this->encoder = new Base64VLQEncoder(); + $this->encoder = new Base64VLQ(); } /** diff --git a/tests/Base64VLQTest.php b/tests/Base64VLQTest.php index 21b373b8..a3b638de 100644 --- a/tests/Base64VLQTest.php +++ b/tests/Base64VLQTest.php @@ -11,7 +11,7 @@ namespace Leafo\ScssPhp\Tests; -use Leafo\ScssPhp\SourceMap\Base64VLQEncoder; +use Leafo\ScssPhp\SourceMap\Base64VLQ; /** * Base64VLQ encoder test @@ -30,7 +30,7 @@ class Base64VLQTest extends \PHPUnit_Framework_TestCase */ public function testEncode($expected, $value) { - $encoder = new Base64VLQEncoder; + $encoder = new Base64VLQ; $this->assertEquals($expected, $encoder->encode($value)); } From c1ca4095952a431d4847862e048715bc6fa331fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Nguyen?= Date: Thu, 11 Oct 2018 13:27:55 +0200 Subject: [PATCH 134/329] fix doc for addImportPath, should also accept callable as input --- src/Compiler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compiler.php b/src/Compiler.php index 637f1c1c..ed80d8d3 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -3308,7 +3308,7 @@ public function getParsedFiles() * * @api * - * @param string $path + * @param string|callable $path */ public function addImportPath($path) { From b931793663ac56d57d5f87f9f6f3f50cf6b73aa0 Mon Sep 17 00:00:00 2001 From: Geoff Willings Date: Tue, 23 Oct 2018 23:12:14 +0100 Subject: [PATCH 135/329] Bug fix error thrown from strpos if needle (basePath) is empty and ignore PhpStorm .idea IDE directory --- .gitignore | 1 + src/SourceMap/SourceMapGenerator.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index be6e5ecf..999984a4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.idea .sass-cache scss_cache composer.lock diff --git a/src/SourceMap/SourceMapGenerator.php b/src/SourceMap/SourceMapGenerator.php index 6e969cae..39bfac1c 100644 --- a/src/SourceMap/SourceMapGenerator.php +++ b/src/SourceMap/SourceMapGenerator.php @@ -303,7 +303,7 @@ protected function normalizeFilename($filename) $basePath = $this->options['sourceMapBasepath']; // "Trim" the 'sourceMapBasepath' from the output filename. - if (strpos($filename, $basePath) === 0) { + if (strlen($basePath) && strpos($filename, $basePath) === 0) { $filename = substr($filename, strlen($basePath)); } From a0e5590e65e33ad6c10e4c98e4aa7c8563779ee8 Mon Sep 17 00:00:00 2001 From: Geoff Willings Date: Wed, 24 Oct 2018 00:41:31 +0100 Subject: [PATCH 136/329] Fix bug where rooted SCSS URIs aren't normalised properly with baseUri provided --- src/Compiler.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index ed80d8d3..ee4efc96 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -3481,9 +3481,12 @@ public function findImport($url) if (is_string($dir)) { // check urls for normal import paths foreach ($urls as $full) { - $full = $dir - . (! empty($dir) && substr($dir, -1) !== '/' ? '/' : '') - . $full; + $separator = ( + !empty($dir) && + substr($dir, -1) !== '/' && + substr($full, 0, 1) !== '/' + ) ? '/' : ''; + $full = $dir . $separator . $full; if ($this->fileExists($file = $full . '.scss') || ($hasExtension && $this->fileExists($file = $full)) From 51041822ae0e8b646e7d86de6c6f81100345f939 Mon Sep 17 00:00:00 2001 From: Geoff Willings Date: Wed, 24 Oct 2018 00:42:04 +0100 Subject: [PATCH 137/329] Json preference to not escape slashes (opinionated) --- src/SourceMap/SourceMapGenerator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SourceMap/SourceMapGenerator.php b/src/SourceMap/SourceMapGenerator.php index 39bfac1c..7bb005c4 100644 --- a/src/SourceMap/SourceMapGenerator.php +++ b/src/SourceMap/SourceMapGenerator.php @@ -202,7 +202,7 @@ public function generateJson() unset($sourceMap['sourceRoot']); } - return json_encode($sourceMap); + return json_encode($sourceMap, JSON_UNESCAPED_SLASHES); } /** From 94261339c3b11fdec1d230c57a54084c34a8c824 Mon Sep 17 00:00:00 2001 From: Vince Date: Wed, 13 Mar 2019 14:54:47 -0700 Subject: [PATCH 138/329] Fix for "continue" causing a warning in PHP 7.3 "continue statements targeting switch control flow structures will now generate a warning. In PHP such continue statements are equivalent to break, while they behave as continue 2 in other languages." http://php.net/manual/en/migration73.incompatible.php "In PHP the switch statement is considered a looping structure for the purposes of continue. continue behaves like break (when no arguments are passed). If a switch is inside a loop, continue 2 will continue with the next iteration of the outer loop." http://php.net/manual/en/control-structures.continue.php Signed-off-by: Vince --- tests/ScssTest.php | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/tests/ScssTest.php b/tests/ScssTest.php index 96f0d76e..9c412fe3 100644 --- a/tests/ScssTest.php +++ b/tests/ScssTest.php @@ -75,7 +75,7 @@ public function provideTests() if (preg_match('/^\s*def test_([a-z_]+)/', $line, $matches)) { $state = 1; // enter function $name = $matches[1]; - continue; + continue 2; } break; @@ -83,7 +83,7 @@ public function provideTests() case 1: // inside function if ($line === '' || $line[0] === '#') { - continue; + continue 2; } if (preg_match('/= <<([A-Z_]+)\s*$/', $line, $matches) @@ -95,14 +95,14 @@ public function provideTests() ; } - continue; + continue 2; } if (preg_match('/^\s*assert_equal\(< e' ) { - continue; + continue 2; } if (preg_match('/^\s*end\s*$/', $line)) { @@ -168,7 +168,7 @@ public function provideTests() $scss = array(); $css = array(); $style = null; - continue; + continue 2; } $skipped[] = $line; @@ -179,9 +179,9 @@ public function provideTests() // get css if (preg_match('/^CSS\s*$/', $line)) { $state = 3; // get scss - continue; + continue 2; } - + $css[] = $lines[$i]; break; @@ -190,9 +190,9 @@ public function provideTests() // get scss if (preg_match('/^SCSS\s*$/', $line)) { $state = 1; // end of parameter list - continue; + continue 2; } - + $scss[] = $lines[$i]; break; @@ -201,12 +201,12 @@ public function provideTests() // inside block if (preg_match('/^\s*end\s*$/', $line)) { $state = 1; // end block - continue; + continue 2; } if (preg_match('/^\s*assert_equal < Date: Sun, 17 Mar 2019 23:23:12 +0200 Subject: [PATCH 139/329] Avoid infinitely duplicating parts when extending selector --- src/Compiler.php | 7 ++++++- tests/inputs/extending_compound_selector.scss | 19 +++++++++++++++++++ tests/outputs/extending_compound_selector.css | 4 ++++ .../extending_compound_selector.css | 11 +++++++++++ 4 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 tests/inputs/extending_compound_selector.scss create mode 100644 tests/outputs/extending_compound_selector.css create mode 100644 tests/outputs_numbered/extending_compound_selector.css diff --git a/src/Compiler.php b/src/Compiler.php index ed80d8d3..c73f5b02 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -463,7 +463,12 @@ protected function matchExtends($selector, &$out, $from = 0, $initial = true) $tempReplacement = $k > 0 ? array_slice($new, $k) : $new; for ($l = count($tempReplacement) - 1; $l >= 0; $l--) { - $slice = $tempReplacement[$l]; + $slice = []; + foreach ($tempReplacement[$l] as $chunk) { + if (!in_array($chunk, $slice)) { + $slice[] = $chunk; + } + } array_unshift($replacement, $slice); if (! $this->isImmediateRelationshipCombinator(end($slice))) { diff --git a/tests/inputs/extending_compound_selector.scss b/tests/inputs/extending_compound_selector.scss new file mode 100644 index 00000000..669591fd --- /dev/null +++ b/tests/inputs/extending_compound_selector.scss @@ -0,0 +1,19 @@ +.foo { + &:after { + color: red; + } + &:hover:after { + color: blue; + } +} + +.bar { + @extend .foo; + &:before { + @extend .bar:after; + } +} + +.baz.bar:before { + @extend .bar:before; +} diff --git a/tests/outputs/extending_compound_selector.css b/tests/outputs/extending_compound_selector.css new file mode 100644 index 00000000..7e8cb599 --- /dev/null +++ b/tests/outputs/extending_compound_selector.css @@ -0,0 +1,4 @@ +.foo:after, .bar:after, .bar:before, .baz.bar:before { + color: red; } + .foo:hover:after, .bar:hover:after, .bar:before:hover, .baz.bar:before:hover { + color: blue; } diff --git a/tests/outputs_numbered/extending_compound_selector.css b/tests/outputs_numbered/extending_compound_selector.css new file mode 100644 index 00000000..50685dcf --- /dev/null +++ b/tests/outputs_numbered/extending_compound_selector.css @@ -0,0 +1,11 @@ +/* line 1, inputs/extending_compound_selector.scss */ +/* line 2, inputs/extending_compound_selector.scss */ + .foo:after, .bar:after, .bar:before, .baz.bar:before { + color: red; } +/* line 5, inputs/extending_compound_selector.scss */ +.foo:hover:after, .bar:hover:after, .bar:before:hover, .baz.bar:before:hover { + color: blue; } +/* line 10, inputs/extending_compound_selector.scss */ +/* line 12, inputs/extending_compound_selector.scss */ + +/* line 17, inputs/extending_compound_selector.scss */ From 405ebd336c86b397841eb3d17af1aa9200ca2b41 Mon Sep 17 00:00:00 2001 From: Vjacheslav Trushkin Date: Sun, 17 Mar 2019 23:56:10 +0200 Subject: [PATCH 140/329] Change private properties to protected in compiler --- src/Compiler.php | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/Compiler.php b/src/Compiler.php index ed80d8d3..f9934aa2 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -145,18 +145,18 @@ class Compiler protected $charsetSeen; protected $sourceNames; - private $indentLevel; - private $commentsSeen; - private $extends; - private $extendsMap; - private $parsedFiles; - private $parser; - private $sourceIndex; - private $sourceLine; - private $sourceColumn; - private $stderr; - private $shouldEvaluate; - private $ignoreErrors; + protected $indentLevel; + protected $commentsSeen; + protected $extends; + protected $extendsMap; + protected $parsedFiles; + protected $parser; + protected $sourceIndex; + protected $sourceLine; + protected $sourceColumn; + protected $stderr; + protected $shouldEvaluate; + protected $ignoreErrors; /** * Constructor @@ -817,7 +817,7 @@ protected function compileAtRoot(Block $block) * * @return array */ - private function spliceTree($envs, Block $block, $without) + protected function spliceTree($envs, Block $block, $without) { $newBlock = null; @@ -894,7 +894,7 @@ private function spliceTree($envs, Block $block, $without) * * @return integer */ - private function compileWith($with) + protected function compileWith($with) { static $mapping = [ 'rule' => self::WITH_RULE, @@ -945,7 +945,7 @@ private function compileWith($with) * * @return \Leafo\ScssPhp\Compiler\Environment */ - private function filterWithout($envs, $without) + protected function filterWithout($envs, $without) { $filtered = []; @@ -968,7 +968,7 @@ private function filterWithout($envs, $without) * * @return boolean */ - private function isWithout($without, Block $block) + protected function isWithout($without, Block $block) { if ((($without & static::WITH_RULE) && isset($block->selectors)) || (($without & static::WITH_MEDIA) && @@ -2215,7 +2215,7 @@ protected function reduce($value, $inExp = false) * * @return array|null */ - private function fncall($name, $argValues) + protected function fncall($name, $argValues) { // SCSS @function if ($this->callScssFunction($name, $argValues, $returnValue)) { @@ -3016,7 +3016,7 @@ protected function multiplyMedia(Environment $env = null, $childQueries = null) * * @return array */ - private function compactEnv(Environment $env) + protected function compactEnv(Environment $env) { for ($envs = []; $env; $env = $env->parent) { $envs[] = $env; @@ -3032,7 +3032,7 @@ private function compactEnv(Environment $env) * * @return \Leafo\ScssPhp\Compiler\Environment */ - private function extractEnv($envs) + protected function extractEnv($envs) { for ($env = null; $e = array_pop($envs);) { $e->parent = $env; @@ -3864,7 +3864,7 @@ protected function applyArguments($argDef, $argValues) * * @return array|\Leafo\ScssPhp\Node\Number */ - private function coerceValue($value) + protected function coerceValue($value) { if (is_array($value) || $value instanceof \ArrayAccess) { return $value; @@ -4203,7 +4203,7 @@ public function toHSL($red, $green, $blue) * * @return float */ - private function hueToRGB($m1, $m2, $h) + protected function hueToRGB($m1, $m2, $h) { if ($h < 0) { $h += 1; From 20d88db8a832429c2a4cac035c32a63b968cb6f4 Mon Sep 17 00:00:00 2001 From: josh Date: Sun, 27 Dec 2015 13:30:27 -0700 Subject: [PATCH 141/329] add matchChar() --- src/Parser.php | 168 ++++++++++++++++++++++++++++--------------------- 1 file changed, 98 insertions(+), 70 deletions(-) diff --git a/src/Parser.php b/src/Parser.php index 748d38ae..5114cdab 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -286,7 +286,7 @@ protected function parseChunk() if ($this->literal('@at-root') && ($this->selectors($selector) || true) && ($this->map($with) || true) && - $this->literal('{') + $this->matchChar('{') ) { $atRoot = $this->pushSpecialBlock(Type::T_AT_ROOT, $s); $atRoot->selector = $selector; @@ -297,7 +297,7 @@ protected function parseChunk() $this->seek($s); - if ($this->literal('@media') && $this->mediaQueryList($mediaQueryList) && $this->literal('{')) { + if ($this->literal('@media') && $this->mediaQueryList($mediaQueryList) && $this->matchChar('{')) { $media = $this->pushSpecialBlock(Type::T_MEDIA, $s); $media->queryList = $mediaQueryList[2]; @@ -309,7 +309,7 @@ protected function parseChunk() if ($this->literal('@mixin') && $this->keyword($mixinName) && ($this->argumentDef($args) || true) && - $this->literal('{') + $this->matchChar('{') ) { $mixin = $this->pushSpecialBlock(Type::T_MIXIN, $s); $mixin->name = $mixinName; @@ -322,11 +322,11 @@ protected function parseChunk() if ($this->literal('@include') && $this->keyword($mixinName) && - ($this->literal('(') && + ($this->matchChar('(') && ($this->argValues($argValues) || true) && - $this->literal(')') || true) && + $this->matchChar(')') || true) && ($this->end() || - $this->literal('{') && $hasBlock = true) + $this->matchChar('{') && $hasBlock = true) ) { $child = [Type::T_INCLUDE, $mixinName, isset($argValues) ? $argValues : null, null]; @@ -391,7 +391,7 @@ protected function parseChunk() if ($this->literal('@function') && $this->keyword($fnName) && $this->argumentDef($args) && - $this->literal('{') + $this->matchChar('{') ) { $func = $this->pushSpecialBlock(Type::T_FUNCTION, $s); $func->name = $fnName; @@ -431,7 +431,7 @@ protected function parseChunk() $this->genericList($varNames, 'variable', ',', false) && $this->literal('in') && $this->valueList($list) && - $this->literal('{') + $this->matchChar('{') ) { $each = $this->pushSpecialBlock(Type::T_EACH, $s); @@ -448,7 +448,7 @@ protected function parseChunk() if ($this->literal('@while') && $this->expression($cond) && - $this->literal('{') + $this->matchChar('{') ) { $while = $this->pushSpecialBlock(Type::T_WHILE, $s); $while->cond = $cond; @@ -465,7 +465,7 @@ protected function parseChunk() ($this->literal('through') || ($forUntil = true && $this->literal('to'))) && $this->expression($end) && - $this->literal('{') + $this->matchChar('{') ) { $for = $this->pushSpecialBlock(Type::T_FOR, $s); $for->var = $varName[1]; @@ -478,7 +478,7 @@ protected function parseChunk() $this->seek($s); - if ($this->literal('@if') && $this->valueList($cond) && $this->literal('{')) { + if ($this->literal('@if') && $this->valueList($cond) && $this->matchChar('{')) { $if = $this->pushSpecialBlock(Type::T_IF, $s); $if->cond = $cond; $if->cases = []; @@ -535,9 +535,9 @@ protected function parseChunk() list(, $if) = $last; if ($this->literal('@else')) { - if ($this->literal('{')) { + if ($this->matchChar('{')) { $else = $this->pushSpecialBlock(Type::T_ELSE, $s); - } elseif ($this->literal('if') && $this->valueList($cond) && $this->literal('{')) { + } elseif ($this->literal('if') && $this->valueList($cond) && $this->matchChar('{')) { $else = $this->pushSpecialBlock(Type::T_ELSEIF, $s); $else->cond = $cond; } @@ -576,10 +576,10 @@ protected function parseChunk() $this->seek($s); // doesn't match built in directive, do generic one - if ($this->literal('@', false) && + if ($this->matchChar('@', false) && $this->keyword($dirName) && ($this->variable($dirValue) || $this->openString('{', $dirValue) || true) && - $this->literal('{') + $this->matchChar('{') ) { if ($dirName === 'media') { $directive = $this->pushSpecialBlock(Type::T_MEDIA, $s); @@ -617,7 +617,7 @@ protected function parseChunk() // variable assigns if ($this->variable($name) && - $this->literal(':') && + $this->matchChar(':') && $this->valueList($value) && $this->end() ) { @@ -636,7 +636,7 @@ protected function parseChunk() } // opening css block - if ($this->selectors($selectors) && $this->literal('{')) { + if ($this->selectors($selectors) && $this->matchChar('{')) { $this->pushBlock($selectors, $s); return true; @@ -645,7 +645,7 @@ protected function parseChunk() $this->seek($s); // property assign, or nested assign - if ($this->propertyName($name) && $this->literal(':')) { + if ($this->propertyName($name) && $this->matchChar(':')) { $foundSomething = false; if ($this->valueList($value)) { @@ -653,7 +653,7 @@ protected function parseChunk() $foundSomething = true; } - if ($this->literal('{')) { + if ($this->matchChar('{')) { $propBlock = $this->pushSpecialBlock(Type::T_NESTED_PROPERTY, $s); $propBlock->prefix = $name; $foundSomething = true; @@ -669,7 +669,7 @@ protected function parseChunk() $this->seek($s); // closing a block - if ($this->literal('}')) { + if ($this->matchChar('}')) { $block = $this->popBlock(); if (isset($block->type) && $block->type === Type::T_INCLUDE) { @@ -686,7 +686,7 @@ protected function parseChunk() } // extra stuff - if ($this->literal(';') || + if ($this->matchChar(';') || $this->literal('')) { + if ($this->literal('-->', 3)) { return true; } @@ -687,7 +687,7 @@ protected function parseChunk() // extra stuff if ($this->matchChar(';') || - $this->literal('