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

MyIntervals / PHP-CSS-Parser / 20503584137

25 Dec 2025 10:25AM UTC coverage: 68.727% (-0.5%) from 69.191%
20503584137

Pull #1444

github

web-flow
Merge 55c55b861 into 0ae1fde22
Pull Request #1444: Do not escape characters that do not need escaping in CSS string

0 of 14 new or added lines in 1 file covered. (0.0%)

1334 of 1941 relevant lines covered (68.73%)

32.84 hits per line

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

18.37
/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

13
use function Safe\preg_match;
14

15
/**
16
 * This class is a wrapper for quoted strings to distinguish them from keywords.
17
 *
18
 * `CSSString`s always output with double quotes.
19
 */
20
class CSSString extends PrimitiveValue
21
{
22
    /**
23
     * @var string
24
     */
25
    private $string;
26

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

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

78
    public function setString(string $string): void
1✔
79
    {
80
        $this->string = $string;
1✔
81
    }
1✔
82

83
    public function getString(): string
2✔
84
    {
85
        return $this->string;
2✔
86
    }
87

88
    /**
89
     * @return non-empty-string
90
     */
91
    public function render(OutputFormat $outputFormat): string
×
92
    {
NEW
93
        $string = $this->escape($this->string, $outputFormat->getStringQuotingType());
×
94
        $string = \str_replace("\n", '\\A', $string);
×
95
        return $outputFormat->getStringQuotingType() . $string . $outputFormat->getStringQuotingType();
×
96
    }
97

NEW
98
    private function escape(string $str, string $quote) : string
×
99
    {
100
        $matches = [
NEW
101
            0x0, // null
×
102
            0x5c, // \
103
        ];
104

NEW
105
        $matches[] = $quote === '"' ? 0x22 : 0x27;
×
106

NEW
107
        $length = strlen($str);
×
NEW
108
        $output = '';
×
NEW
109
        $previous = 0x0;
×
110

NEW
111
        for ($i = 0; $i < $length; ++$i) {
×
NEW
112
            $current = ord($str[$i]);
×
113

NEW
114
            if (in_array($current, $matches, true) && $previous !== 0x5c) {
×
NEW
115
                $output .= '\\';
×
116
            }
117

NEW
118
            $output .= $str[$i];
×
NEW
119
            $previous = $current;
×
120
        }
121

NEW
122
        return $output;
×
123
    }
124
}
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

© 2025 Coveralls, Inc