Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.
<?php
>
/** * SCSSPHP *
< * @copyright 2012-2019 Leaf Corcoran
> * @copyright 2012-2020 Leaf Corcoran
* * @license http://opensource.org/licenses/MIT MIT * * @link http://scssphp.github.io/scssphp */ namespace ScssPhp\ScssPhp; use ScssPhp\ScssPhp\Formatter\OutputBlock; use ScssPhp\ScssPhp\SourceMap\SourceMapGenerator; /** * Base formatter * * @author Leaf Corcoran <leafot@gmail.com>
> * */ > * @internal
abstract class Formatter { /**
< * @var integer
> * @var int
*/ public $indentLevel; /** * @var string */ public $indentChar; /** * @var string */ public $break; /** * @var string */ public $open; /** * @var string */ public $close; /** * @var string */ public $tagSeparator; /** * @var string */ public $assignSeparator; /**
< * @var boolean
> * @var bool
*/ public $keepSemicolons; /** * @var \ScssPhp\ScssPhp\Formatter\OutputBlock */ protected $currentBlock; /**
< * @var integer
> * @var int
*/ protected $currentLine; /**
< * @var integer
> * @var int
*/ protected $currentColumn; /**
< * @var \ScssPhp\ScssPhp\SourceMap\SourceMapGenerator
> * @var \ScssPhp\ScssPhp\SourceMap\SourceMapGenerator|null
*/ protected $sourceMapGenerator; /** * @var string */ protected $strippedSemicolon; /** * Initialize formatter * * @api */ abstract public function __construct(); /** * Return indentation (whitespace) * * @return string */ protected function indentStr() { return ''; } /** * Return property assignment * * @api * * @param string $name * @param mixed $value * * @return string */ public function property($name, $value) { return rtrim($name) . $this->assignSeparator . $value . ';'; } /**
> * Return custom property assignment * Output lines inside a block > * differs in that you have to keep spaces in the value as is * > * * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block > * @api */ > * protected function blockLines(OutputBlock $block) > * @param string $name { > * @param mixed $value $inner = $this->indentStr(); > * > * @return string $glue = $this->break . $inner; > */ > public function customProperty($name, $value) $this->write($inner . implode($glue, $block->lines)); > { > return rtrim($name) . trim($this->assignSeparator) . $value . ';'; if (! empty($block->children)) { > } $this->write($this->break); > } > /**
}
> * > * @return void
<
* Output block selectors * * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block
> * */ > * @return void
protected function blockSelectors(OutputBlock $block) {
> assert(! empty($block->selectors)); $inner = $this->indentStr(); >
$this->write($inner . implode($this->tagSeparator, $block->selectors) . $this->open . $this->break); } /** * Output block children * * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block
> * */ > * @return void
protected function blockChildren(OutputBlock $block) { foreach ($block->children as $child) { $this->block($child); } } /** * Output non-empty block * * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block
> * */ > * @return void
protected function block(OutputBlock $block) { if (empty($block->lines) && empty($block->children)) { return; } $this->currentBlock = $block; $pre = $this->indentStr(); if (! empty($block->selectors)) { $this->blockSelectors($block); $this->indentLevel++; } if (! empty($block->lines)) { $this->blockLines($block); } if (! empty($block->children)) { $this->blockChildren($block); } if (! empty($block->selectors)) { $this->indentLevel--; if (! $this->keepSemicolons) { $this->strippedSemicolon = ''; } if (empty($block->children)) { $this->write($this->break); } $this->write($pre . $this->close . $this->break); } } /** * Test and clean safely empty children * * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block *
< * @return boolean
> * @return bool
*/ protected function testEmptyChildren($block) { $isEmpty = empty($block->lines); if ($block->children) { foreach ($block->children as $k => &$child) { if (! $this->testEmptyChildren($child)) { $isEmpty = false; continue; } if ($child->type === Type::T_MEDIA || $child->type === Type::T_DIRECTIVE) { $child->children = []; $child->selectors = null; } } } return $isEmpty; } /** * Entry point to formatting a block * * @api * * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block An abstract syntax tree * @param \ScssPhp\ScssPhp\SourceMap\SourceMapGenerator|null $sourceMapGenerator Optional source map generator * * @return string */ public function format(OutputBlock $block, SourceMapGenerator $sourceMapGenerator = null) { $this->sourceMapGenerator = null; if ($sourceMapGenerator) { $this->currentLine = 1; $this->currentColumn = 0; $this->sourceMapGenerator = $sourceMapGenerator; } $this->testEmptyChildren($block); ob_start();
> try {
$this->block($block);
> } catch (\Exception $e) { > ob_end_clean(); $out = ob_get_clean(); > throw $e; > } catch (\Throwable $e) { return $out; > ob_end_clean(); } > throw $e; > }
/**
> assert($out !== false);
* Output content * * @param string $str
> * */ > * @return void
protected function write($str) { if (! empty($this->strippedSemicolon)) { echo $this->strippedSemicolon; $this->strippedSemicolon = ''; } /* * Maybe Strip semi-colon appended by property(); it's a separator, not a terminator * will be striped for real before a closing, otherwise displayed unchanged starting the next write */
< if (! $this->keepSemicolons &&
> if ( > ! $this->keepSemicolons &&
$str && (strpos($str, ';') !== false) && (substr($str, -1) === ';') ) { $str = substr($str, 0, -1); $this->strippedSemicolon = ';'; } if ($this->sourceMapGenerator) {
> $lines = explode("\n", $str); $this->sourceMapGenerator->addMapping( > $lastLine = array_pop($lines); $this->currentLine, > $this->currentColumn, > foreach ($lines as $line) { $this->currentBlock->sourceLine, > // If the written line starts is empty, adding a mapping would add it for //columns from parser are off by one > // a non-existent column as we are at the end of the line $this->currentBlock->sourceColumn > 0 ? $this->currentBlock->sourceColumn - 1 : 0, > if ($line !== '') { $this->currentBlock->sourceName > assert($this->currentBlock->sourceLine !== null); ); > assert($this->currentBlock->sourceName !== null);
> }
< $lines = explode("\n", $str); < $lineCount = count($lines); < $this->currentLine += $lineCount-1;
> $this->currentLine++; > $this->currentColumn = 0; > }
< $lastLine = array_pop($lines);
> if ($lastLine !== '') { > assert($this->currentBlock->sourceLine !== null); > assert($this->currentBlock->sourceName !== null); > $this->sourceMapGenerator->addMapping( > $this->currentLine, > $this->currentColumn, > $this->currentBlock->sourceLine, > //columns from parser are off by one > $this->currentBlock->sourceColumn > 0 ? $this->currentBlock->sourceColumn - 1 : 0, > $this->currentBlock->sourceName > ); > }
< $this->currentColumn = ($lineCount === 1 ? $this->currentColumn : 0) + strlen($lastLine);
> $this->currentColumn += \strlen($lastLine);
} echo $str; } }