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