Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
11 / 11
CRAP
100.00% covered (success)
100.00%
1 / 1
AtRule
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
11 / 11
17
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
2
 __clone
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 newFromName
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getName
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getPrelude
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getBlock
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setBlock
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 toTokenOrCVArray
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
4
 toTokenArray
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 toComponentValueArray
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __toString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
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\Objects;
10
11use InvalidArgumentException;
12use Wikimedia\CSS\Util;
13
14/**
15 * Represent a CSS at-rule, eg. `@import url("styles.css")` or `@media (min-width: 768px) { div { color: red } }`
16 */
17class AtRule extends Rule implements DeclarationOrAtRule {
18
19    /** @var string */
20    protected $name;
21
22    /** @var ComponentValueList */
23    protected $prelude;
24
25    /** @var SimpleBlock|null */
26    protected $block = null;
27
28    /**
29     * @param Token $token An at-keyword token
30     */
31    public function __construct( Token $token ) {
32        if ( $token->type() !== Token::T_AT_KEYWORD ) {
33            throw new InvalidArgumentException(
34                "At rule must begin with an at-keyword token, got {$token->type()}"
35            );
36        }
37
38        parent::__construct( $token );
39        $this->name = $token->value();
40        $this->prelude = new ComponentValueList();
41    }
42
43    public function __clone() {
44        $this->prelude = clone $this->prelude;
45        if ( $this->block ) {
46            $this->block = clone $this->block;
47        }
48    }
49
50    /**
51     * Create an at-rule by name
52     * @param string $name
53     * @return AtRule
54     */
55    public static function newFromName( $name ) {
56        return new static( new Token( Token::T_AT_KEYWORD, $name ) );
57    }
58
59    /**
60     * Return the at-rule's name, e.g. "media"
61     * @return string
62     */
63    public function getName() {
64        return $this->name;
65    }
66
67    /**
68     * Return the at-rule's prelude
69     * @return ComponentValueList
70     */
71    public function getPrelude() {
72        return $this->prelude;
73    }
74
75    /**
76     * Return the at-rule's block
77     * @return SimpleBlock|null
78     */
79    public function getBlock() {
80        return $this->block;
81    }
82
83    /**
84     * Set the block
85     * @param SimpleBlock|null $block
86     */
87    public function setBlock( ?SimpleBlock $block = null ) {
88        if ( $block->getStartTokenType() !== Token::T_LEFT_BRACE ) {
89            throw new InvalidArgumentException( 'At-rule block must be delimited by {}' );
90        }
91        $this->block = $block;
92    }
93
94    /**
95     * @param string $function Function to call, toTokenArray() or toComponentValueArray()
96     * @return Token[]|ComponentValue[]
97     */
98    private function toTokenOrCVArray( $function ) {
99        $ret = [];
100
101        $ret[] = new Token(
102            Token::T_AT_KEYWORD, [ 'value' => $this->name, 'position' => [ $this->line, $this->pos ] ]
103        );
104        // Manually looping and appending turns out to be noticeably faster than array_merge.
105        foreach ( $this->prelude->$function() as $v ) {
106            $ret[] = $v;
107        }
108        if ( $this->block ) {
109            foreach ( $this->block->$function() as $v ) {
110                $ret[] = $v;
111            }
112        } else {
113            $ret[] = new Token( Token::T_SEMICOLON );
114        }
115
116        return $ret;
117    }
118
119    /** @inheritDoc */
120    public function toTokenArray() {
121        return $this->toTokenOrCVArray( __FUNCTION__ );
122    }
123
124    /** @inheritDoc */
125    public function toComponentValueArray() {
126        return $this->toTokenOrCVArray( __FUNCTION__ );
127    }
128
129    public function __toString() {
130        return Util::stringify( $this );
131    }
132}