Skip to content

Commit e24df96

Browse files
committed
Merge branch 'master' of github.com:sabberworm/PHP-CSS-Parser into unicode_range
2 parents 9966dbe + b08df82 commit e24df96

File tree

8 files changed

+148
-18
lines changed

8 files changed

+148
-18
lines changed

lib/Sabberworm/CSS/CSSList/AtRuleBlockList.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,11 @@ public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat) {
3535
if($sArgs) {
3636
$sArgs = ' ' . $sArgs;
3737
}
38-
$sResult = "@{$this->sType}$sArgs{$oOutputFormat->spaceBeforeOpeningBrace()}{";
38+
$sResult = $oOutputFormat->sBeforeAtRuleBlock;
39+
$sResult .= "@{$this->sType}$sArgs{$oOutputFormat->spaceBeforeOpeningBrace()}{";
3940
$sResult .= parent::render($oOutputFormat);
4041
$sResult .= '}';
42+
$sResult .= $oOutputFormat->sAfterAtRuleBlock;
4143
return $sResult;
4244
}
4345

lib/Sabberworm/CSS/CSSList/CSSList.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,13 +176,39 @@ public function getLineNo() {
176176
return $this->iLineNo;
177177
}
178178

179+
/**
180+
* Prepend item to list of contents.
181+
*
182+
* @param object $oItem Item.
183+
*/
184+
public function prepend($oItem) {
185+
array_unshift($this->aContents, $oItem);
186+
}
187+
188+
/**
189+
* Append item to list of contents.
190+
*
191+
* @param object $oItem Item.
192+
*/
179193
public function append($oItem) {
180194
$this->aContents[] = $oItem;
181195
}
182196

197+
/**
198+
* Splice the list of contents.
199+
*
200+
* @param int $iOffset Offset.
201+
* @param int $iLength Length. Optional.
202+
* @param RuleSet[] $mReplacement Replacement. Optional.
203+
*/
204+
public function splice($iOffset, $iLength = null, $mReplacement = null) {
205+
array_splice($this->aContents, $iOffset, $iLength, $mReplacement);
206+
}
207+
183208
/**
184209
* Removes an item from the CSS list.
185210
* @param RuleSet|Import|Charset|CSSList $oItemToRemove May be a RuleSet (most likely a DeclarationBlock), a Import, a Charset or another CSSList (most likely a MediaQuery)
211+
* @return bool Whether the item was removed.
186212
*/
187213
public function remove($oItemToRemove) {
188214
$iKey = array_search($oItemToRemove, $this->aContents, true);
@@ -193,6 +219,19 @@ public function remove($oItemToRemove) {
193219
return false;
194220
}
195221

222+
/**
223+
* Replaces an item from the CSS list.
224+
* @param RuleSet|Import|Charset|CSSList $oItemToRemove May be a RuleSet (most likely a DeclarationBlock), a Import, a Charset or another CSSList (most likely a MediaQuery)
225+
*/
226+
public function replace($oOldItem, $oNewItem) {
227+
$iKey = array_search($oOldItem, $this->aContents, true);
228+
if ($iKey !== false) {
229+
array_splice($this->aContents, $iKey, 1, $oNewItem);
230+
return true;
231+
}
232+
return false;
233+
}
234+
196235
/**
197236
* Set the contents.
198237
* @param array $aContents Objects to set as content.

lib/Sabberworm/CSS/OutputFormat.php

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44

55
use Sabberworm\CSS\Parsing\OutputException;
66

7+
/**
8+
* Class OutputFormat
9+
*
10+
* @method OutputFormat setSemicolonAfterLastRule( bool $bSemicolonAfterLastRule ) Set whether semicolons are added after last rule.
11+
*/
712
class OutputFormat {
813
/**
914
* Value format
@@ -35,6 +40,10 @@ class OutputFormat {
3540
public $sSpaceAfterBlocks = '';
3641
public $sSpaceBetweenBlocks = "\n";
3742

43+
// Content injected in and around @-rule blocks.
44+
public $sBeforeAtRuleBlock = '';
45+
public $sAfterAtRuleBlock = '';
46+
3847
// This is what’s printed before and after the comma if a declaration block contains multiple selectors.
3948
public $sSpaceBeforeSelectorSeparator = '';
4049
public $sSpaceAfterSelectorSeparator = ' ';
@@ -43,7 +52,12 @@ class OutputFormat {
4352
public $sSpaceAfterListArgumentSeparator = '';
4453

4554
public $sSpaceBeforeOpeningBrace = ' ';
46-
55+
56+
// Content injected in and around declaration blocks.
57+
public $sBeforeDeclarationBlock = '';
58+
public $sAfterDeclarationBlockSelectors = '';
59+
public $sAfterDeclarationBlock = '';
60+
4761
/**
4862
* Indentation
4963
*/
@@ -141,17 +155,36 @@ public function getFormatter() {
141155
public function level() {
142156
return $this->iIndentationLevel;
143157
}
144-
158+
159+
/**
160+
* Create format.
161+
*
162+
* @return OutputFormat Format.
163+
*/
145164
public static function create() {
146165
return new OutputFormat();
147166
}
148-
167+
168+
/**
169+
* Create compact format.
170+
*
171+
* @return OutputFormat Format.
172+
*/
149173
public static function createCompact() {
150-
return self::create()->set('Space*Rules', "")->set('Space*Blocks', "")->setSpaceAfterRuleName('')->setSpaceBeforeOpeningBrace('')->setSpaceAfterSelectorSeparator('');
174+
$format = self::create();
175+
$format->set('Space*Rules', "")->set('Space*Blocks', "")->setSpaceAfterRuleName('')->setSpaceBeforeOpeningBrace('')->setSpaceAfterSelectorSeparator('');
176+
return $format;
151177
}
152-
178+
179+
/**
180+
* Create pretty format.
181+
*
182+
* @return OutputFormat Format.
183+
*/
153184
public static function createPretty() {
154-
return self::create()->set('Space*Rules', "\n")->set('Space*Blocks', "\n")->setSpaceBetweenBlocks("\n\n")->set('SpaceAfterListArgumentSeparator', array('default' => '', ',' => ' '));
185+
$format = self::create();
186+
$format->set('Space*Rules', "\n")->set('Space*Blocks', "\n")->setSpaceBetweenBlocks("\n\n")->set('SpaceAfterListArgumentSeparator', array('default' => '', ',' => ' '));
187+
return $format;
155188
}
156189
}
157190

lib/Sabberworm/CSS/RuleSet/DeclarationBlock.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ public function setSelector($mSelector) {
7676
$this->setSelectors($mSelector);
7777
}
7878

79+
/**
80+
* Get selectors.
81+
*
82+
* @return Selector[] Selectors.
83+
*/
7984
public function getSelectors() {
8085
return $this->aSelectors;
8186
}
@@ -610,9 +615,13 @@ public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat) {
610615
// If all the selectors have been removed, this declaration block becomes invalid
611616
throw new OutputException("Attempt to print declaration block with missing selector", $this->iLineNo);
612617
}
613-
$sResult = $oOutputFormat->implode($oOutputFormat->spaceBeforeSelectorSeparator() . ',' . $oOutputFormat->spaceAfterSelectorSeparator(), $this->aSelectors) . $oOutputFormat->spaceBeforeOpeningBrace() . '{';
618+
$sResult = $oOutputFormat->sBeforeDeclarationBlock;
619+
$sResult .= $oOutputFormat->implode($oOutputFormat->spaceBeforeSelectorSeparator() . ',' . $oOutputFormat->spaceAfterSelectorSeparator(), $this->aSelectors);
620+
$sResult .= $oOutputFormat->sAfterDeclarationBlockSelectors;
621+
$sResult .= $oOutputFormat->spaceBeforeOpeningBrace() . '{';
614622
$sResult .= parent::render($oOutputFormat);
615623
$sResult .= '}';
624+
$sResult .= $oOutputFormat->sAfterDeclarationBlock;
616625
return $sResult;
617626
}
618627

lib/Sabberworm/CSS/RuleSet/RuleSet.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ public function addRule(Rule $oRule, Rule $oSibling = null) {
8989
* @param (null|string|Rule) $mRule pattern to search for. If null, returns all rules. if the pattern ends with a dash, all rules starting with the pattern are returned as well as one matching the pattern with the dash excluded. passing a Rule behaves like calling getRules($mRule->getRule()).
9090
* @example $oRuleSet->getRules('font-') //returns an array of all rules either beginning with font- or matching font.
9191
* @example $oRuleSet->getRules('font') //returns array(0 => $oRule, …) or array().
92+
* @return Rule[] Rules.
9293
*/
9394
public function getRules($mRule = null) {
9495
if ($mRule instanceof Rule) {
@@ -106,7 +107,7 @@ public function getRules($mRule = null) {
106107

107108
/**
108109
* Override all the rules of this set.
109-
* @param array $aRules The rules to override with.
110+
* @param Rule[] $aRules The rules to override with.
110111
*/
111112
public function setRules(array $aRules) {
112113
$this->aRules = array();
@@ -119,6 +120,7 @@ public function setRules(array $aRules) {
119120
* Returns all rules matching the given pattern and returns them in an associative array with the rule’s name as keys. This method exists mainly for backwards-compatibility and is really only partially useful.
120121
* @param (string) $mRule pattern to search for. If null, returns all rules. if the pattern ends with a dash, all rules starting with the pattern are returned as well as one matching the pattern with the dash excluded. passing a Rule behaves like calling getRules($mRule->getRule()).
121122
* Note: This method loses some information: Calling this (with an argument of 'background-') on a declaration block like { background-color: green; background-color; rgba(0, 127, 0, 0.7); } will only yield an associative array containing the rgba-valued rule while @link{getRules()} would yield an indexed array containing both.
123+
* @return Rule[] Rules.
122124
*/
123125
public function getRulesAssoc($mRule = null) {
124126
$aResult = array();
@@ -129,9 +131,9 @@ public function getRulesAssoc($mRule = null) {
129131
}
130132

131133
/**
132-
* Remove a rule from this RuleSet. This accepts all the possible values that @link{getRules()} accepts. If given a Rule, it will only remove this particular rule (by identity). If given a name, it will remove all rules by that name. Note: this is different from pre-v.2.0 behaviour of PHP-CSS-Parser, where passing a Rule instance would remove all rules with the same name. To get the old behvaiour, use removeRule($oRule->getRule()).
133-
* @param (null|string|Rule) $mRule pattern to remove. If $mRule is null, all rules are removed. If the pattern ends in a dash, all rules starting with the pattern are removed as well as one matching the pattern with the dash excluded. Passing a Rule behaves matches by identity.
134-
*/
134+
* Remove a rule from this RuleSet. This accepts all the possible values that @link{getRules()} accepts. If given a Rule, it will only remove this particular rule (by identity). If given a name, it will remove all rules by that name. Note: this is different from pre-v.2.0 behaviour of PHP-CSS-Parser, where passing a Rule instance would remove all rules with the same name. To get the old behvaiour, use removeRule($oRule->getRule()).
135+
* @param (null|string|Rule) $mRule pattern to remove. If $mRule is null, all rules are removed. If the pattern ends in a dash, all rules starting with the pattern are removed as well as one matching the pattern with the dash excluded. Passing a Rule behaves matches by identity.
136+
*/
135137
public function removeRule($mRule) {
136138
if($mRule instanceof Rule) {
137139
$sRule = $mRule->getRule();

lib/Sabberworm/CSS/Value/Value.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Sabberworm\CSS\Value;
44

55
use Sabberworm\CSS\Parsing\ParserState;
6+
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
67
use Sabberworm\CSS\Renderable;
78

89
abstract class Value implements Renderable {
@@ -55,6 +56,9 @@ public static function parseValue(ParserState $oParserState, $aListDelimiters =
5556
array_splice($aStack, $iStartPosition - 1, $iLength * 2 - 1, array($oList));
5657
}
5758
}
59+
if (!isset($aStack[0])) {
60+
throw new UnexpectedTokenException(" {$oParserState->peek()} ", $oParserState->peek(1, -1) . $oParserState->peek(2), 'literal', $oParserState->currentLine());
61+
}
5862
return $aStack[0];
5963
}
6064

tests/Sabberworm/CSS/ParserTest.php

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -478,26 +478,63 @@ function testTrailingWhitespace() {
478478
}
479479

480480
/**
481-
* @expectedException Sabberworm\CSS\Parsing\UnexpectedTokenException
482-
*/
481+
* @expectedException \Sabberworm\CSS\Parsing\UnexpectedTokenException
482+
*/
483483
function testCharsetFailure1() {
484484
$this->parsedStructureForFile('-charset-after-rule', Settings::create()->withLenientParsing(false));
485485
}
486486

487487
/**
488-
* @expectedException Sabberworm\CSS\Parsing\UnexpectedTokenException
489-
*/
488+
* @expectedException \Sabberworm\CSS\Parsing\UnexpectedTokenException
489+
*/
490490
function testCharsetFailure2() {
491491
$this->parsedStructureForFile('-charset-in-block', Settings::create()->withLenientParsing(false));
492492
}
493493

494494
/**
495-
* @expectedException Sabberworm\CSS\Parsing\SourceException
496-
*/
495+
* @expectedException \Sabberworm\CSS\Parsing\SourceException
496+
*/
497497
function testUnopenedClosingBracketFailure() {
498498
$this->parsedStructureForFile('unopened-close-brackets', Settings::create()->withLenientParsing(false));
499499
}
500500

501+
/**
502+
* Ensure that a missing property value raises an exception.
503+
*
504+
* @expectedException \Sabberworm\CSS\Parsing\UnexpectedTokenException
505+
* @covers \Sabberworm\CSS\Value\Value::parseValue()
506+
*/
507+
function testMissingPropertyValueStrict() {
508+
$this->parsedStructureForFile('missing-property-value', Settings::create()->withLenientParsing(false));
509+
}
510+
511+
/**
512+
* Ensure that a missing property value is ignored when in lenient parsing mode.
513+
*
514+
* @covers \Sabberworm\CSS\Value\Value::parseValue()
515+
*/
516+
function testMissingPropertyValueLenient() {
517+
$parsed = $this->parsedStructureForFile('missing-property-value', Settings::create()->withLenientParsing(true));
518+
$rulesets = $parsed->getAllRuleSets();
519+
$this->assertCount( 1, $rulesets );
520+
$block = $rulesets[0];
521+
$this->assertTrue( $block instanceof DeclarationBlock );
522+
$this->assertEquals( array( 'div' ), $block->getSelectors() );
523+
$rules = $block->getRules();
524+
$this->assertCount( 1, $rules );
525+
$rule = $rules[0];
526+
$this->assertEquals( 'display', $rule->getRule() );
527+
$this->assertEquals( 'inline-block', $rule->getValue() );
528+
}
529+
530+
/**
531+
* Parse structure for file.
532+
*
533+
* @param string $sFileName Filename.
534+
* @param null|obJeCt $oSettings Settings.
535+
*
536+
* @return CSSList\Document Parsed document.
537+
*/
501538
function parsedStructureForFile($sFileName, $oSettings = null) {
502539
$sFile = dirname(__FILE__) . '/../../files' . DIRECTORY_SEPARATOR . "$sFileName.css";
503540
$oParser = new Parser(file_get_contents($sFile), $oSettings);
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
div {
2+
display: inline-block;
3+
display:
4+
}

0 commit comments

Comments
 (0)