Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
36 / 36
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
1 / 1
RuleSanitizer
100.00% covered (success)
100.00%
36 / 36
100.00% covered (success)
100.00%
4 / 4
15
100.00% covered (success)
100.00%
1 / 1
 getIndex
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 sanitizeDeclarationBlock
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 sanitizeRuleBlock
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 fixPreludeWhitespace
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
1 / 1
12
 handlesRule
n/a
0 / 0
n/a
0 / 0
0
1<?php
2/**
3 * @file
4 * @license https://opensource.org/licenses/Apache-2.0 Apache-2.0
5 */
6
7namespace Wikimedia\CSS\Sanitizer;
8
9use Wikimedia\CSS\Objects\AtRule;
10use Wikimedia\CSS\Objects\CSSFunction;
11use Wikimedia\CSS\Objects\Rule;
12use Wikimedia\CSS\Objects\SimpleBlock;
13use Wikimedia\CSS\Objects\Token;
14use Wikimedia\CSS\Parser\Parser;
15use Wikimedia\CSS\Util;
16
17/**
18 * Base class for CSS rule sanitizers
19 */
20abstract class RuleSanitizer extends Sanitizer {
21
22    /**
23     * Return an integer indicating ordering constraints. Lower numbers must
24     * come earlier in the document.
25     * @return int|int[] If two numbers are returned, these are the test and
26     *  the newly-set indexes, respectively.
27     */
28    public function getIndex() {
29        return 1000;
30    }
31
32    /**
33     * Sanitize a block's contents as a DeclarationList, in place
34     * @param SimpleBlock $block
35     * @param PropertySanitizer $sanitizer
36     */
37    protected function sanitizeDeclarationBlock( SimpleBlock $block, PropertySanitizer $sanitizer ) {
38        $blockContents = $block->getValue();
39        $parser = Parser::newFromTokens( $blockContents->toTokenArray() );
40        $declarations = $parser->parseDeclarationList();
41        $this->sanitizationErrors = array_merge( $this->sanitizationErrors, $parser->getParseErrors() );
42        $declarations = $this->sanitizeList( $sanitizer, $declarations );
43        $blockContents->clear();
44        $blockContents->add( $declarations->toComponentValueArray() );
45    }
46
47    /**
48     * Sanitize a block's contents as a RuleList, in place
49     * @param SimpleBlock $block
50     * @param RuleSanitizer[] $sanitizers
51     */
52    protected function sanitizeRuleBlock( SimpleBlock $block, array $sanitizers ) {
53        $blockContents = $block->getValue();
54        $parser = Parser::newFromTokens( $blockContents->toTokenArray() );
55        $rules = $parser->parseRuleList();
56        $this->sanitizationErrors = array_merge( $this->sanitizationErrors, $parser->getParseErrors() );
57        $rules = $this->sanitizeRules( $sanitizers, $rules );
58        $blockContents->clear();
59        $blockContents->add( $rules->toComponentValueArray() );
60    }
61
62    /**
63     * For the whitespace at the start of the prelude
64     *
65     * The matcher probably marked it insignificant, but it's actually
66     * significant if it's needed to separate the at-keyword and the first
67     * thing in the prelude. And if there isn't a whitespace there, add one if
68     * it would be significant.
69     *
70     * @param AtRule $rule
71     * @param bool $cloneIfNecessary
72     * @return AtRule
73     */
74    protected function fixPreludeWhitespace( AtRule $rule, $cloneIfNecessary ) {
75        $prelude = $rule->getPrelude();
76        if ( !count( $prelude ) ) {
77            return $rule;
78        }
79
80        $cv = Util::findFirstNonWhitespace( $rule->getPrelude() );
81        if ( !$cv ) {
82            foreach ( $prelude as $i => $v ) {
83                if ( $v instanceof Token && $v->significant() ) {
84                    $prelude[$i] = $v->copyWithSignificance( false );
85                }
86            }
87            return $rule;
88        }
89
90        $significant = $cv instanceof CSSFunction ||
91            ( $cv instanceof Token &&
92                Token::separate( new Token( Token::T_AT_KEYWORD, $rule->getName() ), $cv )
93            );
94
95        // @phan-suppress-next-line PhanNonClassMethodCall False positive
96        if ( $prelude[0] instanceof Token && $prelude[0]->type() === Token::T_WHITESPACE ) {
97            // @phan-suppress-next-line PhanNonClassMethodCall False positive
98            $prelude[0] = $prelude[0]->copyWithSignificance( $significant );
99        } elseif ( $significant ) {
100            if ( $cloneIfNecessary ) {
101                $rule = clone $rule;
102                $prelude = $rule->getPrelude();
103            }
104            $prelude->add( new Token( Token::T_WHITESPACE ), 0 );
105        }
106
107        return $rule;
108    }
109
110    /**
111     * Indicate whether this rule is handled by this sanitizer.
112     * @param Rule $rule
113     * @return bool
114     */
115    abstract public function handlesRule( Rule $rule );
116}