Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
5 / 5
CRAP
100.00% covered (success)
100.00%
1 / 1
SupportsAtRuleSanitizer
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
5 / 5
11
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 getRuleSanitizers
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setRuleSanitizers
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 handlesRule
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 doSanitize
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
6
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\Grammar\Matcher;
12use Wikimedia\CSS\Grammar\MatcherFactory;
13use Wikimedia\CSS\Objects\AtRule;
14use Wikimedia\CSS\Objects\CSSObject;
15use Wikimedia\CSS\Objects\Rule;
16use Wikimedia\CSS\Util;
17
18/**
19 * Sanitizes a CSS \@supports rule
20 * @see https://www.w3.org/TR/2013/CR-css3-conditional-20130404/#at-supports
21 */
22class SupportsAtRuleSanitizer extends RuleSanitizer {
23
24    /** @var Matcher */
25    protected $conditionMatcher;
26
27    /** @var RuleSanitizer[] */
28    protected $ruleSanitizers = [];
29
30    /**
31     * @param MatcherFactory $matcherFactory
32     * @param array $options Additional options:
33     *  - strict: (bool) Only accept defined syntax. Default true.
34     *  - declarationSanitizer: (PropertySanitizer) Check declarations against this Sanitizer.
35     */
36    public function __construct( MatcherFactory $matcherFactory, array $options = [] ) {
37        $this->conditionMatcher = $matcherFactory->cssSupportsCondition(
38            $options['declarationSanitizer'] ?? null,
39            $options['strict'] ?? true
40        );
41    }
42
43    /**
44     * Access the list of rule sanitizers
45     * @return RuleSanitizer[]
46     */
47    public function getRuleSanitizers() {
48        return $this->ruleSanitizers;
49    }
50
51    /**
52     * Set the list of rule sanitizers
53     * @param RuleSanitizer[] $ruleSanitizers
54     */
55    public function setRuleSanitizers( array $ruleSanitizers ) {
56        Util::assertAllInstanceOf( $ruleSanitizers, RuleSanitizer::class, '$ruleSanitizers' );
57        $this->ruleSanitizers = $ruleSanitizers;
58    }
59
60    /** @inheritDoc */
61    public function handlesRule( Rule $rule ) {
62        return $rule instanceof AtRule && !strcasecmp( $rule->getName(), 'supports' );
63    }
64
65    /** @inheritDoc */
66    protected function doSanitize( CSSObject $object ) {
67        if ( !$object instanceof AtRule || !$this->handlesRule( $object ) ) {
68            $this->sanitizationError( 'expected-at-rule', $object, [ 'supports' ] );
69            return null;
70        }
71
72        if ( $object->getBlock() === null ) {
73            $this->sanitizationError( 'at-rule-block-required', $object, [ 'supports' ] );
74            return null;
75        }
76
77        // Test the media query
78        if ( !$this->conditionMatcher->matchAgainst( $object->getPrelude(), [ 'mark-significance' => true ] ) ) {
79            $cv = Util::findFirstNonWhitespace( $object->getPrelude() );
80            if ( $cv ) {
81                $this->sanitizationError( 'invalid-supports-condition', $cv );
82            } else {
83                $this->sanitizationError( 'missing-supports-condition', $object );
84            }
85            return null;
86        }
87
88        $ret = clone $object;
89        $this->fixPreludeWhitespace( $ret, false );
90        $this->sanitizeRuleBlock( $ret->getBlock(), $this->ruleSanitizers );
91
92        // @phan-suppress-next-line PhanTypeMismatchReturn generics weakness
93        return $ret;
94    }
95}