WP-SCSS - Version 1.2.2

Version Description

  • Updated scssphp to version 0.6.6
Download this release

Release Info

Developer connectthink
Plugin Icon wp plugin WP-SCSS
Version 1.2.2
Comparing to
See all releases

Code changes from version 1.2.1 to 1.2.2

readme.txt CHANGED
@@ -4,7 +4,7 @@ Tags: sass, scss, css
4
  Plugin URI: https://github.com/ConnectThink/WP-SCSS
5
  Requires at least: 3.0.1
6
  Tested up to: 4.7
7
- Stable tag: 1.2.1
8
  License: GPLv3 or later
9
  License URI: http://www.gnu.org/copyleft/gpl.html
10
 
@@ -62,8 +62,11 @@ Make sure your directories are properly defined in the settings. Paths are defin
62
  If you are having issues with the plugin, create an issue on [github](https://github.com/ConnectThink/WP-SCSS), and we'll do our best to help.
63
 
64
  == Changelog ==
 
 
 
65
  = 1.2.1 =
66
- * Change set version option to update if already exists
67
 
68
  = 1.2.0 =
69
  * Fixed a bug where directory inputs were not getting sanitized [@mmcev106](https://github.com/ConnectThink/WP-SCSS/pull/66)
4
  Plugin URI: https://github.com/ConnectThink/WP-SCSS
5
  Requires at least: 3.0.1
6
  Tested up to: 4.7
7
+ Stable tag: 1.2.2
8
  License: GPLv3 or later
9
  License URI: http://www.gnu.org/copyleft/gpl.html
10
 
62
  If you are having issues with the plugin, create an issue on [github](https://github.com/ConnectThink/WP-SCSS), and we'll do our best to help.
63
 
64
  == Changelog ==
65
+ = 1.2.2 =
66
+ * Updated scssphp to version 0.6.6
67
+
68
  = 1.2.1 =
69
+ * Changed set version option to update if already exists
70
 
71
  = 1.2.0 =
72
  * Fixed a bug where directory inputs were not getting sanitized [@mmcev106](https://github.com/ConnectThink/WP-SCSS/pull/66)
scssphp/src/Compiler.php CHANGED
@@ -125,20 +125,21 @@ class Compiler
125
  protected $rootEnv;
126
  protected $rootBlock;
127
 
 
 
 
 
 
 
128
  private $indentLevel;
129
  private $commentsSeen;
130
  private $extends;
131
  private $extendsMap;
132
  private $parsedFiles;
133
- private $env;
134
- private $scope;
135
  private $parser;
136
- private $sourceNames;
137
  private $sourceIndex;
138
  private $sourceLine;
139
  private $sourceColumn;
140
- private $storeEnv;
141
- private $charsetSeen;
142
  private $stderr;
143
  private $shouldEvaluate;
144
  private $ignoreErrors;
@@ -207,7 +208,7 @@ class Compiler
207
  *
208
  * @return \Leafo\ScssPhp\Parser
209
  */
210
- private function parserFactory($path)
211
  {
212
  $parser = new Parser($path, count($this->sourceNames), $this->encoding);
213
 
@@ -396,23 +397,42 @@ class Compiler
396
  }
397
 
398
  if ($this->matchExtendsSingle($part, $origin)) {
399
- $before = array_slice($selector, 0, $i);
400
  $after = array_slice($selector, $i + 1);
401
- $s = count($before);
 
 
402
 
403
  foreach ($origin as $new) {
404
  $k = 0;
405
 
406
  // remove shared parts
407
  if ($initial) {
408
- while ($k < $s && isset($new[$k]) && $before[$k] === $new[$k]) {
409
  $k++;
410
  }
411
  }
412
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
413
  $result = array_merge(
414
  $before,
415
- $k > 0 ? array_slice($new, $k) : $new,
 
416
  $after
417
  );
418
 
@@ -423,14 +443,22 @@ class Compiler
423
  $out[] = $result;
424
 
425
  // recursively check for more matches
426
- $this->matchExtends($result, $out, $i, false);
427
 
428
  // selector sequence merging
429
  if (! empty($before) && count($new) > 1) {
 
 
 
 
 
430
  $result2 = array_merge(
431
- array_slice($new, 0, -1),
432
- $k > 0 ? array_slice($before, $k) : $before,
433
- array_slice($new, -1),
 
 
 
434
  $after
435
  );
436
 
@@ -467,6 +495,13 @@ class Compiler
467
  }
468
  }
469
 
 
 
 
 
 
 
 
470
  foreach ($single as $part) {
471
  if (isset($this->extendsMap[$part])) {
472
  foreach ($this->extendsMap[$part] as $idx) {
@@ -496,7 +531,17 @@ class Compiler
496
  return false;
497
  }
498
 
499
- $combined = $this->combineSelectorSingle(end($new), $rem);
 
 
 
 
 
 
 
 
 
 
500
 
501
  if (count(array_diff($combined, $origin[$j][count($origin[$j]) - 1]))) {
502
  $origin[$j][count($origin[$j]) - 1] = $combined;
@@ -511,6 +556,39 @@ class Compiler
511
  return $found;
512
  }
513
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
514
  /**
515
  * Combine selector single
516
  *
@@ -651,7 +729,7 @@ class Compiler
651
  {
652
  $env = $this->pushEnv($block);
653
  $envs = $this->compactEnv($env);
654
- $without = isset($block->with) ? $this->compileWith($block->with) : self::WITH_RULE;
655
 
656
  // wrap inline selector
657
  if ($block->selector) {
@@ -776,12 +854,12 @@ class Compiler
776
  ];
777
 
778
  // exclude selectors by default
779
- $without = self::WITH_RULE;
780
 
781
- if ($this->libMapHasKey([$with, self::$with])) {
782
- $without = self::WITH_ALL;
783
 
784
- $list = $this->coerceList($this->libMapGet([$with, self::$with]));
785
 
786
  foreach ($list[2] as $item) {
787
  $keyword = $this->compileStringContent($this->coerceString($item));
@@ -792,10 +870,10 @@ class Compiler
792
  }
793
  }
794
 
795
- if ($this->libMapHasKey([$with, self::$without])) {
796
  $without = 0;
797
 
798
- $list = $this->coerceList($this->libMapGet([$with, self::$without]));
799
 
800
  foreach ($list[2] as $item) {
801
  $keyword = $this->compileStringContent($this->coerceString($item));
@@ -842,10 +920,10 @@ class Compiler
842
  */
843
  private function isWithout($without, Block $block)
844
  {
845
- if ((($without & self::WITH_RULE) && isset($block->selectors)) ||
846
- (($without & self::WITH_MEDIA) &&
847
  isset($block->type) && $block->type === Type::T_MEDIA) ||
848
- (($without & self::WITH_SUPPORTS) &&
849
  isset($block->type) && $block->type === Type::T_DIRECTIVE &&
850
  isset($block->name) && $block->name === 'supports')
851
  ) {
@@ -936,13 +1014,16 @@ class Compiler
936
  $line = $block->sourceLine;
937
 
938
  switch ($this->lineNumberStyle) {
939
- case self::LINE_COMMENTS:
940
- $annotation->lines[] = '/* line ' . $line . ', ' . $file . ' */';
 
 
941
  break;
942
 
943
- case self::DEBUG_INFO:
944
- $annotation->lines[] = '@media -sass-debug-info{filename{font-family:"' . $file
945
- . '"}line{font-family:' . $line . '}}';
 
946
  break;
947
  }
948
 
@@ -1283,6 +1364,37 @@ class Compiler
1283
  return $out;
1284
  }
1285
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1286
  /**
1287
  * Merge media types
1288
  *
@@ -1460,9 +1572,9 @@ class Compiler
1460
  list(, $name, $value) = $child;
1461
 
1462
  if ($name[0] === Type::T_VARIABLE) {
1463
- $flag = isset($child[3]) ? $child[3] : null;
1464
- $isDefault = $flag === '!default';
1465
- $isGlobal = $flag === '!global';
1466
 
1467
  if ($isGlobal) {
1468
  $this->set($name[1], $this->reduce($value), false, $this->rootEnv);
@@ -1471,7 +1583,7 @@ class Compiler
1471
 
1472
  $shouldSet = $isDefault &&
1473
  (($result = $this->get($name[1], false)) === null
1474
- || $result === self::$null);
1475
 
1476
  if (! $isDefault || $shouldSet) {
1477
  $this->set($name[1], $this->reduce($value));
@@ -1499,7 +1611,7 @@ class Compiler
1499
  if ($value[0] !== Type::T_NULL) {
1500
  $value = $this->reduce($value);
1501
 
1502
- if ($value[0] === Type::T_NULL || $value === self::$nullString) {
1503
  break;
1504
  }
1505
  }
@@ -1525,7 +1637,7 @@ class Compiler
1525
  case Type::T_FUNCTION:
1526
  list(, $block) = $child;
1527
 
1528
- $this->set(self::$namespaces[$block->type] . $block->name, $block);
1529
  break;
1530
 
1531
  case Type::T_EXTEND:
@@ -1573,7 +1685,7 @@ class Compiler
1573
  list(,, $values) = $this->coerceList($item);
1574
 
1575
  foreach ($each->vars as $i => $var) {
1576
- $this->set($var, isset($values[$i]) ? $values[$i] : self::$null, true);
1577
  }
1578
  }
1579
 
@@ -1622,7 +1734,7 @@ class Compiler
1622
  $end = $end[1];
1623
  $d = $start < $end ? 1 : -1;
1624
 
1625
- while (true) {
1626
  if ((! $for->until && $start - $d == $end) ||
1627
  ($for->until && $start == $end)
1628
  ) {
@@ -1682,7 +1794,7 @@ class Compiler
1682
  // including a mixin
1683
  list(, $name, $argValues, $content) = $child;
1684
 
1685
- $mixin = $this->get(self::$namespaces['mixin'] . $name, false);
1686
 
1687
  if (! $mixin) {
1688
  $this->throwError("Undefined mixin $name");
@@ -1695,10 +1807,13 @@ class Compiler
1695
  $this->pushEnv();
1696
  $this->env->depth--;
1697
 
 
 
 
1698
  if (isset($content)) {
1699
  $content->scope = $callingScope;
1700
 
1701
- $this->setRaw(self::$namespaces['special'] . 'content', $content, $this->env);
1702
  }
1703
 
1704
  if (isset($mixin->args)) {
@@ -1709,15 +1824,19 @@ class Compiler
1709
 
1710
  $this->compileChildrenNoReturn($mixin->children, $out);
1711
 
 
 
1712
  $this->popEnv();
1713
  break;
1714
 
1715
  case Type::T_MIXIN_CONTENT:
1716
- $content = $this->get(self::$namespaces['special'] . 'content', false, $this->getStoreEnv())
1717
- ?: $this->get(self::$namespaces['special'] . 'content', false, $this->env);
1718
 
1719
  if (! $content) {
1720
- $this->throwError('Expected @content inside of mixin');
 
 
1721
  break;
1722
  }
1723
 
@@ -1742,7 +1861,7 @@ class Compiler
1742
 
1743
  $line = $this->sourceLine;
1744
  $value = $this->compileValue($this->reduce($value, true));
1745
- echo "Line $line WARN: $value\n";
1746
  break;
1747
 
1748
  case Type::T_ERROR:
@@ -1799,7 +1918,19 @@ class Compiler
1799
  */
1800
  protected function isTruthy($value)
1801
  {
1802
- return $value !== self::$false && $value !== self::$null;
 
 
 
 
 
 
 
 
 
 
 
 
1803
  }
1804
 
1805
  /**
@@ -1842,7 +1973,7 @@ class Compiler
1842
  case Type::T_EXPRESSION:
1843
  list(, $op, $left, $right, $inParens) = $value;
1844
 
1845
- $opName = isset(self::$operatorNames[$op]) ? self::$operatorNames[$op] : $op;
1846
  $inExp = $inExp || $this->shouldEval($left) || $this->shouldEval($right);
1847
 
1848
  $left = $this->reduce($left, true);
@@ -1958,11 +2089,11 @@ class Compiler
1958
 
1959
  if ($op === 'not') {
1960
  if ($inExp || $inParens) {
1961
- if ($exp === self::$false || $exp === self::$null) {
1962
- return self::$true;
1963
  }
1964
 
1965
- return self::$false;
1966
  }
1967
 
1968
  $op = $op . ' ';
@@ -2216,7 +2347,7 @@ class Compiler
2216
  return;
2217
  }
2218
 
2219
- if ($left !== self::$false) {
2220
  return $this->reduce($right, true);
2221
  }
2222
 
@@ -2238,7 +2369,7 @@ class Compiler
2238
  return;
2239
  }
2240
 
2241
- if ($left !== self::$false) {
2242
  return $left;
2243
  }
2244
 
@@ -2469,7 +2600,7 @@ class Compiler
2469
  */
2470
  public function toBool($thing)
2471
  {
2472
- return $thing ? self::$true : self::$false;
2473
  }
2474
 
2475
  /**
@@ -2595,6 +2726,39 @@ class Compiler
2595
  $reduced = $this->reduce($exp);
2596
 
2597
  switch ($reduced[0]) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2598
  case Type::T_STRING:
2599
  $reduced = [Type::T_KEYWORD, $this->compileStringContent($reduced)];
2600
  break;
@@ -2719,7 +2883,7 @@ class Compiler
2719
  $newPart = [];
2720
 
2721
  foreach ($part as $p) {
2722
- if ($p === self::$selfSelector) {
2723
  $setSelf = true;
2724
 
2725
  foreach ($parent as $i => $parentPart) {
@@ -2937,20 +3101,28 @@ class Compiler
2937
  */
2938
  public function get($name, $shouldThrow = true, Environment $env = null)
2939
  {
2940
- $name = $this->normalizeName($name);
 
2941
 
2942
  if (! isset($env)) {
2943
  $env = $this->getStoreEnv();
2944
  }
2945
 
2946
- $hasNamespace = $name[0] === '^' || $name[0] === '@' || $name[0] === '%';
 
2947
 
2948
  for (;;) {
2949
- if (array_key_exists($name, $env->store)) {
2950
- return $env->store[$name];
2951
  }
2952
 
2953
  if (! $hasNamespace && isset($env->marker)) {
 
 
 
 
 
 
2954
  $env = $this->rootEnv;
2955
  continue;
2956
  }
@@ -3303,7 +3475,7 @@ class Compiler
3303
  *
3304
  * @throws \Exception
3305
  */
3306
- private function handleImportLoop($name)
3307
  {
3308
  for ($env = $this->env; $env; $env = $env->parent) {
3309
  $file = $this->sourceNames[$env->block->sourceIndex];
@@ -3338,7 +3510,7 @@ class Compiler
3338
  */
3339
  protected function callScssFunction($name, $argValues, &$returnValue)
3340
  {
3341
- $func = $this->get(self::$namespaces['function'] . $name, false);
3342
 
3343
  if (! $func) {
3344
  return false;
@@ -3346,6 +3518,9 @@ class Compiler
3346
 
3347
  $this->pushEnv();
3348
 
 
 
 
3349
  // set the args
3350
  if (isset($func->args)) {
3351
  $this->applyArguments($func->args, $argValues);
@@ -3360,9 +3535,11 @@ class Compiler
3360
 
3361
  $ret = $this->compileChildren($func->children, $tmp);
3362
 
 
 
3363
  $this->popEnv();
3364
 
3365
- $returnValue = ! isset($ret) ? self::$defaultValue : $ret;
3366
 
3367
  return true;
3368
  }
@@ -3386,7 +3563,7 @@ class Compiler
3386
  list($f, $prototype) = $this->userFunctions[$name];
3387
  } elseif (($f = $this->getBuiltinFunction($name)) && is_callable($f)) {
3388
  $libName = $f[1];
3389
- $prototype = isset(self::$$libName) ? self::$$libName : null;
3390
  } else {
3391
  return false;
3392
  }
@@ -3611,7 +3788,7 @@ class Compiler
3611
  }
3612
 
3613
  if ($value === null) {
3614
- $value = self::$null;
3615
  }
3616
 
3617
  if (is_numeric($value)) {
@@ -3619,7 +3796,30 @@ class Compiler
3619
  }
3620
 
3621
  if ($value === '') {
3622
- return self::$emptyString;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3623
  }
3624
 
3625
  return [Type::T_KEYWORD, $value];
@@ -3638,11 +3838,11 @@ class Compiler
3638
  return $item;
3639
  }
3640
 
3641
- if ($item === self::$emptyList) {
3642
- return self::$emptyMap;
3643
  }
3644
 
3645
- return [Type::T_MAP, [$item], [self::$null]];
3646
  }
3647
 
3648
  /**
@@ -4012,7 +4212,7 @@ class Compiler
4012
  list($list, $value) = $args;
4013
 
4014
  if ($value[0] === Type::T_MAP) {
4015
- return self::$null;
4016
  }
4017
 
4018
  if ($list[0] === Type::T_MAP ||
@@ -4024,7 +4224,7 @@ class Compiler
4024
  }
4025
 
4026
  if ($list[0] !== Type::T_LIST) {
4027
- return self::$null;
4028
  }
4029
 
4030
  $values = [];
@@ -4035,7 +4235,7 @@ class Compiler
4035
 
4036
  $key = array_search($this->normalizeValue($value), $values);
4037
 
4038
- return false === $key ? self::$null : $key + 1;
4039
  }
4040
 
4041
  protected static $libRgb = ['red', 'green', 'blue'];
@@ -4605,7 +4805,7 @@ class Compiler
4605
  $n += count($list[2]);
4606
  }
4607
 
4608
- return isset($list[2][$n]) ? $list[2][$n] : self::$defaultValue;
4609
  }
4610
 
4611
  protected static $libSetNth = ['list', 'n', 'value'];
@@ -4643,7 +4843,7 @@ class Compiler
4643
  }
4644
  }
4645
 
4646
- return self::$null;
4647
  }
4648
 
4649
  protected static $libMapKeys = ['map'];
@@ -4794,7 +4994,7 @@ class Compiler
4794
 
4795
  switch ($value[0]) {
4796
  case Type::T_KEYWORD:
4797
- if ($value === self::$true || $value === self::$false) {
4798
  return 'bool';
4799
  }
4800
 
@@ -4867,7 +5067,7 @@ class Compiler
4867
 
4868
  $result = strpos($stringContent, $substringContent);
4869
 
4870
- return $result === false ? self::$null : new Node\Number($result + 1, '');
4871
  }
4872
 
4873
  protected static $libStrInsert = ['string', 'insert', 'index'];
@@ -4899,7 +5099,7 @@ class Compiler
4899
  protected function libStrSlice($args)
4900
  {
4901
  if (isset($args[2]) && $args[2][1] == 0) {
4902
- return self::$nullString;
4903
  }
4904
 
4905
  $string = $this->coerceString($args[0]);
@@ -4961,7 +5161,7 @@ class Compiler
4961
  $name = $this->compileStringContent($string);
4962
 
4963
  // user defined functions
4964
- if ($this->has(self::$namespaces['function'] . $name)) {
4965
  return true;
4966
  }
4967
 
@@ -4992,7 +5192,7 @@ class Compiler
4992
  $string = $this->coerceString($args[0]);
4993
  $name = $this->compileStringContent($string);
4994
 
4995
- return $this->has(self::$namespaces['mixin'] . $name);
4996
  }
4997
 
4998
  protected static $libVariableExists = ['name'];
@@ -5050,7 +5250,7 @@ class Compiler
5050
  protected static $libInspect = ['value'];
5051
  protected function libInspect($args)
5052
  {
5053
- if ($args[0] === self::$null) {
5054
  return [Type::T_KEYWORD, 'null'];
5055
  }
5056
 
125
  protected $rootEnv;
126
  protected $rootBlock;
127
 
128
+ protected $env;
129
+ protected $scope;
130
+ protected $storeEnv;
131
+ protected $charsetSeen;
132
+ protected $sourceNames;
133
+
134
  private $indentLevel;
135
  private $commentsSeen;
136
  private $extends;
137
  private $extendsMap;
138
  private $parsedFiles;
 
 
139
  private $parser;
 
140
  private $sourceIndex;
141
  private $sourceLine;
142
  private $sourceColumn;
 
 
143
  private $stderr;
144
  private $shouldEvaluate;
145
  private $ignoreErrors;
208
  *
209
  * @return \Leafo\ScssPhp\Parser
210
  */
211
+ protected function parserFactory($path)
212
  {
213
  $parser = new Parser($path, count($this->sourceNames), $this->encoding);
214
 
397
  }
398
 
399
  if ($this->matchExtendsSingle($part, $origin)) {
 
400
  $after = array_slice($selector, $i + 1);
401
+ $before = array_slice($selector, 0, $i);
402
+
403
+ list($before, $nonBreakableBefore) = $this->extractRelationshipFromFragment($before);
404
 
405
  foreach ($origin as $new) {
406
  $k = 0;
407
 
408
  // remove shared parts
409
  if ($initial) {
410
+ while ($k < $i && isset($new[$k]) && $selector[$k] === $new[$k]) {
411
  $k++;
412
  }
413
  }
414
 
415
+ $replacement = [];
416
+ $tempReplacement = $k > 0 ? array_slice($new, $k) : $new;
417
+
418
+ for ($l = count($tempReplacement) - 1; $l >= 0; $l--) {
419
+ $slice = $tempReplacement[$l];
420
+ array_unshift($replacement, $slice);
421
+
422
+ if (! $this->isImmediateRelationshipCombinator(end($slice))) {
423
+ break;
424
+ }
425
+ }
426
+
427
+ $afterBefore = $l != 0 ? array_slice($tempReplacement, 0, $l) : [];
428
+
429
+ // Merge shared direct relationships.
430
+ $mergedBefore = $this->mergeDirectRelationships($afterBefore, $nonBreakableBefore);
431
+
432
  $result = array_merge(
433
  $before,
434
+ $mergedBefore,
435
+ $replacement,
436
  $after
437
  );
438
 
443
  $out[] = $result;
444
 
445
  // recursively check for more matches
446
+ $this->matchExtends($result, $out, count($before) + count($mergedBefore), false);
447
 
448
  // selector sequence merging
449
  if (! empty($before) && count($new) > 1) {
450
+ $sharedParts = $k > 0 ? array_slice($before, 0, $k) : [];
451
+ $postSharedParts = $k > 0 ? array_slice($before, $k) : $before;
452
+
453
+ list($injectBetweenSharedParts, $nonBreakable2) = $this->extractRelationshipFromFragment($afterBefore);
454
+
455
  $result2 = array_merge(
456
+ $sharedParts,
457
+ $injectBetweenSharedParts,
458
+ $postSharedParts,
459
+ $nonBreakable2,
460
+ $nonBreakableBefore,
461
+ $replacement,
462
  $after
463
  );
464
 
495
  }
496
  }
497
 
498
+ $extendingDecoratedTag = false;
499
+
500
+ if (count($single) > 1) {
501
+ $matches = null;
502
+ $extendingDecoratedTag = preg_match('/^[a-z0-9]+$/i', $single[0], $matches) ? $matches[0] : false;
503
+ }
504
+
505
  foreach ($single as $part) {
506
  if (isset($this->extendsMap[$part])) {
507
  foreach ($this->extendsMap[$part] as $idx) {
531
  return false;
532
  }
533
 
534
+ $replacement = end($new);
535
+
536
+ // Extending a decorated tag with another tag is not possible.
537
+ if ($extendingDecoratedTag && $replacement[0] != $extendingDecoratedTag &&
538
+ preg_match('/^[a-z0-9]+$/i', $replacement[0])
539
+ ) {
540
+ unset($origin[$j]);
541
+ continue;
542
+ }
543
+
544
+ $combined = $this->combineSelectorSingle($replacement, $rem);
545
 
546
  if (count(array_diff($combined, $origin[$j][count($origin[$j]) - 1]))) {
547
  $origin[$j][count($origin[$j]) - 1] = $combined;
556
  return $found;
557
  }
558
 
559
+
560
+ /**
561
+ * Extract a relationship from the fragment.
562
+ *
563
+ * When extracting the last portion of a selector we will be left with a
564
+ * fragment which may end with a direction relationship combinator. This
565
+ * method will extract the relationship fragment and return it along side
566
+ * the rest.
567
+ *
568
+ * @param array $fragment The selector fragment maybe ending with a direction relationship combinator.
569
+ * @return array The selector without the relationship fragment if any, the relationship fragment.
570
+ */
571
+ protected function extractRelationshipFromFragment(array $fragment)
572
+ {
573
+ $parents = [];
574
+ $children = [];
575
+ $j = $i = count($fragment);
576
+
577
+ for (;;) {
578
+ $children = $j != $i ? array_slice($fragment, $j, $i - $j) : [];
579
+ $parents = array_slice($fragment, 0, $j);
580
+ $slice = end($parents);
581
+
582
+ if (empty($slice) || ! $this->isImmediateRelationshipCombinator($slice[0])) {
583
+ break;
584
+ }
585
+
586
+ $j -= 2;
587
+ }
588
+
589
+ return [$parents, $children];
590
+ }
591
+
592
  /**
593
  * Combine selector single
594
  *
729
  {
730
  $env = $this->pushEnv($block);
731
  $envs = $this->compactEnv($env);
732
+ $without = isset($block->with) ? $this->compileWith($block->with) : static::WITH_RULE;
733
 
734
  // wrap inline selector
735
  if ($block->selector) {
854
  ];
855
 
856
  // exclude selectors by default
857
+ $without = static::WITH_RULE;
858
 
859
+ if ($this->libMapHasKey([$with, static::$with])) {
860
+ $without = static::WITH_ALL;
861
 
862
+ $list = $this->coerceList($this->libMapGet([$with, static::$with]));
863
 
864
  foreach ($list[2] as $item) {
865
  $keyword = $this->compileStringContent($this->coerceString($item));
870
  }
871
  }
872
 
873
+ if ($this->libMapHasKey([$with, static::$without])) {
874
  $without = 0;
875
 
876
+ $list = $this->coerceList($this->libMapGet([$with, static::$without]));
877
 
878
  foreach ($list[2] as $item) {
879
  $keyword = $this->compileStringContent($this->coerceString($item));
920
  */
921
  private function isWithout($without, Block $block)
922
  {
923
+ if ((($without & static::WITH_RULE) && isset($block->selectors)) ||
924
+ (($without & static::WITH_MEDIA) &&
925
  isset($block->type) && $block->type === Type::T_MEDIA) ||
926
+ (($without & static::WITH_SUPPORTS) &&
927
  isset($block->type) && $block->type === Type::T_DIRECTIVE &&
928
  isset($block->name) && $block->name === 'supports')
929
  ) {
1014
  $line = $block->sourceLine;
1015
 
1016
  switch ($this->lineNumberStyle) {
1017
+ case static::LINE_COMMENTS:
1018
+ $annotation->lines[] = '/* line ' . $line
1019
+ . ($file ? ', ' . $file : '')
1020
+ . ' */';
1021
  break;
1022
 
1023
+ case static::DEBUG_INFO:
1024
+ $annotation->lines[] = '@media -sass-debug-info{'
1025
+ . ($file ? 'filename{font-family:"' . $file . '"}' : '')
1026
+ . 'line{font-family:' . $line . '}}';
1027
  break;
1028
  }
1029
 
1364
  return $out;
1365
  }
1366
 
1367
+ protected function mergeDirectRelationships($selectors1, $selectors2)
1368
+ {
1369
+ if (empty($selectors1) || empty($selectors2)) {
1370
+ return array_merge($selectors1, $selectors2);
1371
+ }
1372
+
1373
+ $part1 = end($selectors1);
1374
+ $part2 = end($selectors2);
1375
+
1376
+ if (! $this->isImmediateRelationshipCombinator($part1[0]) || $part1 !== $part2) {
1377
+ return array_merge($selectors1, $selectors2);
1378
+ }
1379
+
1380
+ $merged = [];
1381
+
1382
+ do {
1383
+ $part1 = array_pop($selectors1);
1384
+ $part2 = array_pop($selectors2);
1385
+
1386
+ if ($this->isImmediateRelationshipCombinator($part1[0]) && $part1 !== $part2) {
1387
+ $merged = array_merge($selectors1, [$part1], $selectors2, [$part2], $merged);
1388
+ break;
1389
+ }
1390
+
1391
+ array_unshift($merged, $part1);
1392
+ array_unshift($merged, [array_pop($selectors1)[0] . array_pop($selectors2)[0]]);
1393
+ } while (! empty($selectors1) && ! empty($selectors2));
1394
+
1395
+ return $merged;
1396
+ }
1397
+
1398
  /**
1399
  * Merge media types
1400
  *
1572
  list(, $name, $value) = $child;
1573
 
1574
  if ($name[0] === Type::T_VARIABLE) {
1575
+ $flags = isset($child[3]) ? $child[3] : [];
1576
+ $isDefault = in_array('!default', $flags);
1577
+ $isGlobal = in_array('!global', $flags);
1578
 
1579
  if ($isGlobal) {
1580
  $this->set($name[1], $this->reduce($value), false, $this->rootEnv);
1583
 
1584
  $shouldSet = $isDefault &&
1585
  (($result = $this->get($name[1], false)) === null
1586
+ || $result === static::$null);
1587
 
1588
  if (! $isDefault || $shouldSet) {
1589
  $this->set($name[1], $this->reduce($value));
1611
  if ($value[0] !== Type::T_NULL) {
1612
  $value = $this->reduce($value);
1613
 
1614
+ if ($value[0] === Type::T_NULL || $value === static::$nullString) {
1615
  break;
1616
  }
1617
  }
1637
  case Type::T_FUNCTION:
1638
  list(, $block) = $child;
1639
 
1640
+ $this->set(static::$namespaces[$block->type] . $block->name, $block);
1641
  break;
1642
 
1643
  case Type::T_EXTEND:
1685
  list(,, $values) = $this->coerceList($item);
1686
 
1687
  foreach ($each->vars as $i => $var) {
1688
+ $this->set($var, isset($values[$i]) ? $values[$i] : static::$null, true);
1689
  }
1690
  }
1691
 
1734
  $end = $end[1];
1735
  $d = $start < $end ? 1 : -1;
1736
 
1737
+ for (;;) {
1738
  if ((! $for->until && $start - $d == $end) ||
1739
  ($for->until && $start == $end)
1740
  ) {
1794
  // including a mixin
1795
  list(, $name, $argValues, $content) = $child;
1796
 
1797
+ $mixin = $this->get(static::$namespaces['mixin'] . $name, false);
1798
 
1799
  if (! $mixin) {
1800
  $this->throwError("Undefined mixin $name");
1807
  $this->pushEnv();
1808
  $this->env->depth--;
1809
 
1810
+ $storeEnv = $this->storeEnv;
1811
+ $this->storeEnv = $this->env;
1812
+
1813
  if (isset($content)) {
1814
  $content->scope = $callingScope;
1815
 
1816
+ $this->setRaw(static::$namespaces['special'] . 'content', $content, $this->env);
1817
  }
1818
 
1819
  if (isset($mixin->args)) {
1824
 
1825
  $this->compileChildrenNoReturn($mixin->children, $out);
1826
 
1827
+ $this->storeEnv = $storeEnv;
1828
+
1829
  $this->popEnv();
1830
  break;
1831
 
1832
  case Type::T_MIXIN_CONTENT:
1833
+ $content = $this->get(static::$namespaces['special'] . 'content', false, $this->getStoreEnv())
1834
+ ?: $this->get(static::$namespaces['special'] . 'content', false, $this->env);
1835
 
1836
  if (! $content) {
1837
+ $content = new \stdClass();
1838
+ $content->scope = new \stdClass();
1839
+ $content->children = $this->storeEnv->parent->block->children;
1840
  break;
1841
  }
1842
 
1861
 
1862
  $line = $this->sourceLine;
1863
  $value = $this->compileValue($this->reduce($value, true));
1864
+ fwrite($this->stderr, "Line $line WARN: $value\n");
1865
  break;
1866
 
1867
  case Type::T_ERROR:
1918
  */
1919
  protected function isTruthy($value)
1920
  {
1921
+ return $value !== static::$false && $value !== static::$null;
1922
+ }
1923
+
1924
+ /**
1925
+ * Is the value a direct relationship combinator?
1926
+ *
1927
+ * @param string $value
1928
+ *
1929
+ * @return bool
1930
+ */
1931
+ protected function isImmediateRelationshipCombinator($value)
1932
+ {
1933
+ return $value === '>' || $value === '+' || $value === '~';
1934
  }
1935
 
1936
  /**
1973
  case Type::T_EXPRESSION:
1974
  list(, $op, $left, $right, $inParens) = $value;
1975
 
1976
+ $opName = isset(static::$operatorNames[$op]) ? static::$operatorNames[$op] : $op;
1977
  $inExp = $inExp || $this->shouldEval($left) || $this->shouldEval($right);
1978
 
1979
  $left = $this->reduce($left, true);
2089
 
2090
  if ($op === 'not') {
2091
  if ($inExp || $inParens) {
2092
+ if ($exp === static::$false || $exp === static::$null) {
2093
+ return static::$true;
2094
  }
2095
 
2096
+ return static::$false;
2097
  }
2098
 
2099
  $op = $op . ' ';
2347
  return;
2348
  }
2349
 
2350
+ if ($left !== static::$false and $left !== static::$null) {
2351
  return $this->reduce($right, true);
2352
  }
2353
 
2369
  return;
2370
  }
2371
 
2372
+ if ($left !== static::$false and $left !== static::$null) {
2373
  return $left;
2374
  }
2375
 
2600
  */
2601
  public function toBool($thing)
2602
  {
2603
+ return $thing ? static::$true : static::$false;
2604
  }
2605
 
2606
  /**
2726
  $reduced = $this->reduce($exp);
2727
 
2728
  switch ($reduced[0]) {
2729
+ case Type::T_LIST:
2730
+ $reduced = $this->extractInterpolation($reduced);
2731
+
2732
+ if ($reduced[0] !== Type::T_LIST) {
2733
+ break;
2734
+ }
2735
+
2736
+ list(, $delim, $items) = $reduced;
2737
+
2738
+ if ($delim !== ' ') {
2739
+ $delim .= ' ';
2740
+ }
2741
+
2742
+ $filtered = [];
2743
+
2744
+ foreach ($items as $item) {
2745
+ if ($item[0] === Type::T_NULL) {
2746
+ continue;
2747
+ }
2748
+
2749
+ $temp = $this->compileValue([Type::T_KEYWORD, $item]);
2750
+ if ($temp[0] === Type::T_STRING) {
2751
+ $filtered[] = $this->compileStringContent($temp);
2752
+ } elseif ($temp[0] === Type::T_KEYWORD) {
2753
+ $filtered[] = $temp[1];
2754
+ } else {
2755
+ $filtered[] = $this->compileValue($temp);
2756
+ }
2757
+ }
2758
+
2759
+ $reduced = [Type::T_KEYWORD, implode("$delim", $filtered)];
2760
+ break;
2761
+
2762
  case Type::T_STRING:
2763
  $reduced = [Type::T_KEYWORD, $this->compileStringContent($reduced)];
2764
  break;
2883
  $newPart = [];
2884
 
2885
  foreach ($part as $p) {
2886
+ if ($p === static::$selfSelector) {
2887
  $setSelf = true;
2888
 
2889
  foreach ($parent as $i => $parentPart) {
3101
  */
3102
  public function get($name, $shouldThrow = true, Environment $env = null)
3103
  {
3104
+ $normalizedName = $this->normalizeName($name);
3105
+ $specialContentKey = static::$namespaces['special'] . 'content';
3106
 
3107
  if (! isset($env)) {
3108
  $env = $this->getStoreEnv();
3109
  }
3110
 
3111
+ $nextIsRoot = false;
3112
+ $hasNamespace = $normalizedName[0] === '^' || $normalizedName[0] === '@' || $normalizedName[0] === '%';
3113
 
3114
  for (;;) {
3115
+ if (array_key_exists($normalizedName, $env->store)) {
3116
+ return $env->store[$normalizedName];
3117
  }
3118
 
3119
  if (! $hasNamespace && isset($env->marker)) {
3120
+ if (! $nextIsRoot && ! empty($env->store[$specialContentKey])) {
3121
+ $env = $env->store[$specialContentKey]->scope;
3122
+ $nextIsRoot = true;
3123
+ continue;
3124
+ }
3125
+
3126
  $env = $this->rootEnv;
3127
  continue;
3128
  }
3475
  *
3476
  * @throws \Exception
3477
  */
3478
+ protected function handleImportLoop($name)
3479
  {
3480
  for ($env = $this->env; $env; $env = $env->parent) {
3481
  $file = $this->sourceNames[$env->block->sourceIndex];
3510
  */
3511
  protected function callScssFunction($name, $argValues, &$returnValue)
3512
  {
3513
+ $func = $this->get(static::$namespaces['function'] . $name, false);
3514
 
3515
  if (! $func) {
3516
  return false;
3518
 
3519
  $this->pushEnv();
3520
 
3521
+ $storeEnv = $this->storeEnv;
3522
+ $this->storeEnv = $this->env;
3523
+
3524
  // set the args
3525
  if (isset($func->args)) {
3526
  $this->applyArguments($func->args, $argValues);
3535
 
3536
  $ret = $this->compileChildren($func->children, $tmp);
3537
 
3538
+ $this->storeEnv = $storeEnv;
3539
+
3540
  $this->popEnv();
3541
 
3542
+ $returnValue = ! isset($ret) ? static::$defaultValue : $ret;
3543
 
3544
  return true;
3545
  }
3563
  list($f, $prototype) = $this->userFunctions[$name];
3564
  } elseif (($f = $this->getBuiltinFunction($name)) && is_callable($f)) {
3565
  $libName = $f[1];
3566
+ $prototype = isset(static::$$libName) ? static::$$libName : null;
3567
  } else {
3568
  return false;
3569
  }
3788
  }
3789
 
3790
  if ($value === null) {
3791
+ return static::$null;
3792
  }
3793
 
3794
  if (is_numeric($value)) {
3796
  }
3797
 
3798
  if ($value === '') {
3799
+ return static::$emptyString;
3800
+ }
3801
+
3802
+ if (preg_match('/^(#([0-9a-f]{6})|#([0-9a-f]{3}))$/i', $value, $m)) {
3803
+ $color = [Type::T_COLOR];
3804
+
3805
+ if (isset($m[3])) {
3806
+ $num = hexdec($m[3]);
3807
+
3808
+ foreach ([3, 2, 1] as $i) {
3809
+ $t = $num & 0xf;
3810
+ $color[$i] = $t << 4 | $t;
3811
+ $num >>= 4;
3812
+ }
3813
+ } else {
3814
+ $num = hexdec($m[2]);
3815
+
3816
+ foreach ([3, 2, 1] as $i) {
3817
+ $color[$i] = $num & 0xff;
3818
+ $num >>= 8;
3819
+ }
3820
+ }
3821
+
3822
+ return $color;
3823
  }
3824
 
3825
  return [Type::T_KEYWORD, $value];
3838
  return $item;
3839
  }
3840
 
3841
+ if ($item === static::$emptyList) {
3842
+ return static::$emptyMap;
3843
  }
3844
 
3845
+ return [Type::T_MAP, [$item], [static::$null]];
3846
  }
3847
 
3848
  /**
4212
  list($list, $value) = $args;
4213
 
4214
  if ($value[0] === Type::T_MAP) {
4215
+ return static::$null;
4216
  }
4217
 
4218
  if ($list[0] === Type::T_MAP ||
4224
  }
4225
 
4226
  if ($list[0] !== Type::T_LIST) {
4227
+ return static::$null;
4228
  }
4229
 
4230
  $values = [];
4235
 
4236
  $key = array_search($this->normalizeValue($value), $values);
4237
 
4238
+ return false === $key ? static::$null : $key + 1;
4239
  }
4240
 
4241
  protected static $libRgb = ['red', 'green', 'blue'];
4805
  $n += count($list[2]);
4806
  }
4807
 
4808
+ return isset($list[2][$n]) ? $list[2][$n] : static::$defaultValue;
4809
  }
4810
 
4811
  protected static $libSetNth = ['list', 'n', 'value'];
4843
  }
4844
  }
4845
 
4846
+ return static::$null;
4847
  }
4848
 
4849
  protected static $libMapKeys = ['map'];
4994
 
4995
  switch ($value[0]) {
4996
  case Type::T_KEYWORD:
4997
+ if ($value === static::$true || $value === static::$false) {
4998
  return 'bool';
4999
  }
5000
 
5067
 
5068
  $result = strpos($stringContent, $substringContent);
5069
 
5070
+ return $result === false ? static::$null : new Node\Number($result + 1, '');
5071
  }
5072
 
5073
  protected static $libStrInsert = ['string', 'insert', 'index'];
5099
  protected function libStrSlice($args)
5100
  {
5101
  if (isset($args[2]) && $args[2][1] == 0) {
5102
+ return static::$nullString;
5103
  }
5104
 
5105
  $string = $this->coerceString($args[0]);
5161
  $name = $this->compileStringContent($string);
5162
 
5163
  // user defined functions
5164
+ if ($this->has(static::$namespaces['function'] . $name)) {
5165
  return true;
5166
  }
5167
 
5192
  $string = $this->coerceString($args[0]);
5193
  $name = $this->compileStringContent($string);
5194
 
5195
+ return $this->has(static::$namespaces['mixin'] . $name);
5196
  }
5197
 
5198
  protected static $libVariableExists = ['name'];
5250
  protected static $libInspect = ['value'];
5251
  protected function libInspect($args)
5252
  {
5253
+ if ($args[0] === static::$null) {
5254
  return [Type::T_KEYWORD, 'null'];
5255
  }
5256
 
scssphp/src/Node/Number.php CHANGED
@@ -110,7 +110,7 @@ class Number extends Node implements \ArrayAccess
110
 
111
  $dimension = $this->dimension;
112
 
113
- foreach (self::$unitTable['in'] as $unit => $conv) {
114
  $from = isset($this->units[$unit]) ? $this->units[$unit] : 0;
115
  $to = isset($units[$unit]) ? $units[$unit] : 0;
116
  $factor = pow($conv, $from - $to);
@@ -265,7 +265,7 @@ class Number extends Node implements \ArrayAccess
265
  */
266
  public function output(Compiler $compiler = null)
267
  {
268
- $dimension = round($this->dimension, self::$precision);
269
 
270
  $units = array_filter($this->units, function ($unitSize) {
271
  return $unitSize;
@@ -277,7 +277,7 @@ class Number extends Node implements \ArrayAccess
277
 
278
  $this->normalizeUnits($dimension, $units, 'in');
279
 
280
- $dimension = round($dimension, self::$precision);
281
  $units = array_filter($units, function ($unitSize) {
282
  return $unitSize;
283
  });
@@ -316,8 +316,8 @@ class Number extends Node implements \ArrayAccess
316
  $units = [];
317
 
318
  foreach ($this->units as $unit => $exp) {
319
- if (isset(self::$unitTable[$baseUnit][$unit])) {
320
- $factor = pow(self::$unitTable[$baseUnit][$unit], $exp);
321
 
322
  $unit = $baseUnit;
323
  $dimension /= $factor;
110
 
111
  $dimension = $this->dimension;
112
 
113
+ foreach (static::$unitTable['in'] as $unit => $conv) {
114
  $from = isset($this->units[$unit]) ? $this->units[$unit] : 0;
115
  $to = isset($units[$unit]) ? $units[$unit] : 0;
116
  $factor = pow($conv, $from - $to);
265
  */
266
  public function output(Compiler $compiler = null)
267
  {
268
+ $dimension = round($this->dimension, static::$precision);
269
 
270
  $units = array_filter($this->units, function ($unitSize) {
271
  return $unitSize;
277
 
278
  $this->normalizeUnits($dimension, $units, 'in');
279
 
280
+ $dimension = round($dimension, static::$precision);
281
  $units = array_filter($units, function ($unitSize) {
282
  return $unitSize;
283
  });
316
  $units = [];
317
 
318
  foreach ($this->units as $unit => $exp) {
319
+ if (isset(static::$unitTable[$baseUnit][$unit])) {
320
+ $factor = pow(static::$unitTable[$baseUnit][$unit], $exp);
321
 
322
  $unit = $baseUnit;
323
  $dimension /= $factor;
scssphp/src/Parser.php CHANGED
@@ -83,17 +83,17 @@ class Parser
83
  $this->utf8 = ! $encoding || strtolower($encoding) === 'utf-8';
84
  $this->patternModifiers = $this->utf8 ? 'Aisu' : 'Ais';
85
 
86
- if (empty(self::$operatorPattern)) {
87
- self::$operatorPattern = '([*\/%+-]|[!=]\=|\>\=?|\<\=\>|\<\=?|and|or)';
88
 
89
  $commentSingle = '\/\/';
90
  $commentMultiLeft = '\/\*';
91
  $commentMultiRight = '\*\/';
92
 
93
- self::$commentPattern = $commentMultiLeft . '.*?' . $commentMultiRight;
94
- self::$whitePattern = $this->utf8
95
- ? '/' . $commentSingle . '[^\n]*\s*|(' . self::$commentPattern . ')\s*|\s+/AisuS'
96
- : '/' . $commentSingle . '[^\n]*\s*|(' . self::$commentPattern . ')\s*|\s+/AisS';
97
  }
98
  }
99
 
@@ -142,11 +142,16 @@ class Parser
142
  */
143
  public function parse($buffer)
144
  {
 
 
 
 
 
 
145
  $this->count = 0;
146
  $this->env = null;
147
  $this->inParens = false;
148
  $this->eatWhiteDefault = true;
149
- $this->buffer = rtrim($buffer, "\x00..\x1f");
150
 
151
  $this->saveEncoding();
152
  $this->extractLineNumbers($buffer);
@@ -558,9 +563,9 @@ class Parser
558
 
559
  list($line, $column) = $this->getSourcePosition($s);
560
 
561
- $statement[self::SOURCE_LINE] = $line;
562
- $statement[self::SOURCE_COLUMN] = $column;
563
- $statement[self::SOURCE_INDEX] = $this->sourceIndex;
564
 
565
  $this->charset = $statement;
566
  }
@@ -617,8 +622,8 @@ class Parser
617
  $this->end()
618
  ) {
619
  // check for '!flag'
620
- $assignmentFlag = $this->stripAssignmentFlag($value);
621
- $this->append([Type::T_ASSIGN, $name, $value, $assignmentFlag], $s);
622
 
623
  return true;
624
  }
@@ -895,7 +900,7 @@ class Parser
895
 
896
  $len = strlen($what);
897
 
898
- if (substr($this->buffer, $this->count, $len) === $what) {
899
  $this->count += $len;
900
 
901
  if ($eatWhitespace) {
@@ -917,7 +922,7 @@ class Parser
917
  {
918
  $gotWhite = false;
919
 
920
- while (preg_match(self::$whitePattern, $this->buffer, $m, null, $this->count)) {
921
  if (isset($m[1]) && empty($this->commentsSeen[$this->count])) {
922
  $this->appendComment([Type::T_COMMENT, $m[1]]);
923
 
@@ -954,9 +959,9 @@ class Parser
954
  if ($pos !== null) {
955
  list($line, $column) = $this->getSourcePosition($pos);
956
 
957
- $statement[self::SOURCE_LINE] = $line;
958
- $statement[self::SOURCE_COLUMN] = $column;
959
- $statement[self::SOURCE_INDEX] = $this->sourceIndex;
960
  }
961
 
962
  $this->env->children[] = $statement;
@@ -1244,13 +1249,13 @@ class Parser
1244
  */
1245
  protected function expHelper($lhs, $minP)
1246
  {
1247
- $operators = self::$operatorPattern;
1248
 
1249
  $ss = $this->seek();
1250
  $whiteBefore = isset($this->buffer[$this->count - 1]) &&
1251
  ctype_space($this->buffer[$this->count - 1]);
1252
 
1253
- while ($this->match($operators, $m, false) && self::$precedence[$m[1]] >= $minP) {
1254
  $whiteAfter = isset($this->buffer[$this->count]) &&
1255
  ctype_space($this->buffer[$this->count]);
1256
  $varAfter = isset($this->buffer[$this->count]) &&
@@ -1270,8 +1275,8 @@ class Parser
1270
  }
1271
 
1272
  // peek and see if rhs belongs to next operator
1273
- if ($this->peek($operators, $next) && self::$precedence[$next[1]] > self::$precedence[$op]) {
1274
- $rhs = $this->expHelper($rhs, self::$precedence[$next[1]]);
1275
  }
1276
 
1277
  $lhs = [Type::T_EXPRESSION, $op, $lhs, $rhs, $this->inParens, $whiteBefore, $whiteAfter];
@@ -1807,7 +1812,7 @@ class Parser
1807
  $oldWhite = $this->eatWhiteDefault;
1808
  $this->eatWhiteDefault = false;
1809
 
1810
- $patt = '(.*?)([\'"]|#\{|' . $this->pregQuote($end) . '|' . self::$commentPattern . ')';
1811
 
1812
  $nestingLevel = 0;
1813
 
@@ -1941,7 +1946,7 @@ class Parser
1941
 
1942
  // match comment hack
1943
  if (preg_match(
1944
- self::$whitePattern,
1945
  $this->buffer,
1946
  $m,
1947
  null,
@@ -2287,25 +2292,29 @@ class Parser
2287
  *
2288
  * @param array $value
2289
  *
2290
- * @return string
2291
  */
2292
- protected function stripAssignmentFlag(&$value)
2293
  {
2294
- $token = &$value;
2295
 
2296
  for ($token = &$value; $token[0] === Type::T_LIST && ($s = count($token[2])); $token = &$lastNode) {
2297
  $lastNode = &$token[2][$s - 1];
2298
 
2299
- if ($lastNode[0] === Type::T_KEYWORD && in_array($lastNode[1], ['!default', '!global'])) {
2300
  array_pop($token[2]);
2301
 
 
 
2302
  $token = $this->flattenList($token);
2303
 
2304
- return $lastNode[1];
 
 
2305
  }
2306
  }
2307
 
2308
- return false;
2309
  }
2310
 
2311
  /**
83
  $this->utf8 = ! $encoding || strtolower($encoding) === 'utf-8';
84
  $this->patternModifiers = $this->utf8 ? 'Aisu' : 'Ais';
85
 
86
+ if (empty(static::$operatorPattern)) {
87
+ static::$operatorPattern = '([*\/%+-]|[!=]\=|\>\=?|\<\=\>|\<\=?|and|or)';
88
 
89
  $commentSingle = '\/\/';
90
  $commentMultiLeft = '\/\*';
91
  $commentMultiRight = '\*\/';
92
 
93
+ static::$commentPattern = $commentMultiLeft . '.*?' . $commentMultiRight;
94
+ static::$whitePattern = $this->utf8
95
+ ? '/' . $commentSingle . '[^\n]*\s*|(' . static::$commentPattern . ')\s*|\s+/AisuS'
96
+ : '/' . $commentSingle . '[^\n]*\s*|(' . static::$commentPattern . ')\s*|\s+/AisS';
97
  }
98
  }
99
 
142
  */
143
  public function parse($buffer)
144
  {
145
+ // strip BOM (byte order marker)
146
+ if (substr($buffer, 0, 3) === "\xef\xbb\xbf") {
147
+ $buffer = substr($buffer, 3);
148
+ }
149
+
150
+ $this->buffer = rtrim($buffer, "\x00..\x1f");
151
  $this->count = 0;
152
  $this->env = null;
153
  $this->inParens = false;
154
  $this->eatWhiteDefault = true;
 
155
 
156
  $this->saveEncoding();
157
  $this->extractLineNumbers($buffer);
563
 
564
  list($line, $column) = $this->getSourcePosition($s);
565
 
566
+ $statement[static::SOURCE_LINE] = $line;
567
+ $statement[static::SOURCE_COLUMN] = $column;
568
+ $statement[static::SOURCE_INDEX] = $this->sourceIndex;
569
 
570
  $this->charset = $statement;
571
  }
622
  $this->end()
623
  ) {
624
  // check for '!flag'
625
+ $assignmentFlags = $this->stripAssignmentFlags($value);
626
+ $this->append([Type::T_ASSIGN, $name, $value, $assignmentFlags], $s);
627
 
628
  return true;
629
  }
900
 
901
  $len = strlen($what);
902
 
903
+ if (strcasecmp(substr($this->buffer, $this->count, $len), $what) === 0) {
904
  $this->count += $len;
905
 
906
  if ($eatWhitespace) {
922
  {
923
  $gotWhite = false;
924
 
925
+ while (preg_match(static::$whitePattern, $this->buffer, $m, null, $this->count)) {
926
  if (isset($m[1]) && empty($this->commentsSeen[$this->count])) {
927
  $this->appendComment([Type::T_COMMENT, $m[1]]);
928
 
959
  if ($pos !== null) {
960
  list($line, $column) = $this->getSourcePosition($pos);
961
 
962
+ $statement[static::SOURCE_LINE] = $line;
963
+ $statement[static::SOURCE_COLUMN] = $column;
964
+ $statement[static::SOURCE_INDEX] = $this->sourceIndex;
965
  }
966
 
967
  $this->env->children[] = $statement;
1249
  */
1250
  protected function expHelper($lhs, $minP)
1251
  {
1252
+ $operators = static::$operatorPattern;
1253
 
1254
  $ss = $this->seek();
1255
  $whiteBefore = isset($this->buffer[$this->count - 1]) &&
1256
  ctype_space($this->buffer[$this->count - 1]);
1257
 
1258
+ while ($this->match($operators, $m, false) && static::$precedence[$m[1]] >= $minP) {
1259
  $whiteAfter = isset($this->buffer[$this->count]) &&
1260
  ctype_space($this->buffer[$this->count]);
1261
  $varAfter = isset($this->buffer[$this->count]) &&
1275
  }
1276
 
1277
  // peek and see if rhs belongs to next operator
1278
+ if ($this->peek($operators, $next) && static::$precedence[$next[1]] > static::$precedence[$op]) {
1279
+ $rhs = $this->expHelper($rhs, static::$precedence[$next[1]]);
1280
  }
1281
 
1282
  $lhs = [Type::T_EXPRESSION, $op, $lhs, $rhs, $this->inParens, $whiteBefore, $whiteAfter];
1812
  $oldWhite = $this->eatWhiteDefault;
1813
  $this->eatWhiteDefault = false;
1814
 
1815
+ $patt = '(.*?)([\'"]|#\{|' . $this->pregQuote($end) . '|' . static::$commentPattern . ')';
1816
 
1817
  $nestingLevel = 0;
1818
 
1946
 
1947
  // match comment hack
1948
  if (preg_match(
1949
+ static::$whitePattern,
1950
  $this->buffer,
1951
  $m,
1952
  null,
2292
  *
2293
  * @param array $value
2294
  *
2295
+ * @return array
2296
  */
2297
+ protected function stripAssignmentFlags(&$value)
2298
  {
2299
+ $flags = [];
2300
 
2301
  for ($token = &$value; $token[0] === Type::T_LIST && ($s = count($token[2])); $token = &$lastNode) {
2302
  $lastNode = &$token[2][$s - 1];
2303
 
2304
+ while ($lastNode[0] === Type::T_KEYWORD && in_array($lastNode[1], ['!default', '!global'])) {
2305
  array_pop($token[2]);
2306
 
2307
+ $node = end($token[2]);
2308
+
2309
  $token = $this->flattenList($token);
2310
 
2311
+ $flags[] = $lastNode[1];
2312
+
2313
+ $lastNode = $node;
2314
  }
2315
  }
2316
 
2317
+ return $flags;
2318
  }
2319
 
2320
  /**
scssphp/src/Server.php CHANGED
@@ -457,7 +457,7 @@ class Server
457
  */
458
  public static function serveFrom($path)
459
  {
460
- $server = new self($path);
461
  $server->serve();
462
  }
463
  }
457
  */
458
  public static function serveFrom($path)
459
  {
460
+ $server = new static($path);
461
  $server->serve();
462
  }
463
  }
scssphp/src/Version.php CHANGED
@@ -18,5 +18,5 @@ namespace Leafo\ScssPhp;
18
  */
19
  class Version
20
  {
21
- const VERSION = 'v0.6.3';
22
  }
18
  */
19
  class Version
20
  {
21
+ const VERSION = 'v0.6.6';
22
  }
wp-scss.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: WP-SCSS
4
  * Plugin URI: https://github.com/ConnectThink/WP-SCSS
5
  * Description: Compiles scss files live on WordPress.
6
- * Version: 1.2.1
7
  * Author: Connect Think
8
  * Author URI: http://connectthink.com
9
  * License: GPLv3
@@ -46,7 +46,7 @@ if (!defined('WPSCSS_VERSION_KEY'))
46
  define('WPSCSS_VERSION_KEY', 'wpscss_version');
47
 
48
  if (!defined('WPSCSS_VERSION_NUM'))
49
- define('WPSCSS_VERSION_NUM', '1.2.1');
50
 
51
  // Add version to options table
52
  if ( get_option( WPSCSS_VERSION_KEY ) !== false ) {
3
  * Plugin Name: WP-SCSS
4
  * Plugin URI: https://github.com/ConnectThink/WP-SCSS
5
  * Description: Compiles scss files live on WordPress.
6
+ * Version: 1.2.2
7
  * Author: Connect Think
8
  * Author URI: http://connectthink.com
9
  * License: GPLv3
46
  define('WPSCSS_VERSION_KEY', 'wpscss_version');
47
 
48
  if (!defined('WPSCSS_VERSION_NUM'))
49
+ define('WPSCSS_VERSION_NUM', '1.2.2');
50
 
51
  // Add version to options table
52
  if ( get_option( WPSCSS_VERSION_KEY ) !== false ) {