Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.

Differences Between: [Versions 310 and 400] [Versions 311 and 400] [Versions 39 and 400] [Versions 400 and 401] [Versions 400 and 402] [Versions 400 and 403]

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