diff --git a/src/CSSList/AtRuleBlockList.php b/src/CSSList/AtRuleBlockList.php index 218adb9a..598fefc1 100644 --- a/src/CSSList/AtRuleBlockList.php +++ b/src/CSSList/AtRuleBlockList.php @@ -61,13 +61,14 @@ public function __toString() */ public function render(OutputFormat $oOutputFormat) { + $sResult = $oOutputFormat->comments($this); + $sResult .= $oOutputFormat->sBeforeAtRuleBlock; $sArgs = $this->sArgs; if ($sArgs) { $sArgs = ' ' . $sArgs; } - $sResult = $oOutputFormat->sBeforeAtRuleBlock; $sResult .= "@{$this->sType}$sArgs{$oOutputFormat->spaceBeforeOpeningBrace()}{"; - $sResult .= parent::render($oOutputFormat); + $sResult .= $this->renderListContents($oOutputFormat); $sResult .= '}'; $sResult .= $oOutputFormat->sAfterAtRuleBlock; return $sResult; diff --git a/src/CSSList/CSSList.php b/src/CSSList/CSSList.php index 946740a4..f21d7f75 100644 --- a/src/CSSList/CSSList.php +++ b/src/CSSList/CSSList.php @@ -69,8 +69,9 @@ public static function parseList(ParserState $oParserState, CSSList $oList) $oParserState = new ParserState($oParserState, Settings::create()); } $bLenientParsing = $oParserState->getSettings()->bLenientParsing; + $aComments = []; while (!$oParserState->isEnd()) { - $comments = $oParserState->consumeWhiteSpace(); + $aComments = array_merge($aComments, $oParserState->consumeWhiteSpace()); $oListItem = null; if ($bLenientParsing) { try { @@ -86,11 +87,12 @@ public static function parseList(ParserState $oParserState, CSSList $oList) return; } if ($oListItem) { - $oListItem->setComments($comments); + $oListItem->addComments($aComments); $oList->append($oListItem); } - $oParserState->consumeWhiteSpace(); + $aComments = $oParserState->consumeWhiteSpace(); } + $oList->addComments($aComments); if (!$bIsRoot && !$bLenientParsing) { throw new SourceException("Unexpected end of document", $oParserState->currentLine()); } @@ -125,7 +127,7 @@ private static function parseListItem(ParserState $oParserState, CSSList $oList) $oParserState->currentLine() ); } - $oParserState->setCharset($oAtRule->getCharset()->getString()); + $oParserState->setCharset($oAtRule->getCharset()); } return $oAtRule; } elseif ($oParserState->comes('}')) { @@ -172,10 +174,10 @@ private static function parseAtRule(ParserState $oParserState) $oParserState->consumeUntil([';', ParserState::EOF], true, true); return new Import($oLocation, $sMediaQuery ?: null, $iIdentifierLineNum); } elseif ($sIdentifier === 'charset') { - $sCharset = CSSString::parse($oParserState); + $oCharsetString = CSSString::parse($oParserState); $oParserState->consumeWhiteSpace(); $oParserState->consumeUntil([';', ParserState::EOF], true, true); - return new Charset($sCharset, $iIdentifierLineNum); + return new Charset($oCharsetString, $iIdentifierLineNum); } elseif (self::identifierIs($sIdentifier, 'keyframes')) { $oResult = new KeyFrame($iIdentifierLineNum); $oResult->setVendorKeyFrame($sIdentifier); @@ -402,7 +404,7 @@ public function __toString() /** * @return string */ - public function render(OutputFormat $oOutputFormat) + protected function renderListContents(OutputFormat $oOutputFormat) { $sResult = ''; $bIsFirst = true; diff --git a/src/CSSList/Document.php b/src/CSSList/Document.php index 91ab2c6b..b2f50434 100644 --- a/src/CSSList/Document.php +++ b/src/CSSList/Document.php @@ -159,7 +159,7 @@ public function render(OutputFormat $oOutputFormat = null) if ($oOutputFormat === null) { $oOutputFormat = new OutputFormat(); } - return parent::render($oOutputFormat); + return $oOutputFormat->comments($this) . $this->renderListContents($oOutputFormat); } /** diff --git a/src/CSSList/KeyFrame.php b/src/CSSList/KeyFrame.php index d9420e9c..caef7b3d 100644 --- a/src/CSSList/KeyFrame.php +++ b/src/CSSList/KeyFrame.php @@ -72,8 +72,9 @@ public function __toString() */ public function render(OutputFormat $oOutputFormat) { - $sResult = "@{$this->vendorKeyFrame} {$this->animationName}{$oOutputFormat->spaceBeforeOpeningBrace()}{"; - $sResult .= parent::render($oOutputFormat); + $sResult = $oOutputFormat->comments($this); + $sResult .= "@{$this->vendorKeyFrame} {$this->animationName}{$oOutputFormat->spaceBeforeOpeningBrace()}{"; + $sResult .= $this->renderListContents($oOutputFormat); $sResult .= '}'; return $sResult; } diff --git a/src/OutputFormat.php b/src/OutputFormat.php index 595d3064..96f26e14 100644 --- a/src/OutputFormat.php +++ b/src/OutputFormat.php @@ -143,6 +143,13 @@ class OutputFormat */ public $bIgnoreExceptions = false; + /** + * Render comments for lists and RuleSets + * + * @var bool + */ + public $bRenderComments = false; + /** * @var OutputFormatter|null */ @@ -314,8 +321,12 @@ public static function create() public static function createCompact() { $format = self::create(); - $format->set('Space*Rules', "")->set('Space*Blocks', "")->setSpaceAfterRuleName('') - ->setSpaceBeforeOpeningBrace('')->setSpaceAfterSelectorSeparator(''); + $format->set('Space*Rules', "") + ->set('Space*Blocks', "") + ->setSpaceAfterRuleName('') + ->setSpaceBeforeOpeningBrace('') + ->setSpaceAfterSelectorSeparator('') + ->setRenderComments(false); return $format; } @@ -327,8 +338,11 @@ public static function createCompact() public static function createPretty() { $format = self::create(); - $format->set('Space*Rules', "\n")->set('Space*Blocks', "\n") - ->setSpaceBetweenBlocks("\n\n")->set('SpaceAfterListArgumentSeparator', ['default' => '', ',' => ' ']); + $format->set('Space*Rules', "\n") + ->set('Space*Blocks', "\n") + ->setSpaceBetweenBlocks("\n\n") + ->set('SpaceAfterListArgumentSeparator', ['default' => '', ',' => ' ']) + ->setRenderComments(true); return $format; } } diff --git a/src/OutputFormatter.php b/src/OutputFormatter.php index 535feca7..7418494c 100644 --- a/src/OutputFormatter.php +++ b/src/OutputFormatter.php @@ -2,6 +2,7 @@ namespace Sabberworm\CSS; +use Sabberworm\CSS\Comment\Commentable; use Sabberworm\CSS\Parsing\OutputException; class OutputFormatter @@ -211,6 +212,28 @@ public function removeLastSemicolon($sString) return implode(';', $sString); } + /** + * + * @param array $aComments + * @return string + */ + public function comments(Commentable $oCommentable) + { + if (!$this->oFormat->bRenderComments) { + return ''; + } + + $sResult = ''; + $aComments = $oCommentable->getComments(); + $iLastCommentIndex = count($aComments) - 1; + + foreach ($aComments as $i => $oComment) { + $sResult .= $oComment->render($this->oFormat); + $sResult .= $i === $iLastCommentIndex ? $this->spaceAfterBlocks() : $this->spaceBetweenBlocks(); + } + return $sResult; + } + /** * @param string $sSpaceString * diff --git a/src/Parsing/ParserState.php b/src/Parsing/ParserState.php index e7d85ee0..df18f557 100644 --- a/src/Parsing/ParserState.php +++ b/src/Parsing/ParserState.php @@ -204,7 +204,7 @@ public function parseCharacter($bIsForIdentifier) */ public function consumeWhiteSpace() { - $comments = []; + $aComments = []; do { while (preg_match('/\\s/isSu', $this->peek()) === 1) { $this->consume(1); @@ -214,16 +214,16 @@ public function consumeWhiteSpace() $oComment = $this->consumeComment(); } catch (UnexpectedEOFException $e) { $this->iCurrentPosition = $this->iLength; - return; + return $aComments; } } else { $oComment = $this->consumeComment(); } if ($oComment !== false) { - $comments[] = $oComment; + $aComments[] = $oComment; } } while ($oComment !== false); - return $comments; + return $aComments; } /** diff --git a/src/Property/Charset.php b/src/Property/Charset.php index 3ee0c3d0..26e1b250 100644 --- a/src/Property/Charset.php +++ b/src/Property/Charset.php @@ -4,6 +4,7 @@ use Sabberworm\CSS\Comment\Comment; use Sabberworm\CSS\OutputFormat; +use Sabberworm\CSS\Value\CSSString; /** * Class representing an `@charset` rule. @@ -16,9 +17,9 @@ class Charset implements AtRule { /** - * @var string + * @var CSSString */ - private $sCharset; + private $oCharset; /** * @var int @@ -31,12 +32,12 @@ class Charset implements AtRule protected $aComments; /** - * @param string $sCharset + * @param CSSString $oCharset * @param int $iLineNo */ - public function __construct($sCharset, $iLineNo = 0) + public function __construct(CSSString $oCharset, $iLineNo = 0) { - $this->sCharset = $sCharset; + $this->oCharset = $oCharset; $this->iLineNo = $iLineNo; $this->aComments = []; } @@ -50,13 +51,14 @@ public function getLineNo() } /** - * @param string $sCharset + * @param string|CSSString $oCharset * * @return void */ public function setCharset($sCharset) { - $this->sCharset = $sCharset; + $sCharset = $sCharset instanceof CSSString ? $sCharset : new CSSString($sCharset); + $this->oCharset = $sCharset; } /** @@ -64,7 +66,7 @@ public function setCharset($sCharset) */ public function getCharset() { - return $this->sCharset; + return $this->oCharset->getString(); } /** @@ -80,7 +82,7 @@ public function __toString() */ public function render(OutputFormat $oOutputFormat) { - return "@charset {$this->sCharset->render($oOutputFormat)};"; + return "{$oOutputFormat->comments($this)}@charset {$this->oCharset->render($oOutputFormat)};"; } /** @@ -96,7 +98,7 @@ public function atRuleName() */ public function atRuleArgs() { - return $this->sCharset; + return $this->oCharset; } /** diff --git a/src/Property/Import.php b/src/Property/Import.php index a2253016..43d9f0d2 100644 --- a/src/Property/Import.php +++ b/src/Property/Import.php @@ -83,7 +83,7 @@ public function __toString() */ public function render(OutputFormat $oOutputFormat) { - return "@import " . $this->oLocation->render($oOutputFormat) + return $oOutputFormat->comments($this) . "@import " . $this->oLocation->render($oOutputFormat) . ($this->sMediaQuery === null ? '' : ' ' . $this->sMediaQuery) . ';'; } diff --git a/src/Rule/Rule.php b/src/Rule/Rule.php index c1ea6df7..ac60aa4c 100644 --- a/src/Rule/Rule.php +++ b/src/Rule/Rule.php @@ -346,8 +346,8 @@ public function __toString() */ public function render(OutputFormat $oOutputFormat) { - $sResult = "{$this->sRule}:{$oOutputFormat->spaceAfterRuleName()}"; - if ($this->mValue instanceof Value) { //Can also be a ValueList + $sResult = "{$oOutputFormat->comments($this)}{$this->sRule}:{$oOutputFormat->spaceAfterRuleName()}"; + if ($this->mValue instanceof Value) { // Can also be a ValueList $sResult .= $this->mValue->render($oOutputFormat); } else { $sResult .= $this->mValue; diff --git a/src/RuleSet/AtRuleSet.php b/src/RuleSet/AtRuleSet.php index 88bc5bd3..50958ef2 100644 --- a/src/RuleSet/AtRuleSet.php +++ b/src/RuleSet/AtRuleSet.php @@ -61,12 +61,13 @@ public function __toString() */ public function render(OutputFormat $oOutputFormat) { + $sResult = $oOutputFormat->comments($this); $sArgs = $this->sArgs; if ($sArgs) { $sArgs = ' ' . $sArgs; } - $sResult = "@{$this->sType}$sArgs{$oOutputFormat->spaceBeforeOpeningBrace()}{"; - $sResult .= parent::render($oOutputFormat); + $sResult .= "@{$this->sType}$sArgs{$oOutputFormat->spaceBeforeOpeningBrace()}{"; + $sResult .= $this->renderRules($oOutputFormat); $sResult .= '}'; return $sResult; } diff --git a/src/RuleSet/DeclarationBlock.php b/src/RuleSet/DeclarationBlock.php index c27cdd4c..3bebda67 100644 --- a/src/RuleSet/DeclarationBlock.php +++ b/src/RuleSet/DeclarationBlock.php @@ -812,18 +812,19 @@ public function __toString() */ public function render(OutputFormat $oOutputFormat) { + $sResult = $oOutputFormat->comments($this); if (count($this->aSelectors) === 0) { // If all the selectors have been removed, this declaration block becomes invalid throw new OutputException("Attempt to print declaration block with missing selector", $this->iLineNo); } - $sResult = $oOutputFormat->sBeforeDeclarationBlock; + $sResult .= $oOutputFormat->sBeforeDeclarationBlock; $sResult .= $oOutputFormat->implode( $oOutputFormat->spaceBeforeSelectorSeparator() . ',' . $oOutputFormat->spaceAfterSelectorSeparator(), $this->aSelectors ); $sResult .= $oOutputFormat->sAfterDeclarationBlockSelectors; $sResult .= $oOutputFormat->spaceBeforeOpeningBrace() . '{'; - $sResult .= parent::render($oOutputFormat); + $sResult .= $this->renderRules($oOutputFormat); $sResult .= '}'; $sResult .= $oOutputFormat->sAfterDeclarationBlock; return $sResult; diff --git a/src/RuleSet/RuleSet.php b/src/RuleSet/RuleSet.php index 9404bb0b..e7f4b82d 100644 --- a/src/RuleSet/RuleSet.php +++ b/src/RuleSet/RuleSet.php @@ -266,23 +266,24 @@ public function __toString() /** * @return string */ - public function render(OutputFormat $oOutputFormat) + protected function renderRules(OutputFormat $oOutputFormat) { $sResult = ''; $bIsFirst = true; + $oNextLevel = $oOutputFormat->nextLevel(); foreach ($this->aRules as $aRules) { foreach ($aRules as $oRule) { - $sRendered = $oOutputFormat->safely(function () use ($oRule, $oOutputFormat) { - return $oRule->render($oOutputFormat->nextLevel()); + $sRendered = $oNextLevel->safely(function () use ($oRule, $oNextLevel) { + return $oRule->render($oNextLevel); }); if ($sRendered === null) { continue; } if ($bIsFirst) { $bIsFirst = false; - $sResult .= $oOutputFormat->nextLevel()->spaceBeforeRules(); + $sResult .= $oNextLevel->spaceBeforeRules(); } else { - $sResult .= $oOutputFormat->nextLevel()->spaceBetweenRules(); + $sResult .= $oNextLevel->spaceBetweenRules(); } $sResult .= $sRendered; } diff --git a/tests/Comment/CommentTest.php b/tests/Comment/CommentTest.php new file mode 100644 index 00000000..d4d67b09 --- /dev/null +++ b/tests/Comment/CommentTest.php @@ -0,0 +1,85 @@ +render(OutputFormat::createPretty())); + self::assertSame( + '/** Number 11 **//**' . "\n" + . ' * Comments' . "\n" + . ' *//* Hell */@import url("some/url.css") screen;' + . '/* Number 4 *//* Number 5 */.foo,#bar{' + . '/* Number 6 */background-color:#000;}@media screen{' + . '/** Number 10 **/#foo.bar{/** Number 10b **/position:absolute;}}', + $oCss->render(OutputFormat::createCompact()->setRenderComments(true)) + ); + } + + /** + * @test + */ + public function stripCommentsFromOutput() + { + $oCss = TestsParserTest::parsedStructureForFile('comments'); + self::assertSame(' +@import url("some/url.css") screen; + +.foo, #bar { + background-color: #000; +} + +@media screen { + #foo.bar { + position: absolute; + } +} +', $oCss->render(OutputFormat::createPretty()->setRenderComments(false))); + self::assertSame( + '@import url("some/url.css") screen;' + . '.foo,#bar{background-color:#000;}' + . '@media screen{#foo.bar{position:absolute;}}', + $oCss->render(OutputFormat::createCompact()) + ); + } +} diff --git a/tests/ParserTest.php b/tests/ParserTest.php index ab247c3d..c7023cbc 100644 --- a/tests/ParserTest.php +++ b/tests/ParserTest.php @@ -5,6 +5,7 @@ use PHPUnit\Framework\TestCase; use Sabberworm\CSS\CSSList\Document; use Sabberworm\CSS\CSSList\KeyFrame; +use Sabberworm\CSS\OutputFormat; use Sabberworm\CSS\Parser; use Sabberworm\CSS\Parsing\UnexpectedTokenException; use Sabberworm\CSS\Property\AtRule; @@ -89,7 +90,7 @@ public function files() */ public function colorParsing() { - $oDoc = $this->parsedStructureForFile('colortest'); + $oDoc = self::parsedStructureForFile('colortest'); foreach ($oDoc->getAllRuleSets() as $oRuleSet) { if (!$oRuleSet instanceof DeclarationBlock) { continue; @@ -169,7 +170,7 @@ public function colorParsing() */ public function unicodeParsing() { - $oDoc = $this->parsedStructureForFile('unicode'); + $oDoc = self::parsedStructureForFile('unicode'); foreach ($oDoc->getAllDeclarationBlocks() as $oRuleSet) { $sSelector = $oRuleSet->getSelectors(); $sSelector = $sSelector[0]->getSelector(); @@ -220,7 +221,7 @@ public function unicodeParsing() */ public function unicodeRangeParsing() { - $oDoc = $this->parsedStructureForFile('unicode-range'); + $oDoc = self::parsedStructureForFile('unicode-range'); $sExpected = "@font-face {unicode-range: U+0100-024F,U+0259,U+1E??-2EFF,U+202F;}"; self::assertSame($sExpected, $oDoc->render()); } @@ -230,7 +231,7 @@ public function unicodeRangeParsing() */ public function specificity() { - $oDoc = $this->parsedStructureForFile('specificity'); + $oDoc = self::parsedStructureForFile('specificity'); $oDeclarationBlock = $oDoc->getAllDeclarationBlocks(); $oDeclarationBlock = $oDeclarationBlock[0]; $aSelectors = $oDeclarationBlock->getSelectors(); @@ -282,7 +283,7 @@ public function specificity() */ public function manipulation() { - $oDoc = $this->parsedStructureForFile('atrules'); + $oDoc = self::parsedStructureForFile('atrules'); self::assertSame( '@charset "utf-8";' . "\n" @@ -353,10 +354,10 @@ public function manipulation() . '@media screen and (orientation: landscape) {@-ms-viewport {width: 1024px;height: 768px;}}' . "\n" . '@region-style #intro {#my_id p {color: blue;}}', - $oDoc->render() + $oDoc->render(OutputFormat::create()->setRenderComments(false)) ); - $oDoc = $this->parsedStructureForFile('values'); + $oDoc = self::parsedStructureForFile('values'); self::assertSame( '#header {margin: 10px 2em 1cm 2%;font-family: Verdana,Helvetica,"Gill Sans",sans-serif;' . 'font-size: 10px;color: red !important;background-color: green;' @@ -388,7 +389,7 @@ public function manipulation() */ public function ruleGetters() { - $oDoc = $this->parsedStructureForFile('values'); + $oDoc = self::parsedStructureForFile('values'); $aBlocks = $oDoc->getAllDeclarationBlocks(); $oHeaderBlock = $aBlocks[0]; $oBodyBlock = $aBlocks[1]; @@ -411,7 +412,7 @@ public function ruleGetters() */ public function slashedValues() { - $oDoc = $this->parsedStructureForFile('slashed'); + $oDoc = self::parsedStructureForFile('slashed'); self::assertSame( '.test {font: 12px/1.5 Verdana,Arial,sans-serif;border-radius: 5px 10px 5px 10px/10px 5px 10px 5px;}', $oDoc->render() @@ -452,7 +453,7 @@ public function slashedValues() */ public function functionSyntax() { - $oDoc = $this->parsedStructureForFile('functions'); + $oDoc = self::parsedStructureForFile('functions'); $sExpected = 'div.main {background-image: linear-gradient(#000,#fff);}' . "\n" . '.collapser::before, .collapser::-moz-before, .collapser::-webkit-before {content: "»";font-size: 1.2em;' @@ -490,7 +491,7 @@ public function functionSyntax() */ public function expandShorthands() { - $oDoc = $this->parsedStructureForFile('expand-shorthands'); + $oDoc = self::parsedStructureForFile('expand-shorthands'); $sExpected = 'body {font: italic 500 14px/1.618 "Trebuchet MS",Georgia,serif;border: 2px solid #f0f;' . 'background: #ccc url("/images/foo.png") no-repeat left top;margin: 1em !important;' . 'padding: 2px 6px 3px;}'; @@ -514,7 +515,7 @@ public function expandShorthands() */ public function createShorthands() { - $oDoc = $this->parsedStructureForFile('create-shorthands'); + $oDoc = self::parsedStructureForFile('create-shorthands'); $sExpected = 'body {font-size: 2em;font-family: Helvetica,Arial,sans-serif;font-weight: bold;' . 'border-width: 2px;border-color: #999;border-style: dotted;background-color: #fff;' . 'background-image: url("foobar.png");background-repeat: repeat-y;margin-top: 2px;margin-right: 3px;' @@ -531,7 +532,7 @@ public function createShorthands() */ public function namespaces() { - $oDoc = $this->parsedStructureForFile('namespaces'); + $oDoc = self::parsedStructureForFile('namespaces'); $sExpected = '@namespace toto "http://toto.example.org"; @namespace "http://example.com/foo"; @namespace foo url("http://www.example.com/"); @@ -546,7 +547,7 @@ public function namespaces() */ public function innerColors() { - $oDoc = $this->parsedStructureForFile('inner-color'); + $oDoc = self::parsedStructureForFile('inner-color'); $sExpected = 'test {background: -webkit-gradient(linear,0 0,0 bottom,from(#006cad),to(hsl(202,100%,49%)));}'; self::assertSame($sExpected, $oDoc->render()); } @@ -556,7 +557,7 @@ public function innerColors() */ public function prefixedGradient() { - $oDoc = $this->parsedStructureForFile('webkit'); + $oDoc = self::parsedStructureForFile('webkit'); $sExpected = '.test {background: -webkit-linear-gradient(top right,white,black);}'; self::assertSame($sExpected, $oDoc->render()); } @@ -566,7 +567,7 @@ public function prefixedGradient() */ public function listValueRemoval() { - $oDoc = $this->parsedStructureForFile('atrules'); + $oDoc = self::parsedStructureForFile('atrules'); foreach ($oDoc->getContents() as $oItem) { if ($oItem instanceof AtRule) { $oDoc->remove($oItem); @@ -575,7 +576,7 @@ public function listValueRemoval() } self::assertSame('html, body {font-size: -.6em;}', $oDoc->render()); - $oDoc = $this->parsedStructureForFile('nested'); + $oDoc = self::parsedStructureForFile('nested'); foreach ($oDoc->getAllDeclarationBlocks() as $oBlock) { $oDoc->removeDeclarationBlockBySelector($oBlock, false); break; @@ -587,7 +588,7 @@ public function listValueRemoval() $oDoc->render() ); - $oDoc = $this->parsedStructureForFile('nested'); + $oDoc = self::parsedStructureForFile('nested'); foreach ($oDoc->getAllDeclarationBlocks() as $oBlock) { $oDoc->removeDeclarationBlockBySelector($oBlock, true); break; @@ -606,7 +607,7 @@ public function listValueRemoval() */ public function selectorRemoval() { - $oDoc = $this->parsedStructureForFile('1readme'); + $oDoc = self::parsedStructureForFile('1readme'); $aBlocks = $oDoc->getAllDeclarationBlocks(); $oBlock1 = $aBlocks[0]; self::assertTrue($oBlock1->removeSelector('html')); @@ -625,10 +626,12 @@ public function selectorRemoval() */ public function comments() { - $oDoc = $this->parsedStructureForFile('comments'); - $sExpected = '@import url("some/url.css") screen; + $oDoc = self::parsedStructureForFile('comments'); + $sExpected = <<render()); } @@ -637,7 +640,7 @@ public function comments() */ public function urlInFile() { - $oDoc = $this->parsedStructureForFile('url', Settings::create()->withMultibyteSupport(true)); + $oDoc = self::parsedStructureForFile('url', Settings::create()->withMultibyteSupport(true)); $sExpected = 'body {background: #fff url("https://somesite.com/images/someimage.gif") repeat top center;} body {background-url: url("https://somesite.com/images/someimage.gif");}'; self::assertSame($sExpected, $oDoc->render()); @@ -648,7 +651,7 @@ public function urlInFile() */ public function hexAlphaInFile() { - $oDoc = $this->parsedStructureForFile('hex-alpha', Settings::create()->withMultibyteSupport(true)); + $oDoc = self::parsedStructureForFile('hex-alpha', Settings::create()->withMultibyteSupport(true)); $sExpected = 'div {background: rgba(17,34,51,.27);} div {background: rgba(17,34,51,.27);}'; self::assertSame($sExpected, $oDoc->render()); @@ -659,7 +662,7 @@ public function hexAlphaInFile() */ public function calcInFile() { - $oDoc = $this->parsedStructureForFile('calc', Settings::create()->withMultibyteSupport(true)); + $oDoc = self::parsedStructureForFile('calc', Settings::create()->withMultibyteSupport(true)); $sExpected = 'div {width: calc(100% / 4);} div {margin-top: calc(-120% - 4px);} div {height: -webkit-calc(9 / 16 * 100%) !important;width: -moz-calc(( 50px - 50% ) * 2);} @@ -672,7 +675,7 @@ public function calcInFile() */ public function calcNestedInFile() { - $oDoc = $this->parsedStructureForFile('calc-nested', Settings::create()->withMultibyteSupport(true)); + $oDoc = self::parsedStructureForFile('calc-nested', Settings::create()->withMultibyteSupport(true)); $sExpected = '.test {font-size: calc(( 3 * 4px ) + -2px);top: calc(200px - calc(20 * 3px));}'; self::assertSame($sExpected, $oDoc->render()); } @@ -682,7 +685,7 @@ public function calcNestedInFile() */ public function gridLineNameInFile() { - $oDoc = $this->parsedStructureForFile('grid-linename', Settings::create()->withMultibyteSupport(true)); + $oDoc = self::parsedStructureForFile('grid-linename', Settings::create()->withMultibyteSupport(true)); $sExpected = "div {grid-template-columns: [linename] 100px;}\n" . "span {grid-template-columns: [linename1 linename2] 100px;}"; self::assertSame($sExpected, $oDoc->render()); @@ -693,7 +696,7 @@ public function gridLineNameInFile() */ public function emptyGridLineNameLenientInFile() { - $oDoc = $this->parsedStructureForFile('empty-grid-linename'); + $oDoc = self::parsedStructureForFile('empty-grid-linename'); $sExpected = '.test {grid-template-columns: [] 100px;}'; self::assertSame($sExpected, $oDoc->render()); } @@ -703,7 +706,7 @@ public function emptyGridLineNameLenientInFile() */ public function invalidGridLineNameInFile() { - $oDoc = $this->parsedStructureForFile('invalid-grid-linename', Settings::create()->withMultibyteSupport(true)); + $oDoc = self::parsedStructureForFile('invalid-grid-linename', Settings::create()->withMultibyteSupport(true)); $sExpected = "div {}"; self::assertSame($sExpected, $oDoc->render()); } @@ -713,7 +716,7 @@ public function invalidGridLineNameInFile() */ public function unmatchedBracesInFile() { - $oDoc = $this->parsedStructureForFile('unmatched_braces', Settings::create()->withMultibyteSupport(true)); + $oDoc = self::parsedStructureForFile('unmatched_braces', Settings::create()->withMultibyteSupport(true)); $sExpected = 'button, input, checkbox, textarea {outline: 0;margin: 0;}'; self::assertSame($sExpected, $oDoc->render()); } @@ -723,13 +726,13 @@ public function unmatchedBracesInFile() */ public function invalidSelectorsInFile() { - $oDoc = $this->parsedStructureForFile('invalid-selectors', Settings::create()->withMultibyteSupport(true)); + $oDoc = self::parsedStructureForFile('invalid-selectors', Settings::create()->withMultibyteSupport(true)); $sExpected = '@keyframes mymove {from {top: 0px;}} #test {color: white;background: green;} #test {display: block;background: white;color: black;}'; self::assertSame($sExpected, $oDoc->render()); - $oDoc = $this->parsedStructureForFile('invalid-selectors-2', Settings::create()->withMultibyteSupport(true)); + $oDoc = self::parsedStructureForFile('invalid-selectors-2', Settings::create()->withMultibyteSupport(true)); $sExpected = '@media only screen and (max-width: 1215px) {.breadcrumb {padding-left: 10px;} .super-menu > li:first-of-type {border-left-width: 0;} .super-menu > li:last-of-type {border-right-width: 0;} @@ -744,12 +747,12 @@ public function invalidSelectorsInFile() */ public function selectorEscapesInFile() { - $oDoc = $this->parsedStructureForFile('selector-escapes', Settings::create()->withMultibyteSupport(true)); + $oDoc = self::parsedStructureForFile('selector-escapes', Settings::create()->withMultibyteSupport(true)); $sExpected = '#\# {color: red;} .col-sm-1\/5 {width: 20%;}'; self::assertSame($sExpected, $oDoc->render()); - $oDoc = $this->parsedStructureForFile('invalid-selectors-2', Settings::create()->withMultibyteSupport(true)); + $oDoc = self::parsedStructureForFile('invalid-selectors-2', Settings::create()->withMultibyteSupport(true)); $sExpected = '@media only screen and (max-width: 1215px) {.breadcrumb {padding-left: 10px;} .super-menu > li:first-of-type {border-left-width: 0;} .super-menu > li:last-of-type {border-right-width: 0;} @@ -764,7 +767,7 @@ public function selectorEscapesInFile() */ public function identifierEscapesInFile() { - $oDoc = $this->parsedStructureForFile('identifier-escapes', Settings::create()->withMultibyteSupport(true)); + $oDoc = self::parsedStructureForFile('identifier-escapes', Settings::create()->withMultibyteSupport(true)); $sExpected = 'div {font: 14px Font Awesome\ 5 Pro;font: 14px Font Awesome\} 5 Pro;' . 'font: 14px Font Awesome\; 5 Pro;f\;ont: 14px Font Awesome\; 5 Pro;}'; self::assertSame($sExpected, $oDoc->render()); @@ -775,7 +778,7 @@ public function identifierEscapesInFile() */ public function selectorIgnoresInFile() { - $oDoc = $this->parsedStructureForFile('selector-ignores', Settings::create()->withMultibyteSupport(true)); + $oDoc = self::parsedStructureForFile('selector-ignores', Settings::create()->withMultibyteSupport(true)); $sExpected = '.some[selectors-may=\'contain-a-{\'] {}' . "\n" . '.this-selector .valid {width: 100px;}' @@ -789,7 +792,7 @@ public function selectorIgnoresInFile() */ public function keyframeSelectors() { - $oDoc = $this->parsedStructureForFile( + $oDoc = self::parsedStructureForFile( 'keyframe-selector-validation', Settings::create()->withMultibyteSupport(true) ); @@ -808,7 +811,7 @@ public function keyframeSelectors() */ public function lineNameFailure() { - $this->parsedStructureForFile('-empty-grid-linename', Settings::create()->withLenientParsing(false)); + self::parsedStructureForFile('-empty-grid-linename', Settings::create()->withLenientParsing(false)); } /** @@ -818,7 +821,7 @@ public function lineNameFailure() */ public function calcFailure() { - $this->parsedStructureForFile('-calc-no-space-around-minus', Settings::create()->withLenientParsing(false)); + self::parsedStructureForFile('-calc-no-space-around-minus', Settings::create()->withLenientParsing(false)); } /** @@ -826,7 +829,7 @@ public function calcFailure() */ public function urlInFileMbOff() { - $oDoc = $this->parsedStructureForFile('url', Settings::create()->withMultibyteSupport(false)); + $oDoc = self::parsedStructureForFile('url', Settings::create()->withMultibyteSupport(false)); $sExpected = 'body {background: #fff url("https://somesite.com/images/someimage.gif") repeat top center;}' . "\n" . 'body {background-url: url("https://somesite.com/images/someimage.gif");}'; @@ -838,7 +841,7 @@ public function urlInFileMbOff() */ public function emptyFile() { - $oDoc = $this->parsedStructureForFile('-empty', Settings::create()->withMultibyteSupport(true)); + $oDoc = self::parsedStructureForFile('-empty', Settings::create()->withMultibyteSupport(true)); $sExpected = ''; self::assertSame($sExpected, $oDoc->render()); } @@ -848,7 +851,7 @@ public function emptyFile() */ public function emptyFileMbOff() { - $oDoc = $this->parsedStructureForFile('-empty', Settings::create()->withMultibyteSupport(false)); + $oDoc = self::parsedStructureForFile('-empty', Settings::create()->withMultibyteSupport(false)); $sExpected = ''; self::assertSame($sExpected, $oDoc->render()); } @@ -858,7 +861,7 @@ public function emptyFileMbOff() */ public function charsetLenient1() { - $oDoc = $this->parsedStructureForFile('-charset-after-rule', Settings::create()->withLenientParsing(true)); + $oDoc = self::parsedStructureForFile('-charset-after-rule', Settings::create()->withLenientParsing(true)); $sExpected = '#id {prop: var(--val);}'; self::assertSame($sExpected, $oDoc->render()); } @@ -868,7 +871,7 @@ public function charsetLenient1() */ public function charsetLenient2() { - $oDoc = $this->parsedStructureForFile('-charset-in-block', Settings::create()->withLenientParsing(true)); + $oDoc = self::parsedStructureForFile('-charset-in-block', Settings::create()->withLenientParsing(true)); $sExpected = '@media print {}'; self::assertSame($sExpected, $oDoc->render()); } @@ -878,7 +881,7 @@ public function charsetLenient2() */ public function trailingWhitespace() { - $oDoc = $this->parsedStructureForFile('trailing-whitespace', Settings::create()->withLenientParsing(false)); + $oDoc = self::parsedStructureForFile('trailing-whitespace', Settings::create()->withLenientParsing(false)); $sExpected = 'div {width: 200px;}'; self::assertSame($sExpected, $oDoc->render()); } @@ -890,7 +893,7 @@ public function trailingWhitespace() */ public function charsetFailure1() { - $this->parsedStructureForFile('-charset-after-rule', Settings::create()->withLenientParsing(false)); + self::parsedStructureForFile('-charset-after-rule', Settings::create()->withLenientParsing(false)); } /** @@ -900,7 +903,7 @@ public function charsetFailure1() */ public function charsetFailure2() { - $this->parsedStructureForFile('-charset-in-block', Settings::create()->withLenientParsing(false)); + self::parsedStructureForFile('-charset-in-block', Settings::create()->withLenientParsing(false)); } /** @@ -910,7 +913,7 @@ public function charsetFailure2() */ public function unopenedClosingBracketFailure() { - $this->parsedStructureForFile('-unopened-close-brackets', Settings::create()->withLenientParsing(false)); + self::parsedStructureForFile('-unopened-close-brackets', Settings::create()->withLenientParsing(false)); } /** @@ -923,7 +926,7 @@ public function unopenedClosingBracketFailure() */ public function missingPropertyValueStrict() { - $this->parsedStructureForFile('missing-property-value', Settings::create()->withLenientParsing(false)); + self::parsedStructureForFile('missing-property-value', Settings::create()->withLenientParsing(false)); } /** @@ -935,7 +938,7 @@ public function missingPropertyValueStrict() */ public function missingPropertyValueLenient() { - $parsed = $this->parsedStructureForFile('missing-property-value', Settings::create()->withLenientParsing(true)); + $parsed = self::parsedStructureForFile('missing-property-value', Settings::create()->withLenientParsing(true)); $rulesets = $parsed->getAllRuleSets(); self::assertCount(1, $rulesets); $block = $rulesets[0]; @@ -956,7 +959,7 @@ public function missingPropertyValueLenient() * * @return Document parsed document */ - private function parsedStructureForFile($sFileName, $oSettings = null) + public static function parsedStructureForFile($sFileName, $oSettings = null) { $sFile = __DIR__ . "/fixtures/$sFileName.css"; $oParser = new Parser(file_get_contents($sFile), $oSettings); @@ -970,7 +973,7 @@ private function parsedStructureForFile($sFileName, $oSettings = null) */ public function lineNumbersParsing() { - $oDoc = $this->parsedStructureForFile('line-numbers'); + $oDoc = self::parsedStructureForFile('line-numbers'); // array key is the expected line number $aExpected = [ 1 => [Charset::class], @@ -1045,7 +1048,7 @@ public function unexpectedTokenExceptionLineNo() public function ieHacksStrictParsing() { // We can't strictly parse IE hacks. - $this->parsedStructureForFile('ie-hacks', Settings::create()->beStrict()); + self::parsedStructureForFile('ie-hacks', Settings::create()->beStrict()); } /** @@ -1053,7 +1056,7 @@ public function ieHacksStrictParsing() */ public function ieHacksParsing() { - $oDoc = $this->parsedStructureForFile('ie-hacks', Settings::create()->withLenientParsing(true)); + $oDoc = self::parsedStructureForFile('ie-hacks', Settings::create()->withLenientParsing(true)); $sExpected = 'p {padding-right: .75rem \9;background-image: none \9;color: red \9\0;' . 'background-color: red \9\0;background-color: red \9\0 !important;content: "red \0";content: "red઼";}'; self::assertSame($sExpected, $oDoc->render()); @@ -1066,13 +1069,14 @@ public function ieHacksParsing() */ public function commentExtracting() { - $oDoc = $this->parsedStructureForFile('comments'); + $oDoc = self::parsedStructureForFile('comments'); $aNodes = $oDoc->getContents(); // Import property. $importComments = $aNodes[0]->getComments(); - self::assertCount(1, $importComments); - self::assertSame("*\n * Comments Hell.\n ", $importComments[0]->getComment()); + self::assertCount(2, $importComments); + self::assertSame("*\n * Comments\n ", $importComments[0]->getComment()); + self::assertSame(" Hell ", $importComments[1]->getComment()); // Declaration block. $fooBarBlock = $aNodes[1]; @@ -1140,7 +1144,7 @@ public function topLevelCommentExtracting() */ public function microsoftFilterStrictParsing() { - $oDoc = $this->parsedStructureForFile('ms-filter', Settings::create()->beStrict()); + $oDoc = self::parsedStructureForFile('ms-filter', Settings::create()->beStrict()); } /** @@ -1148,7 +1152,7 @@ public function microsoftFilterStrictParsing() */ public function microsoftFilterParsing() { - $oDoc = $this->parsedStructureForFile('ms-filter'); + $oDoc = self::parsedStructureForFile('ms-filter'); $sExpected = '.test {filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#80000000",' . 'endColorstr="#00000000",GradientType=1);}'; self::assertSame($sExpected, $oDoc->render()); @@ -1159,7 +1163,7 @@ public function microsoftFilterParsing() */ public function largeSizeValuesInFile() { - $oDoc = $this->parsedStructureForFile('large-z-index', Settings::create()->withMultibyteSupport(false)); + $oDoc = self::parsedStructureForFile('large-z-index', Settings::create()->withMultibyteSupport(false)); $sExpected = '.overlay {z-index: 10000000000000000000000;}'; self::assertSame($sExpected, $oDoc->render()); } @@ -1169,7 +1173,7 @@ public function largeSizeValuesInFile() */ public function lonelyImport() { - $oDoc = $this->parsedStructureForFile('lonely-import'); + $oDoc = self::parsedStructureForFile('lonely-import'); $sExpected = "@import url(\"example.css\") only screen and (max-width: 600px);"; self::assertSame($sExpected, $oDoc->render()); } diff --git a/tests/fixtures/comments.css b/tests/fixtures/comments.css index ea136bcc..6e443b69 100644 --- a/tests/fixtures/comments.css +++ b/tests/fixtures/comments.css @@ -1,6 +1,7 @@ /** - * Comments Hell. + * Comments */ + /* Hell */ @import /* Number 1 */"some/url.css"/* Number 2 */ screen/* Number 3 */; .foo, /* Number 4 */ #bar/* Number 5 */ {