Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/Block.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,8 @@ class Block
* @var array
*/
public $children;
/**
* @var \Leafo\ScssPhp\Block
*/
public $selfParent;
}
26 changes: 18 additions & 8 deletions src/Compiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,7 @@ protected function compileAtRoot(Block $block)
$wrapped->comments = [];
$wrapped->parent = $block;
$wrapped->children = $block->children;
$wrapped->selfParent = $block->selfParent;

$block->children = [[Type::T_BLOCK, $wrapped]];
}
Expand Down Expand Up @@ -882,6 +883,7 @@ private function spliceTree($envs, Block $block, $without)
$newBlock = $b;
}

$newBlock->selfParent = $block->selfParent;
$type = isset($newBlock->type) ? $newBlock->type : Type::T_BLOCK;

return [$type, $newBlock];
Expand Down Expand Up @@ -1083,7 +1085,7 @@ protected function compileBlock(Block $block)
$this->scope->children[] = $out;

if (count($block->children)) {
$out->selectors = $this->multiplySelectors($env);
$out->selectors = $this->multiplySelectors($env, $block->selfParent);

$this->compileChildrenNoReturn($block->children, $out);
}
Expand Down Expand Up @@ -2899,15 +2901,21 @@ protected function extractInterpolation($list)
* Find the final set of selectors
*
* @param \Leafo\ScssPhp\Compiler\Environment $env
* @param Leafo\ScssPhp\Block $selfParent
*
* @return array
*/
protected function multiplySelectors(Environment $env)
protected function multiplySelectors(Environment $env, $selfParent = null)
{
$envs = $this->compactEnv($env);
$selectors = [];
$parentSelectors = [[]];

$selfParentSelectors = null;
if (!is_null($selfParent) and $selfParent->selectors) {
$selfParentSelectors = $this->evalSelectors($selfParent->selectors);
}

while ($env = array_pop($envs)) {
if (empty($env->selectors)) {
continue;
Expand All @@ -2917,7 +2925,7 @@ protected function multiplySelectors(Environment $env)

foreach ($env->selectors as $selector) {
foreach ($parentSelectors as $parent) {
$selectors[] = $this->joinSelectors($parent, $selector);
$selectors[] = $this->joinSelectors($parent, $selector, $selfParentSelectors);
}
}

Expand All @@ -2932,10 +2940,10 @@ protected function multiplySelectors(Environment $env)
*
* @param array $parent
* @param array $child
*
* @param array $selfParentSelectors
* @return array
*/
protected function joinSelectors($parent, $child)
protected function joinSelectors($parent, $child, $selfParentSelectors = null)
{
$setSelf = false;
$out = [];
Expand All @@ -2946,15 +2954,17 @@ protected function joinSelectors($parent, $child)
foreach ($part as $p) {
if ($p === static::$selfSelector) {
$setSelf = true;

foreach ($parent as $i => $parentPart) {
if (is_null($selfParentSelectors)) {
$selfParentSelectors = $parent;
}
foreach ($selfParentSelectors as $i => $parentPart) {
if ($i > 0) {
$out[] = $newPart;
$newPart = [];
}

foreach ($parentPart as $pp) {
$newPart[] = $pp;
$newPart[] = (is_array($pp) ? implode($pp) : $pp);
}
}
} else {
Expand Down
19 changes: 19 additions & 0 deletions src/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,11 @@ protected function popBlock()
$this->throwParseError('unexpected }');
}

if ($block->type == Type::T_AT_ROOT) {
// keeps the parent in case of self selector &
$block->selfParent = $block->parent;
}

$this->env = $block->parent;
unset($block->parent);

Expand Down Expand Up @@ -1918,6 +1923,20 @@ protected function interpolation(&$out, $lookWhite = true)
return true;
}

$this->seek($s);

if ($this->literal('#{') && $this->selectorSingle($sel) && $this->literal('}', false)) {
$out = $sel[0];

$this->eatWhiteDefault = $oldWhite;

if ($this->eatWhiteDefault) {
$this->whitespace();
}

return true;
}

$this->seek($s);
$this->eatWhiteDefault = $oldWhite;

Expand Down
6 changes: 6 additions & 0 deletions tests/inputs/at_root.scss
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,9 @@ $table-padding: 10px !default;
@include table;
}
}

.badge {
@at-root a#{&} {
text-decoration: none;
}
}
6 changes: 6 additions & 0 deletions tests/inputs/interpolation.scss
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,9 @@ $foo: ('a', 'b');
div {
prop: #{$foo};
}

.badge {
a#{&} {
text-decoration: none;
}
}
3 changes: 3 additions & 0 deletions tests/outputs/at_root.css
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,6 @@ body .second {
padding: 0px; }
tbody {
padding: 10px; }

a.badge {
text-decoration: none; }
3 changes: 3 additions & 0 deletions tests/outputs/interpolation.css
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,6 @@ foo, x, y {

div {
prop: a, b; }

a.badge {
text-decoration: none; }
5 changes: 5 additions & 0 deletions tests/outputs_numbered/at_root.css
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,8 @@ margin: 0; } }
/* line 139, inputs/at_root.scss */
tbody {
padding: 10px; }
/* line 151, inputs/at_root.scss */
/* line 152, inputs/at_root.scss */

a.badge {
text-decoration: none; }
5 changes: 5 additions & 0 deletions tests/outputs_numbered/interpolation.css
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,8 @@ foo, x, y {
/* line 97, inputs/interpolation.scss */
div {
prop: a, b; }
/* line 101, inputs/interpolation.scss */
/* line 102, inputs/interpolation.scss */

a.badge {
text-decoration: none; }