• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MyIntervals / PHP-CSS-Parser / 21410081995

27 Jan 2026 06:56PM UTC coverage: 70.488% (-0.8%) from 71.315%
21410081995

Pull #1484

github

web-flow
Merge 2332f66fa into 96410045c
Pull Request #1484: Remove `thecodingmachine/safe` dependency (2)

21 of 60 new or added lines in 8 files covered. (35.0%)

5 existing lines in 3 files now uncovered.

1445 of 2050 relevant lines covered (70.49%)

30.36 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

44.0
/src/Value/CSSString.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Sabberworm\CSS\Value;
6

7
use Sabberworm\CSS\OutputFormat;
8
use Sabberworm\CSS\Parsing\ParserState;
9
use Sabberworm\CSS\Parsing\SourceException;
10
use Sabberworm\CSS\Parsing\UnexpectedEOFException;
11
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
12
use Sabberworm\CSS\ShortClassNameProvider;
13

14
/**
15
 * This class is a wrapper for quoted strings to distinguish them from keywords.
16
 *
17
 * `CSSString`s always output with double quotes.
18
 */
19
class CSSString extends PrimitiveValue
20
{
21
    use ShortClassNameProvider;
22

23
    /**
24
     * @var string
25
     */
26
    private $string;
27

28
    /**
29
     * @param int<1, max>|null $lineNumber
30
     */
31
    public function __construct(string $string, ?int $lineNumber = null)
10✔
32
    {
33
        $this->string = $string;
10✔
34
        parent::__construct($lineNumber);
10✔
35
    }
10✔
36

37
    /**
38
     * @throws SourceException
39
     * @throws UnexpectedEOFException
40
     * @throws UnexpectedTokenException
41
     *
42
     * @internal since V8.8.0
43
     */
44
    public static function parse(ParserState $parserState): CSSString
×
45
    {
46
        $begin = $parserState->peek();
×
47
        $quote = null;
×
48
        if ($begin === "'") {
×
49
            $quote = "'";
×
50
        } elseif ($begin === '"') {
×
51
            $quote = '"';
×
52
        }
53
        if ($quote !== null) {
×
54
            $parserState->consume($quote);
×
55
        }
56
        $result = '';
×
57
        $content = null;
×
58
        if ($quote === null) {
×
59
            // Unquoted strings end in whitespace or with braces, brackets, parentheses
NEW
60
            while (true) {
×
61
                /** @phpstan-ignore theCodingMachineSafe.function */
NEW
62
                $matchResult = \preg_match('/[\\s{}()<>\\[\\]]/isu', $parserState->peek());
×
NEW
63
                if ($matchResult === false) {
×
NEW
64
                    throw new \RuntimeException('Unexpected error');
×
65
                }
NEW
66
                if ($matchResult !== 0) {
×
NEW
67
                    break;
×
68
                }
UNCOV
69
                $result .= $parserState->parseCharacter(false);
×
70
            }
71
        } else {
72
            while (!$parserState->comes($quote)) {
×
73
                $content = $parserState->parseCharacter(false);
×
74
                if ($content === null) {
×
75
                    throw new SourceException(
×
76
                        "Non-well-formed quoted string {$parserState->peek(3)}",
×
77
                        $parserState->currentLine()
×
78
                    );
79
                }
80
                $result .= $content;
×
81
            }
82
            $parserState->consume($quote);
×
83
        }
84
        return new CSSString($result, $parserState->currentLine());
×
85
    }
86

87
    public function setString(string $string): void
1✔
88
    {
89
        $this->string = $string;
1✔
90
    }
1✔
91

92
    public function getString(): string
2✔
93
    {
94
        return $this->string;
2✔
95
    }
96

97
    /**
98
     * @return non-empty-string
99
     */
100
    public function render(OutputFormat $outputFormat): string
2✔
101
    {
102
        return $outputFormat->getStringQuotingType()
2✔
103
            . $this->escape($this->string, $outputFormat)
2✔
104
            . $outputFormat->getStringQuotingType();
2✔
105
    }
106

107
    /**
108
     * @return array<string, bool|int|float|string|array<mixed>|null>
109
     *
110
     * @internal
111
     */
112
    public function getArrayRepresentation(): array
2✔
113
    {
114
        return [
115
            'class' => $this->getShortClassName(),
2✔
116
            // We're using the term "contents" here to make the difference to the class more clear.
117
            'contents' => $this->string,
2✔
118
        ];
119
    }
120

121
    private function escape(string $string, OutputFormat $outputFormat): string
2✔
122
    {
123
        $charactersToEscape = '\\';
2✔
124
        $charactersToEscape .= ($outputFormat->getStringQuotingType() === '"' ? '"' : "'");
2✔
125
        $withEscapedQuotes = \addcslashes($string, $charactersToEscape);
2✔
126

127
        $withNewlineEncoded = \str_replace("\n", '\\A', $withEscapedQuotes);
2✔
128

129
        return $withNewlineEncoded;
2✔
130
    }
131
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc