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