Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
1 / 1
NamespaceAtRuleSanitizer
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
4 / 4
10
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 getIndex
100.00% covered (success)
100.00%
1 / 1
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%
13 / 13
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\Alternative;
12use Wikimedia\CSS\Grammar\Juxtaposition;
13use Wikimedia\CSS\Grammar\Matcher;
14use Wikimedia\CSS\Grammar\MatcherFactory;
15use Wikimedia\CSS\Grammar\Quantifier;
16use Wikimedia\CSS\Objects\AtRule;
17use Wikimedia\CSS\Objects\CSSObject;
18use Wikimedia\CSS\Objects\Rule;
19use Wikimedia\CSS\Util;
20
21/**
22 * Sanitizes a CSS \@namespace rule
23 * @see https://www.w3.org/TR/2014/REC-css-namespaces-3-20140320/
24 */
25class NamespaceAtRuleSanitizer extends RuleSanitizer {
26
27    /** @var Matcher */
28    protected $matcher;
29
30    /**
31     * @param MatcherFactory $matcherFactory
32     */
33    public function __construct( MatcherFactory $matcherFactory ) {
34        $this->matcher = new Juxtaposition( [
35            Quantifier::optional( $matcherFactory->ident() ),
36            new Alternative( [
37                $matcherFactory->urlstring( 'namespace' ),
38                $matcherFactory->url( 'namespace' ),
39            ] ),
40        ] );
41    }
42
43    /** @inheritDoc */
44    public function getIndex() {
45        return -900;
46    }
47
48    /** @inheritDoc */
49    public function handlesRule( Rule $rule ) {
50        return $rule instanceof AtRule && !strcasecmp( $rule->getName(), 'namespace' );
51    }
52
53    /** @inheritDoc */
54    protected function doSanitize( CSSObject $object ) {
55        if ( !$object instanceof AtRule || !$this->handlesRule( $object ) ) {
56            $this->sanitizationError( 'expected-at-rule', $object, [ 'namespace' ] );
57            return null;
58        }
59
60        if ( $object->getBlock() !== null ) {
61            $this->sanitizationError( 'at-rule-block-not-allowed', $object->getBlock(), [ 'namespace' ] );
62            return null;
63        }
64        if ( !$this->matcher->matchAgainst( $object->getPrelude(), [ 'mark-significance' => true ] ) ) {
65            $cv = Util::findFirstNonWhitespace( $object->getPrelude() );
66            if ( $cv ) {
67                $this->sanitizationError( 'invalid-namespace-value', $cv );
68            } else {
69                $this->sanitizationError( 'missing-namespace-value', $object );
70            }
71            return null;
72        }
73        // @phan-suppress-next-line PhanTypeMismatchReturn generics weakness
74        return $this->fixPreludeWhitespace( $object, true );
75    }
76}