Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403]
1 <?php 2 /** 3 * SCSSPHP 4 * 5 * @copyright 2012-2019 Leaf Corcoran 6 * 7 * @license http://opensource.org/licenses/MIT MIT 8 * 9 * @link http://scssphp.github.io/scssphp 10 */ 11 12 namespace ScssPhp\ScssPhp\Formatter; 13 14 use ScssPhp\ScssPhp\Formatter; 15 use ScssPhp\ScssPhp\Formatter\OutputBlock; 16 use ScssPhp\ScssPhp\Type; 17 18 /** 19 * Nested formatter 20 * 21 * @author Leaf Corcoran <leafot@gmail.com> 22 */ 23 class Nested extends Formatter 24 { 25 /** 26 * @var integer 27 */ 28 private $depth; 29 30 /** 31 * {@inheritdoc} 32 */ 33 public function __construct() 34 { 35 $this->indentLevel = 0; 36 $this->indentChar = ' '; 37 $this->break = "\n"; 38 $this->open = ' {'; 39 $this->close = ' }'; 40 $this->tagSeparator = ', '; 41 $this->assignSeparator = ': '; 42 $this->keepSemicolons = true; 43 } 44 45 /** 46 * {@inheritdoc} 47 */ 48 protected function indentStr() 49 { 50 $n = $this->depth - 1; 51 52 return str_repeat($this->indentChar, max($this->indentLevel + $n, 0)); 53 } 54 55 /** 56 * {@inheritdoc} 57 */ 58 protected function blockLines(OutputBlock $block) 59 { 60 $inner = $this->indentStr(); 61 62 $glue = $this->break . $inner; 63 64 foreach ($block->lines as $index => $line) { 65 if (substr($line, 0, 2) === '/*') { 66 $block->lines[$index] = preg_replace('/[\r\n]+/', $glue, $line); 67 } 68 } 69 70 $this->write($inner . implode($glue, $block->lines)); 71 } 72 73 /** 74 * {@inheritdoc} 75 */ 76 protected function block(OutputBlock $block) 77 { 78 static $depths; 79 static $downLevel; 80 static $closeBlock; 81 static $previousEmpty; 82 static $previousHasSelector; 83 84 if ($block->type === 'root') { 85 $depths = [ 0 ]; 86 $downLevel = ''; 87 $closeBlock = ''; 88 $this->depth = 0; 89 $previousEmpty = false; 90 $previousHasSelector = false; 91 } 92 93 $isMediaOrDirective = in_array($block->type, [Type::T_DIRECTIVE, Type::T_MEDIA]); 94 $isSupport = ($block->type === Type::T_DIRECTIVE 95 && $block->selectors && strpos(implode('', $block->selectors), '@supports') !== false); 96 97 while ($block->depth < end($depths) || ($block->depth == 1 && end($depths) == 1)) { 98 array_pop($depths); 99 $this->depth--; 100 101 if (! $this->depth && ($block->depth <= 1 || (! $this->indentLevel && $block->type === Type::T_COMMENT)) && 102 (($block->selectors && ! $isMediaOrDirective) || $previousHasSelector) 103 ) { 104 $downLevel = $this->break; 105 } 106 107 if (empty($block->lines) && empty($block->children)) { 108 $previousEmpty = true; 109 } 110 } 111 112 if (empty($block->lines) && empty($block->children)) { 113 return; 114 } 115 116 $this->currentBlock = $block; 117 118 if (! empty($block->lines) || (! empty($block->children) && ($this->depth < 1 || $isSupport))) { 119 if ($block->depth > end($depths)) { 120 if (! $previousEmpty || $this->depth < 1) { 121 $this->depth++; 122 $depths[] = $block->depth; 123 } else { 124 // keep the current depth unchanged but take the block depth as a new reference for following blocks 125 array_pop($depths); 126 $depths[] = $block->depth; 127 } 128 } 129 } 130 131 $previousEmpty = ($block->type === Type::T_COMMENT); 132 $previousHasSelector = false; 133 134 if (! empty($block->selectors)) { 135 if ($closeBlock) { 136 $this->write($closeBlock); 137 $closeBlock = ''; 138 } 139 140 if ($downLevel) { 141 $this->write($downLevel); 142 $downLevel = ''; 143 } 144 145 $this->blockSelectors($block); 146 147 $this->indentLevel++; 148 } 149 150 if (! empty($block->lines)) { 151 if ($closeBlock) { 152 $this->write($closeBlock); 153 $closeBlock = ''; 154 } 155 156 if ($downLevel) { 157 $this->write($downLevel); 158 $downLevel = ''; 159 } 160 161 $this->blockLines($block); 162 163 $closeBlock = $this->break; 164 } 165 166 if (! empty($block->children)) { 167 if ($this->depth > 0 && ($isMediaOrDirective || ! $this->hasFlatChild($block))) { 168 array_pop($depths); 169 170 $this->depth--; 171 $this->blockChildren($block); 172 $this->depth++; 173 174 $depths[] = $block->depth; 175 } else { 176 $this->blockChildren($block); 177 } 178 } 179 180 // reclear to not be spoiled by children if T_DIRECTIVE 181 if ($block->type === Type::T_DIRECTIVE) { 182 $previousHasSelector = false; 183 } 184 185 if (! empty($block->selectors)) { 186 $this->indentLevel--; 187 188 if (! $this->keepSemicolons) { 189 $this->strippedSemicolon = ''; 190 } 191 192 $this->write($this->close); 193 194 $closeBlock = $this->break; 195 196 if ($this->depth > 1 && ! empty($block->children)) { 197 array_pop($depths); 198 $this->depth--; 199 } 200 201 if (! $isMediaOrDirective) { 202 $previousHasSelector = true; 203 } 204 } 205 206 if ($block->type === 'root') { 207 $this->write($this->break); 208 } 209 } 210 211 /** 212 * Block has flat child 213 * 214 * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block 215 * 216 * @return boolean 217 */ 218 private function hasFlatChild($block) 219 { 220 foreach ($block->children as $child) { 221 if (empty($child->selectors)) { 222 return true; 223 } 224 } 225 226 return false; 227 } 228 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body