true, ]; $declarationSanitizer = null; if ( isset( $options['declarationSanitizer'] ) ) { $declarationSanitizer = $options['declarationSanitizer']; if ( !$declarationSanitizer instanceof PropertySanitizer ) { throw new \InvalidArgumentException( 'declarationSanitizer must be an instance of ' . PropertySanitizer::class ); } } $ws = $matcherFactory->significantWhitespace(); $anythingPlus = new AnythingMatcher( [ 'quantifier' => '+' ] ); if ( $options['strict'] ) { $generalEnclosed = new NothingMatcher(); } else { $generalEnclosed = new Alternative( [ new FunctionMatcher( null, $anythingPlus ), new BlockMatcher( Token::T_LEFT_PAREN, new Juxtaposition( [ $matcherFactory->ident(), $anythingPlus ] ) ), ] ); } $supportsConditionBlock = new NothingMatcher(); // temp $supportsConditionInParens = new Alternative( [ &$supportsConditionBlock, new BlockMatcher( Token::T_LEFT_PAREN, new CheckedMatcher( $anythingPlus, function ( ComponentValueList $list, Match $match, array $options ) use ( $declarationSanitizer ) { $cvlist = new ComponentValueList( $match->getValues() ); $parser = Parser::newFromTokens( $cvlist->toTokenArray() ); $declaration = $parser->parseDeclaration(); if ( $parser->getParseErrors() || !$declaration ) { return false; } if ( !$declarationSanitizer ) { return true; } $oldErrors = $declarationSanitizer->sanitizationErrors; $ret = $declarationSanitizer->doSanitize( $declaration ); $errors = $declarationSanitizer->getSanitizationErrors(); $declarationSanitizer->sanitizationErrors = $oldErrors; return $ret === $declaration && !$errors; } ) ), $generalEnclosed, ] ); $supportsCondition = new Alternative( [ new Juxtaposition( [ new KeywordMatcher( 'not' ), $ws, $supportsConditionInParens ] ), new Juxtaposition( [ $supportsConditionInParens, Quantifier::plus( new Juxtaposition( [ $ws, new KeywordMatcher( 'and' ), $ws, $supportsConditionInParens ] ) ) ] ), new Juxtaposition( [ $supportsConditionInParens, Quantifier::plus( new Juxtaposition( [ $ws, new KeywordMatcher( 'or' ), $ws, $supportsConditionInParens ] ) ) ] ), $supportsConditionInParens, ] ); $supportsConditionBlock = new BlockMatcher( Token::T_LEFT_PAREN, $supportsCondition ); $this->conditionMatcher = $supportsCondition; } /** * Access the list of rule sanitizers * @return RuleSanitizer[] */ public function getRuleSanitizers() { return $this->ruleSanitizers; } /** * Set the list of rule sanitizers * @param RuleSanitizer[] $ruleSanitizers */ public function setRuleSanitizers( array $ruleSanitizers ) { Util::assertAllInstanceOf( $ruleSanitizers, RuleSanitizer::class, '$ruleSanitizers' ); $this->ruleSanitizers = $ruleSanitizers; } public function handlesRule( Rule $rule ) { return $rule instanceof AtRule && !strcasecmp( $rule->getName(), 'supports' ); } protected function doSanitize( CSSObject $object ) { if ( !$object instanceof Rule || !$this->handlesRule( $object ) ) { $this->sanitizationError( 'expected-at-rule', $object, [ 'supports' ] ); return null; } if ( $object->getBlock() === null ) { $this->sanitizationError( 'at-rule-block-required', $object, [ 'supports' ] ); return null; } // Test the media query if ( !$this->conditionMatcher->match( $object->getPrelude(), [ 'mark-significance' => true ] ) ) { $cv = Util::findFirstNonWhitespace( $object->getPrelude() ); if ( $cv ) { $this->sanitizationError( 'invalid-supports-condition', $cv ); } else { $this->sanitizationError( 'missing-supports-condition', $object ); } return null; } $ret = clone( $object ); $this->fixPreludeWhitespace( $ret, false ); $this->sanitizeRuleBlock( $ret->getBlock(), $this->ruleSanitizers ); return $ret; } }