Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.

Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [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                  $replacedLine = preg_replace('/\r\n?|\n|\f/', $this->break, $line);
  72                  assert($replacedLine !== null);
  73                  $block->lines[$index] = $replacedLine;
  74              }
  75          }
  76  
  77          $this->write($inner . implode($glue, $block->lines));
  78      }
  79  
  80      /**
  81       * {@inheritdoc}
  82       */
  83      protected function block(OutputBlock $block)
  84      {
  85          static $depths;
  86          static $downLevel;
  87          static $closeBlock;
  88          static $previousEmpty;
  89          static $previousHasSelector;
  90  
  91          if ($block->type === 'root') {
  92              $depths = [ 0 ];
  93              $downLevel = '';
  94              $closeBlock = '';
  95              $this->depth = 0;
  96              $previousEmpty = false;
  97              $previousHasSelector = false;
  98          }
  99  
 100          $isMediaOrDirective = \in_array($block->type, [Type::T_DIRECTIVE, Type::T_MEDIA]);
 101          $isSupport = ($block->type === Type::T_DIRECTIVE
 102              && $block->selectors && strpos(implode('', $block->selectors), '@supports') !== false);
 103  
 104          while ($block->depth < end($depths) || ($block->depth == 1 && end($depths) == 1)) {
 105              array_pop($depths);
 106              $this->depth--;
 107  
 108              if (
 109                  ! $this->depth && ($block->depth <= 1 || (! $this->indentLevel && $block->type === Type::T_COMMENT)) &&
 110                  (($block->selectors && ! $isMediaOrDirective) || $previousHasSelector)
 111              ) {
 112                  $downLevel = $this->break;
 113              }
 114  
 115              if (empty($block->lines) && empty($block->children)) {
 116                  $previousEmpty = true;
 117              }
 118          }
 119  
 120          if (empty($block->lines) && empty($block->children)) {
 121              return;
 122          }
 123  
 124          $this->currentBlock = $block;
 125  
 126          if (! empty($block->lines) || (! empty($block->children) && ($this->depth < 1 || $isSupport))) {
 127              if ($block->depth > end($depths)) {
 128                  if (! $previousEmpty || $this->depth < 1) {
 129                      $this->depth++;
 130  
 131                      $depths[] = $block->depth;
 132                  } else {
 133                      // keep the current depth unchanged but take the block depth as a new reference for following blocks
 134                      array_pop($depths);
 135  
 136                      $depths[] = $block->depth;
 137                  }
 138              }
 139          }
 140  
 141          $previousEmpty = ($block->type === Type::T_COMMENT);
 142          $previousHasSelector = false;
 143  
 144          if (! empty($block->selectors)) {
 145              if ($closeBlock) {
 146                  $this->write($closeBlock);
 147                  $closeBlock = '';
 148              }
 149  
 150              if ($downLevel) {
 151                  $this->write($downLevel);
 152                  $downLevel = '';
 153              }
 154  
 155              $this->blockSelectors($block);
 156  
 157              $this->indentLevel++;
 158          }
 159  
 160          if (! empty($block->lines)) {
 161              if ($closeBlock) {
 162                  $this->write($closeBlock);
 163                  $closeBlock = '';
 164              }
 165  
 166              if ($downLevel) {
 167                  $this->write($downLevel);
 168                  $downLevel = '';
 169              }
 170  
 171              $this->blockLines($block);
 172  
 173              $closeBlock = $this->break;
 174          }
 175  
 176          if (! empty($block->children)) {
 177              if ($this->depth > 0 && ($isMediaOrDirective || ! $this->hasFlatChild($block))) {
 178                  array_pop($depths);
 179  
 180                  $this->depth--;
 181                  $this->blockChildren($block);
 182                  $this->depth++;
 183  
 184                  $depths[] = $block->depth;
 185              } else {
 186                  $this->blockChildren($block);
 187              }
 188          }
 189  
 190          // reclear to not be spoiled by children if T_DIRECTIVE
 191          if ($block->type === Type::T_DIRECTIVE) {
 192              $previousHasSelector = false;
 193          }
 194  
 195          if (! empty($block->selectors)) {
 196              $this->indentLevel--;
 197  
 198              if (! $this->keepSemicolons) {
 199                  $this->strippedSemicolon = '';
 200              }
 201  
 202              $this->write($this->close);
 203  
 204              $closeBlock = $this->break;
 205  
 206              if ($this->depth > 1 && ! empty($block->children)) {
 207                  array_pop($depths);
 208                  $this->depth--;
 209              }
 210  
 211              if (! $isMediaOrDirective) {
 212                  $previousHasSelector = true;
 213              }
 214          }
 215  
 216          if ($block->type === 'root') {
 217              $this->write($this->break);
 218          }
 219      }
 220  
 221      /**
 222       * Block has flat child
 223       *
 224       * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block
 225       *
 226       * @return bool
 227       */
 228      private function hasFlatChild($block)
 229      {
 230          foreach ($block->children as $child) {
 231              if (empty($child->selectors)) {
 232                  return true;
 233              }
 234          }
 235  
 236          return false;
 237      }
 238  }