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

MyIntervals / PHP-CSS-Parser / 13101132524

02 Feb 2025 05:53PM UTC coverage: 48.703% (+3.4%) from 45.347%
13101132524

Pull #871

github

web-flow
Merge 97925da7a into 5fe6db9f4
Pull Request #871: [FEATURE] Add dedicated accessors for `OutputFormat`

121 of 123 new or added lines in 1 file covered. (98.37%)

1 existing line in 1 file now uncovered.

920 of 1889 relevant lines covered (48.7%)

10.81 hits per line

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

94.65
/src/OutputFormat.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Sabberworm\CSS;
6

7
class OutputFormat
8
{
9
    /**
10
     * Value format: `"` means double-quote, `'` means single-quote
11
     *
12
     * @var string
13
     */
14
    public $sStringQuotingType = '"';
15

16
    /**
17
     * Output RGB colors in hash notation if possible
18
     *
19
     * @var string
20
     */
21
    public $bRGBHashNotation = true;
22

23
    /**
24
     * Declaration format
25
     *
26
     * Semicolon after the last rule of a declaration block can be omitted. To do that, set this false.
27
     *
28
     * @var bool
29
     */
30
    public $bSemicolonAfterLastRule = true;
31

32
    /**
33
     * Spacing
34
     * Note that these strings are not sanity-checked: the value should only consist of whitespace
35
     * Any newline character will be indented according to the current level.
36
     * The triples (After, Before, Between) can be set using a wildcard (e.g. `$oFormat->set('Space*Rules', "\n");`)
37
     */
38
    public $sSpaceAfterRuleName = ' ';
39

40
    /**
41
     * @var string
42
     */
43
    public $sSpaceBeforeRules = '';
44

45
    /**
46
     * @var string
47
     */
48
    public $sSpaceAfterRules = '';
49

50
    /**
51
     * @var string
52
     */
53
    public $sSpaceBetweenRules = '';
54

55
    /**
56
     * @var string
57
     */
58
    public $sSpaceBeforeBlocks = '';
59

60
    /**
61
     * @var string
62
     */
63
    public $sSpaceAfterBlocks = '';
64

65
    /**
66
     * @var string
67
     */
68
    public $sSpaceBetweenBlocks = "\n";
69

70
    /**
71
     * Content injected in and around at-rule blocks.
72
     *
73
     * @var string
74
     */
75
    public $sBeforeAtRuleBlock = '';
76

77
    /**
78
     * @var string
79
     */
80
    public $sAfterAtRuleBlock = '';
81

82
    /**
83
     * This is what’s printed before and after the comma if a declaration block contains multiple selectors.
84
     *
85
     * @var string
86
     */
87
    public $sSpaceBeforeSelectorSeparator = '';
88

89
    /**
90
     * @var string
91
     */
92
    public $sSpaceAfterSelectorSeparator = ' ';
93

94
    /**
95
     * This is what’s printed after the comma of value lists
96
     *
97
     * @var string
98
     */
99
    public $sSpaceBeforeListArgumentSeparator = '';
100

101
    /**
102
     * @var string
103
     */
104
    public $sSpaceAfterListArgumentSeparator = '';
105

106
    /**
107
     * @var string
108
     */
109
    public $sSpaceBeforeOpeningBrace = ' ';
110

111
    /**
112
     * Content injected in and around declaration blocks.
113
     *
114
     * @var string
115
     */
116
    public $sBeforeDeclarationBlock = '';
117

118
    /**
119
     * @var string
120
     */
121
    public $sAfterDeclarationBlockSelectors = '';
122

123
    /**
124
     * @var string
125
     */
126
    public $sAfterDeclarationBlock = '';
127

128
    /**
129
     * Indentation character(s) per level. Only applicable if newlines are used in any of the spacing settings.
130
     *
131
     * @var string
132
     */
133
    public $sIndentation = "\t";
134

135
    /**
136
     * Output exceptions.
137
     *
138
     * @var bool
139
     */
140
    public $bIgnoreExceptions = false;
141

142
    /**
143
     * Render comments for lists and RuleSets
144
     *
145
     * @var bool
146
     */
147
    public $bRenderComments = false;
148

149
    /**
150
     * @var OutputFormatter|null
151
     */
152
    private $oFormatter = null;
153

154
    /**
155
     * @var OutputFormat|null
156
     */
157
    private $oNextLevelFormat = null;
158

159
    /**
160
     * @var int
161
     */
162
    private $iIndentationLevel = 0;
163

164
    public function __construct() {}
165

166
    /**
167
     * @param string $sName
168
     *
169
     * @return string|null
170
     */
171
    public function get($sName)
19✔
172
    {
173
        $aVarPrefixes = ['a', 's', 'm', 'b', 'f', 'o', 'c', 'i'];
19✔
174
        foreach ($aVarPrefixes as $sPrefix) {
19✔
175
            $sFieldName = $sPrefix . \ucfirst($sName);
19✔
176
            if (isset($this->$sFieldName)) {
19✔
177
                return $this->$sFieldName;
19✔
178
            }
179
        }
180
        return null;
×
181
    }
182

183
    /**
184
     * @param array<array-key, string>|string $aNames
185
     * @param mixed $mValue
186
     *
187
     * @return self|false
188
     */
189
    public function set($aNames, $mValue)
8✔
190
    {
191
        $aVarPrefixes = ['a', 's', 'm', 'b', 'f', 'o', 'c', 'i'];
8✔
192
        if (\is_string($aNames) && \strpos($aNames, '*') !== false) {
8✔
193
            $aNames =
194
                [
195
                    \str_replace('*', 'Before', $aNames),
8✔
196
                    \str_replace('*', 'Between', $aNames),
8✔
197
                    \str_replace('*', 'After', $aNames),
8✔
198
                ];
199
        } elseif (!\is_array($aNames)) {
3✔
200
            $aNames = [$aNames];
3✔
201
        }
202
        foreach ($aVarPrefixes as $sPrefix) {
8✔
203
            $bDidReplace = false;
8✔
204
            foreach ($aNames as $sName) {
8✔
205
                $sFieldName = $sPrefix . \ucfirst($sName);
8✔
206
                if (isset($this->$sFieldName)) {
8✔
207
                    $this->$sFieldName = $mValue;
8✔
208
                    $bDidReplace = true;
8✔
209
                }
210
            }
211
            if ($bDidReplace) {
8✔
212
                return $this;
8✔
213
            }
214
        }
215
        // Break the chain so the user knows this option is invalid
216
        return false;
×
217
    }
218

219
    /**
220
     * @param array<array-key, mixed> $aArguments
221
     *
222
     * @return mixed
223
     *
224
     * @throws \Exception
225
     */
226
    public function __call(string $sMethodName, array $aArguments)
19✔
227
    {
228
        if (\method_exists(OutputFormatter::class, $sMethodName)) {
19✔
229
            return \call_user_func_array([$this->getFormatter(), $sMethodName], $aArguments);
19✔
230
        } else {
UNCOV
231
            throw new \Exception('Unknown OutputFormat method called: ' . $sMethodName);
×
232
        }
233
    }
234

235
    /**
236
     * @internal
237
     */
238
    public function getStringQuotingType(): string
20✔
239
    {
240
        return $this->sStringQuotingType;
20✔
241
    }
242

243
    /**
244
     * @return $this fluent interface
245
     */
246
    public function setStringQuotingType(string $quotingType): self
3✔
247
    {
248
        $this->sStringQuotingType = $quotingType;
3✔
249

250
        return $this;
3✔
251
    }
252

253
    /**
254
     * @internal
255
     */
256
    public function getRGBHashNotation(): bool
22✔
257
    {
258
        return $this->bRGBHashNotation;
22✔
259
    }
260

261
    /**
262
     * @return $this fluent interface
263
     */
264
    public function setRGBHashNotation(bool $rgbHashNotation): self
4✔
265
    {
266
        $this->bRGBHashNotation = $rgbHashNotation;
4✔
267

268
        return $this;
4✔
269
    }
270

271
    /**
272
     * @internal
273
     */
274
    public function getSemicolonAfterLastRule(): bool
3✔
275
    {
276
        return $this->bSemicolonAfterLastRule;
3✔
277
    }
278

279
    /**
280
     * @return $this fluent interface
281
     */
282
    public function setSemicolonAfterLastRule(bool $semicolonAfterLastRule): self
4✔
283
    {
284
        $this->bSemicolonAfterLastRule = $semicolonAfterLastRule;
4✔
285

286
        return $this;
4✔
287
    }
288

289
    /**
290
     * @internal
291
     */
292
    public function getSpaceAfterRuleName(): string
2✔
293
    {
294
        return $this->sSpaceAfterRuleName;
2✔
295
    }
296

297
    /**
298
     * @return $this fluent interface
299
     */
300
    public function setSpaceAfterRuleName(string $whitespace): self
6✔
301
    {
302
        $this->sSpaceAfterRuleName = $whitespace;
6✔
303

304
        return $this;
6✔
305
    }
306

307
    /**
308
     * @internal
309
     */
310
    public function getSpaceBeforeRules(): string
2✔
311
    {
312
        return $this->sSpaceBeforeRules;
2✔
313
    }
314

315
    /**
316
     * @return $this fluent interface
317
     */
318
    public function setSpaceBeforeRules(string $whitespace): self
2✔
319
    {
320
        $this->sSpaceBeforeRules = $whitespace;
2✔
321

322
        return $this;
2✔
323
    }
324

325
    /**
326
     * @internal
327
     */
328
    public function getSpaceAfterRules(): string
2✔
329
    {
330
        return $this->sSpaceAfterRules;
2✔
331
    }
332

333
    /**
334
     * @return $this fluent interface
335
     */
336
    public function setSpaceAfterRules(string $whitespace): self
2✔
337
    {
338
        $this->sSpaceAfterRules = $whitespace;
2✔
339

340
        return $this;
2✔
341
    }
342

343
    /**
344
     * @internal
345
     */
346
    public function getSpaceBetweenRules(): string
2✔
347
    {
348
        return $this->sSpaceBetweenRules;
2✔
349
    }
350

351
    /**
352
     * @return $this fluent interface
353
     */
354
    public function setSpaceBetweenRules(string $whitespace): self
2✔
355
    {
356
        $this->sSpaceBetweenRules = $whitespace;
2✔
357

358
        return $this;
2✔
359
    }
360

361
    /**
362
     * @internal
363
     */
364
    public function getSpaceBeforeBlocks(): string
2✔
365
    {
366
        return $this->sSpaceBeforeBlocks;
2✔
367
    }
368

369
    /**
370
     * @return $this fluent interface
371
     */
372
    public function setSpaceBeforeBlocks(string $whitespace): self
2✔
373
    {
374
        $this->sSpaceBeforeBlocks = $whitespace;
2✔
375

376
        return $this;
2✔
377
    }
378

379
    /**
380
     * @internal
381
     */
382
    public function getSpaceAfterBlocks(): string
2✔
383
    {
384
        return $this->sSpaceAfterBlocks;
2✔
385
    }
386

387
    /**
388
     * @return $this fluent interface
389
     */
390
    public function setSpaceAfterBlocks(string $whitespace): self
2✔
391
    {
392
        $this->sSpaceAfterBlocks = $whitespace;
2✔
393

394
        return $this;
2✔
395
    }
396

397
    /**
398
     * @internal
399
     */
400
    public function getSpaceBetweenBlocks(): string
2✔
401
    {
402
        return $this->sSpaceBetweenBlocks;
2✔
403
    }
404

405
    /**
406
     * @return $this fluent interface
407
     */
408
    public function setSpaceBetweenBlocks(string $whitespace): self
6✔
409
    {
410
        $this->sSpaceBetweenBlocks = $whitespace;
6✔
411

412
        return $this;
6✔
413
    }
414

415
    /**
416
     * @internal
417
     */
418
    public function getBeforeAtRuleBlock(): string
2✔
419
    {
420
        return $this->sBeforeAtRuleBlock;
2✔
421
    }
422

423
    /**
424
     * @return $this fluent interface
425
     */
426
    public function setBeforeAtRuleBlock(string $whitespace): self
2✔
427
    {
428
        $this->sBeforeAtRuleBlock = $whitespace;
2✔
429

430
        return $this;
2✔
431
    }
432

433
    /**
434
     * @internal
435
     */
436
    public function getAfterAtRuleBlock(): string
2✔
437
    {
438
        return $this->sAfterAtRuleBlock;
2✔
439
    }
440

441
    /**
442
     * @return $this fluent interface
443
     */
444
    public function setAfterAtRuleBlock(string $whitespace): self
2✔
445
    {
446
        $this->sAfterAtRuleBlock = $whitespace;
2✔
447

448
        return $this;
2✔
449
    }
450

451
    /**
452
     * @internal
453
     */
454
    public function getSpaceBeforeSelectorSeparator(): string
2✔
455
    {
456
        return $this->sSpaceBeforeSelectorSeparator;
2✔
457
    }
458

459
    /**
460
     * @return $this fluent interface
461
     */
462
    public function setSpaceBeforeSelectorSeparator(string $whitespace): self
2✔
463
    {
464
        $this->sSpaceBeforeSelectorSeparator = $whitespace;
2✔
465

466
        return $this;
2✔
467
    }
468

469
    /**
470
     * @internal
471
     */
472
    public function getSpaceAfterSelectorSeparator(): string
2✔
473
    {
474
        return $this->sSpaceAfterSelectorSeparator;
2✔
475
    }
476

477
    /**
478
     * @return $this fluent interface
479
     */
480
    public function setSpaceAfterSelectorSeparator(string $whitespace): self
6✔
481
    {
482
        $this->sSpaceAfterSelectorSeparator = $whitespace;
6✔
483

484
        return $this;
6✔
485
    }
486

487
    /**
488
     * @internal
489
     */
490
    public function getSpaceBeforeListArgumentSeparator(): string
2✔
491
    {
492
        return $this->sSpaceBeforeListArgumentSeparator;
2✔
493
    }
494

495
    /**
496
     * @return $this fluent interface
497
     */
498
    public function setSpaceBeforeListArgumentSeparator(string $whitespace): self
2✔
499
    {
500
        $this->sSpaceBeforeListArgumentSeparator = $whitespace;
2✔
501

502
        return $this;
2✔
503
    }
504

505
    /**
506
     * @internal
507
     */
508
    public function getSpaceAfterListArgumentSeparator(): string
2✔
509
    {
510
        return $this->sSpaceAfterListArgumentSeparator;
2✔
511
    }
512

513
    /**
514
     * @return $this fluent interface
515
     */
516
    public function setSpaceAfterListArgumentSeparator(string $whitespace): self
3✔
517
    {
518
        $this->sSpaceAfterListArgumentSeparator = $whitespace;
3✔
519

520
        return $this;
3✔
521
    }
522

523
    /**
524
     * @internal
525
     */
526
    public function getSpaceBeforeOpeningBrace(): string
2✔
527
    {
528
        return $this->sSpaceBeforeOpeningBrace;
2✔
529
    }
530

531
    /**
532
     * @return $this fluent interface
533
     */
534
    public function setSpaceBeforeOpeningBrace(string $whitespace): self
6✔
535
    {
536
        $this->sSpaceBeforeOpeningBrace = $whitespace;
6✔
537

538
        return $this;
6✔
539
    }
540

541
    /**
542
     * @internal
543
     */
544
    public function getBeforeDeclarationBlock(): string
2✔
545
    {
546
        return $this->sBeforeDeclarationBlock;
2✔
547
    }
548

549
    /**
550
     * @return $this fluent interface
551
     */
552
    public function setBeforeDeclarationBlock(string $whitespace): self
2✔
553
    {
554
        $this->sBeforeDeclarationBlock = $whitespace;
2✔
555

556
        return $this;
2✔
557
    }
558

559
    /**
560
     * @internal
561
     */
562
    public function getAfterDeclarationBlockSelectors(): string
2✔
563
    {
564
        return $this->sAfterDeclarationBlockSelectors;
2✔
565
    }
566

567
    /**
568
     * @return $this fluent interface
569
     */
570
    public function setAfterDeclarationBlockSelectors(string $whitespace): self
2✔
571
    {
572
        $this->sAfterDeclarationBlockSelectors = $whitespace;
2✔
573

574
        return $this;
2✔
575
    }
576

577
    /**
578
     * @internal
579
     */
580
    public function getAfterDeclarationBlock(): string
2✔
581
    {
582
        return $this->sAfterDeclarationBlock;
2✔
583
    }
584

585
    /**
586
     * @return $this fluent interface
587
     */
588
    public function setAfterDeclarationBlock(string $whitespace): self
2✔
589
    {
590
        $this->sAfterDeclarationBlock = $whitespace;
2✔
591

592
        return $this;
2✔
593
    }
594

595
    /**
596
     * @internal
597
     */
598
    public function getIndentation(): string
2✔
599
    {
600
        return $this->sIndentation;
2✔
601
    }
602

603
    /**
604
     * @return $this fluent interface
605
     */
606
    public function setIndentation(string $sIndentation): self
3✔
607
    {
608
        $this->sIndentation = $sIndentation;
3✔
609

610
        return $this;
3✔
611
    }
612

613
    /**
614
     * @internal
615
     */
616
    public function getIgnoreExceptions(): bool
3✔
617
    {
618
        return $this->bIgnoreExceptions;
3✔
619
    }
620

621
    /**
622
     * @return $this fluent interface
623
     */
624
    public function setIgnoreExceptions(bool $bIgnoreExceptions): self
5✔
625
    {
626
        $this->bIgnoreExceptions = $bIgnoreExceptions;
5✔
627

628
        return $this;
5✔
629
    }
630

631
    /**
632
     * @internal
633
     */
634
    public function getRenderComments(): bool
3✔
635
    {
636
        return $this->bRenderComments;
3✔
637
    }
638

639
    /**
640
     * @return $this fluent interface
641
     */
642
    public function setRenderComments(bool $bRenderComments): self
7✔
643
    {
644
        $this->bRenderComments = $bRenderComments;
7✔
645

646
        return $this;
7✔
647
    }
648

649
    /**
650
     * @internal
651
     */
652
    public function getIndentationLevel(): int
2✔
653
    {
654
        return $this->iIndentationLevel;
2✔
655
    }
656

657
    /**
658
     * @return $this fluent interface
659
     */
660
    public function setIndentationLevel(int $iIndentationLevel): self
2✔
661
    {
662
        $this->iIndentationLevel = $iIndentationLevel;
2✔
663

664
        return $this;
2✔
665
    }
666

667
    /**
668
     * @param int $iNumber
669
     *
670
     * @return $this fluent interface
671
     */
NEW
672
    public function indentWithTabs($iNumber = 1): self
×
673
    {
674
        return $this->setIndentation(\str_repeat("\t", $iNumber));
×
675
    }
676

677
    /**
678
     * @param int $iNumber
679
     *
680
     * @return $this fluent interface
681
     */
NEW
682
    public function indentWithSpaces($iNumber = 2): self
×
683
    {
684
        return $this->setIndentation(\str_repeat(' ', $iNumber));
×
685
    }
686

687
    /**
688
     * @return OutputFormat
689
     */
690
    public function nextLevel()
19✔
691
    {
692
        if ($this->oNextLevelFormat === null) {
19✔
693
            $this->oNextLevelFormat = clone $this;
19✔
694
            $this->oNextLevelFormat->iIndentationLevel++;
19✔
695
            $this->oNextLevelFormat->oFormatter = null;
19✔
696
        }
697
        return $this->oNextLevelFormat;
19✔
698
    }
699

700
    public function beLenient(): void
×
701
    {
702
        $this->bIgnoreExceptions = true;
×
703
    }
×
704

705
    /**
706
     * @return OutputFormatter
707
     */
708
    public function getFormatter()
19✔
709
    {
710
        if ($this->oFormatter === null) {
19✔
711
            $this->oFormatter = new OutputFormatter($this);
19✔
712
        }
713
        return $this->oFormatter;
19✔
714
    }
715

716
    /**
717
     * @return int
718
     *
719
     * @internal
720
     */
721
    public function level()
19✔
722
    {
723
        return $this->iIndentationLevel;
19✔
724
    }
725

726
    /**
727
     * Creates an instance of this class without any particular formatting settings.
728
     */
729
    public static function create(): self
18✔
730
    {
731
        return new OutputFormat();
18✔
732
    }
733

734
    /**
735
     * Creates an instance of this class with a preset for compact formatting.
736
     */
737
    public static function createCompact(): self
3✔
738
    {
739
        $format = self::create();
3✔
740
        $format->set('Space*Rules', '')
3✔
741
            ->set('Space*Blocks', '')
3✔
742
            ->setSpaceAfterRuleName('')
3✔
743
            ->setSpaceBeforeOpeningBrace('')
3✔
744
            ->setSpaceAfterSelectorSeparator('')
3✔
745
            ->setRenderComments(false);
3✔
746
        return $format;
3✔
747
    }
748

749
    /**
750
     * Creates an instance of this class with a preset for pretty formatting.
751
     */
752
    public static function createPretty(): self
3✔
753
    {
754
        $format = self::create();
3✔
755
        $format->set('Space*Rules', "\n")
3✔
756
            ->set('Space*Blocks', "\n")
3✔
757
            ->setSpaceBetweenBlocks("\n\n")
3✔
758
            ->set('SpaceAfterListArgumentSeparator', ['default' => '', ',' => ' '])
3✔
759
            ->setRenderComments(true);
3✔
760
        return $format;
3✔
761
    }
762
}
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