aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/scssphp/scssphp/src/Formatter.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/scssphp/scssphp/src/Formatter.php')
-rw-r--r--vendor/scssphp/scssphp/src/Formatter.php377
1 files changed, 377 insertions, 0 deletions
diff --git a/vendor/scssphp/scssphp/src/Formatter.php b/vendor/scssphp/scssphp/src/Formatter.php
new file mode 100644
index 000000000..6137dc650
--- /dev/null
+++ b/vendor/scssphp/scssphp/src/Formatter.php
@@ -0,0 +1,377 @@
+<?php
+
+/**
+ * SCSSPHP
+ *
+ * @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 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 bool
+ */
+ public $keepSemicolons;
+
+ /**
+ * @var \ScssPhp\ScssPhp\Formatter\OutputBlock
+ */
+ protected $currentBlock;
+
+ /**
+ * @var int
+ */
+ protected $currentLine;
+
+ /**
+ * @var int
+ */
+ protected $currentColumn;
+
+ /**
+ * @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
+ * differs in that you have to keep spaces in the value as is
+ *
+ * @api
+ *
+ * @param string $name
+ * @param mixed $value
+ *
+ * @return string
+ */
+ public function customProperty($name, $value)
+ {
+ return rtrim($name) . trim($this->assignSeparator) . $value . ';';
+ }
+
+ /**
+ * Output lines inside a block
+ *
+ * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block
+ *
+ * @return void
+ */
+ protected function blockLines(OutputBlock $block)
+ {
+ $inner = $this->indentStr();
+ $glue = $this->break . $inner;
+
+ $this->write($inner . implode($glue, $block->lines));
+
+ if (! empty($block->children)) {
+ $this->write($this->break);
+ }
+ }
+
+ /**
+ * 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 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();
+ throw $e;
+ } catch (\Throwable $e) {
+ ob_end_clean();
+ throw $e;
+ }
+
+ $out = ob_get_clean();
+ assert($out !== false);
+
+ return $out;
+ }
+
+ /**
+ * 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 &&
+ $str &&
+ (strpos($str, ';') !== false) &&
+ (substr($str, -1) === ';')
+ ) {
+ $str = substr($str, 0, -1);
+
+ $this->strippedSemicolon = ';';
+ }
+
+ if ($this->sourceMapGenerator) {
+ $lines = explode("\n", $str);
+ $lastLine = array_pop($lines);
+
+ foreach ($lines as $line) {
+ // If the written line starts is empty, adding a mapping would add it for
+ // a non-existent column as we are at the end of the line
+ if ($line !== '') {
+ 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->currentLine++;
+ $this->currentColumn = 0;
+ }
+
+ 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 += \strlen($lastLine);
+ }
+
+ echo $str;
+ }
+}