Skip to content

Commit ae7e206

Browse files
committed
fix: support @import string
Signed-off-by: Emilien Escalle <[email protected]>
1 parent e3cd551 commit ae7e206

File tree

3 files changed

+120
-81
lines changed

3 files changed

+120
-81
lines changed

src/CssLint/Linter.php

Lines changed: 55 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -194,34 +194,39 @@ protected function lintChar(string $charValue): ?bool
194194
return true;
195195
}
196196

197-
if (is_bool($bLintCommentChar = $this->lintCommentChar($charValue))) {
197+
if (is_bool($lintImportChar = $this->lintImportChar($charValue))) {
198198
$this->setPreviousChar($charValue);
199-
return $bLintCommentChar;
199+
return $lintImportChar;
200200
}
201201

202-
if (is_bool($bLintSelectorChar = $this->lintSelectorChar($charValue))) {
202+
if (is_bool($lintCommentChar = $this->lintCommentChar($charValue))) {
203203
$this->setPreviousChar($charValue);
204-
return $bLintSelectorChar;
204+
return $lintCommentChar;
205205
}
206206

207-
if (is_bool($bLintSelectorContentChar = $this->lintSelectorContentChar($charValue))) {
207+
if (is_bool($lintSelectorChar = $this->lintSelectorChar($charValue))) {
208208
$this->setPreviousChar($charValue);
209-
return $bLintSelectorContentChar;
209+
return $lintSelectorChar;
210210
}
211211

212-
if (is_bool($bLintPropertyNameChar = $this->lintPropertyNameChar($charValue))) {
212+
if (is_bool($lintSelectorContentChar = $this->lintSelectorContentChar($charValue))) {
213213
$this->setPreviousChar($charValue);
214-
return $bLintPropertyNameChar;
214+
return $lintSelectorContentChar;
215215
}
216216

217-
if (is_bool($bLintPropertyContentChar = $this->lintPropertyContentChar($charValue))) {
217+
if (is_bool($lintPropertyNameChar = $this->lintPropertyNameChar($charValue))) {
218218
$this->setPreviousChar($charValue);
219-
return $bLintPropertyContentChar;
219+
return $lintPropertyNameChar;
220220
}
221221

222-
if (is_bool($bLintNestedSelectorChar = $this->lintNestedSelectorChar($charValue))) {
222+
if (is_bool($lintPropertyContentChar = $this->lintPropertyContentChar($charValue))) {
223223
$this->setPreviousChar($charValue);
224-
return $bLintNestedSelectorChar;
224+
return $lintPropertyContentChar;
225+
}
226+
227+
if (is_bool($lintNestedSelectorChar = $this->lintNestedSelectorChar($charValue))) {
228+
$this->setPreviousChar($charValue);
229+
return $lintNestedSelectorChar;
225230
}
226231

227232
$this->addError('Unexpected char ' . json_encode($charValue));
@@ -292,14 +297,14 @@ protected function lintSelectorChar(string $charValue): ?bool
292297
// Start of selector content
293298
if ($charValue === '{') {
294299
// Check if selector if valid
295-
$sSelector = trim($this->getContextContent());
300+
$selector = trim($this->getContextContent());
296301

297302
// @nested is a specific selector content
298303
if (
299304
// @media selector
300-
preg_match('/^@media.+/', $sSelector)
305+
preg_match('/^@media.+/', $selector)
301306
// Keyframes selector
302-
|| preg_match('/^@.*keyframes.+/', $sSelector)
307+
|| preg_match('/^@.*keyframes.+/', $selector)
303308
) {
304309
$this->setNestedSelector(true);
305310
$this->resetContext();
@@ -313,41 +318,41 @@ protected function lintSelectorChar(string $charValue): ?bool
313318

314319
// There cannot have two following commas
315320
if ($charValue === ',') {
316-
$sSelector = $this->getContextContent();
317-
if ($sSelector === '' || $sSelector === '0' || in_array(preg_match('/, *$/', $sSelector), [0, false], true)) {
321+
$selector = $this->getContextContent();
322+
if ($selector === '' || $selector === '0' || in_array(preg_match('/, *$/', $selector), [0, false], true)) {
318323
$this->addContextContent($charValue);
319324
return true;
320325
}
321326

322327
$this->addError(sprintf(
323328
'Selector token %s cannot be preceded by "%s"',
324329
json_encode($charValue),
325-
$sSelector
330+
$selector
326331
));
327332
return false;
328333
}
329334

330335
// Wildcard and hash
331336
if (in_array($charValue, ['*', '#'], true)) {
332-
$sSelector = $this->getContextContent();
333-
if ($sSelector === '' || $sSelector === '0' || preg_match('/[a-zA-Z>,\'"] *$/', $sSelector)) {
337+
$selector = $this->getContextContent();
338+
if ($selector === '' || $selector === '0' || preg_match('/[a-zA-Z>,\'"] *$/', $selector)) {
334339
$this->addContextContent($charValue);
335340
return true;
336341
}
337342

338-
$this->addError('Selector token "' . $charValue . '" cannot be preceded by "' . $sSelector . '"');
343+
$this->addError('Selector token "' . $charValue . '" cannot be preceded by "' . $selector . '"');
339344
return true;
340345
}
341346

342347
// Dot
343348
if ($charValue === '.') {
344-
$sSelector = $this->getContextContent();
345-
if ($sSelector === '' || $sSelector === '0' || preg_match('/(, |[a-zA-Z]).*$/', $sSelector)) {
349+
$selector = $this->getContextContent();
350+
if ($selector === '' || $selector === '0' || preg_match('/(, |[a-zA-Z]).*$/', $selector)) {
346351
$this->addContextContent($charValue);
347352
return true;
348353
}
349354

350-
$this->addError('Selector token "' . $charValue . '" cannot be preceded by "' . $sSelector . '"');
355+
$this->addError('Selector token "' . $charValue . '" cannot be preceded by "' . $selector . '"');
351356
return true;
352357
}
353358

@@ -485,6 +490,32 @@ protected function lintNestedSelectorChar(string $charValue): ?bool
485490
return null;
486491
}
487492

493+
/**
494+
* Performs lint for a given char, check @import rules
495+
* @return bool|null : true if the process should continue, else false, null if this char is not an @import rule
496+
*/
497+
protected function lintImportChar(string $charValue): ?bool
498+
{
499+
if ($this->assertContext(null) && $charValue === '@') {
500+
$this->setContext(self::CONTEXT_SELECTOR);
501+
$this->addContextContent($charValue);
502+
return true;
503+
}
504+
505+
if ($this->assertContext(self::CONTEXT_SELECTOR) && str_starts_with($this->getContextContent(), '@import')) {
506+
$this->addContextContent($charValue);
507+
508+
if ($charValue === ';') {
509+
$this->resetContext();
510+
return true;
511+
}
512+
513+
return true;
514+
}
515+
516+
return null;
517+
}
518+
488519
/**
489520
* Check if a given char is an end of line token
490521
* @return boolean : true if the char is an end of line token, else false

tests/TestSuite/LinterTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,4 +194,12 @@ public function testLintNotValidCssFile()
194194
'Unterminated "selector content" (line: 17, char: 0)',
195195
], $this->linter->getErrors());
196196
}
197+
198+
public function testLintValidImportRule()
199+
{
200+
$this->assertTrue(
201+
$this->linter->lintString("@import url('https://fonts.googleapis.com/css2?family=Poppins&display=swap');"),
202+
print_r($this->linter->getErrors(), true)
203+
);
204+
}
197205
}

tests/TestSuite/PropertiesTest.php

Lines changed: 57 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -9,149 +9,149 @@ class PropertiesTest extends TestCase
99
{
1010
public function testShouldReturnTrueWhenGivenStandardPropertyExists()
1111
{
12-
$oProperties = new Properties();
13-
$this->assertTrue($oProperties->propertyExists('align-content'));
12+
$properties = new Properties();
13+
$this->assertTrue($properties->propertyExists('align-content'));
1414
}
1515

1616
public function testShouldReturnTrueWhenGivenConstructorStandardPropertyExists()
1717
{
18-
$oProperties = new Properties();
19-
$this->assertTrue($oProperties->propertyExists('-moz-align-content'));
18+
$properties = new Properties();
19+
$this->assertTrue($properties->propertyExists('-moz-align-content'));
2020
}
2121

2222
public function testShouldReturnTrueWhenGivenConstructorNonStandardPropertyExists()
2323
{
24-
$oProperties = new Properties();
25-
$this->assertTrue($oProperties->propertyExists('-moz-font-smoothing'));
24+
$properties = new Properties();
25+
$this->assertTrue($properties->propertyExists('-moz-font-smoothing'));
2626
}
2727

2828
public function testShouldReturnTrueWhenGivenPropertyDoesNotExist()
2929
{
30-
$oProperties = new Properties();
31-
$this->assertFalse($oProperties->propertyExists('-wrong-font-smoothing'));
30+
$properties = new Properties();
31+
$this->assertFalse($properties->propertyExists('-wrong-font-smoothing'));
3232
}
3333

3434
public function testGetAllowedIndentationChars()
3535
{
36-
$oProperties = new Properties();
37-
$this->assertEquals([" "], $oProperties->getAllowedIndentationChars());
36+
$properties = new Properties();
37+
$this->assertEquals([" "], $properties->getAllowedIndentationChars());
3838
}
3939

4040
public function testSetAllowedIndentationChars()
4141
{
42-
$oProperties = new Properties();
42+
$properties = new Properties();
4343
$aAllowedIndentationChars = ["\t"];
44-
$oProperties->setAllowedIndentationChars($aAllowedIndentationChars);
45-
$this->assertEquals($aAllowedIndentationChars, $oProperties->getAllowedIndentationChars());
44+
$properties->setAllowedIndentationChars($aAllowedIndentationChars);
45+
$this->assertEquals($aAllowedIndentationChars, $properties->getAllowedIndentationChars());
4646
}
4747

4848
public function testShouldReturnTrueWhenGivenCharIsAnAllowedIndentationChar()
4949
{
50-
$oProperties = new Properties();
51-
$this->assertTrue($oProperties->isAllowedIndentationChar(" "));
50+
$properties = new Properties();
51+
$this->assertTrue($properties->isAllowedIndentationChar(" "));
5252
}
5353

5454
public function testShouldReturnTrueWhenGivenCharIsNotAnAllowedIndentationChar()
5555
{
56-
$oProperties = new Properties();
57-
$this->assertFalse($oProperties->isAllowedIndentationChar("\t"));
56+
$properties = new Properties();
57+
$this->assertFalse($properties->isAllowedIndentationChar("\t"));
5858
}
5959

6060
public function testMergeConstructorsShouldDisableAContructor()
6161
{
62-
$oProperties = new Properties();
63-
$this->assertTrue($oProperties->propertyExists('-moz-font-smoothing'));
62+
$properties = new Properties();
63+
$this->assertTrue($properties->propertyExists('-moz-font-smoothing'));
6464

65-
$oProperties->mergeConstructors(['moz' => false]);
66-
$this->assertFalse($oProperties->propertyExists('-moz-font-smoothing'));
65+
$properties->mergeConstructors(['moz' => false]);
66+
$this->assertFalse($properties->propertyExists('-moz-font-smoothing'));
6767
}
6868

6969
public function testMergeConstructorsShouldAddAContructor()
7070
{
71-
$oProperties = new Properties();
72-
$this->assertFalse($oProperties->propertyExists('-new-font-smoothing'));
71+
$properties = new Properties();
72+
$this->assertFalse($properties->propertyExists('-new-font-smoothing'));
7373

74-
$oProperties->mergeConstructors(['new' => true]);
75-
$this->assertTrue($oProperties->propertyExists('-new-font-smoothing'));
74+
$properties->mergeConstructors(['new' => true]);
75+
$this->assertTrue($properties->propertyExists('-new-font-smoothing'));
7676
}
7777

7878
public function testMergeStandardsShouldDisableAContructor()
7979
{
80-
$oProperties = new Properties();
81-
$this->assertTrue($oProperties->propertyExists('align-content'));
80+
$properties = new Properties();
81+
$this->assertTrue($properties->propertyExists('align-content'));
8282

83-
$oProperties->mergeStandards(['align-content' => false]);
84-
$this->assertFalse($oProperties->propertyExists('align-content'));
83+
$properties->mergeStandards(['align-content' => false]);
84+
$this->assertFalse($properties->propertyExists('align-content'));
8585
}
8686

8787
public function testMergeStandardsShouldAddAContructor()
8888
{
89-
$oProperties = new Properties();
90-
$this->assertFalse($oProperties->propertyExists('new-content'));
89+
$properties = new Properties();
90+
$this->assertFalse($properties->propertyExists('new-content'));
9191

92-
$oProperties->mergeStandards(['new-content' => true]);
93-
$this->assertTrue($oProperties->propertyExists('new-content'));
92+
$properties->mergeStandards(['new-content' => true]);
93+
$this->assertTrue($properties->propertyExists('new-content'));
9494
}
9595

9696
public function testMergeNonStandardsShouldDisableAContructor()
9797
{
98-
$oProperties = new Properties();
99-
$this->assertTrue($oProperties->propertyExists('-moz-font-smoothing'));
98+
$properties = new Properties();
99+
$this->assertTrue($properties->propertyExists('-moz-font-smoothing'));
100100

101-
$oProperties->mergeNonStandards(['font-smoothing' => false]);
102-
$this->assertFalse($oProperties->propertyExists('-moz-font-smoothing'));
101+
$properties->mergeNonStandards(['font-smoothing' => false]);
102+
$this->assertFalse($properties->propertyExists('-moz-font-smoothing'));
103103
}
104104

105105
public function testMergeNonStandardsShouldAddAContructor()
106106
{
107-
$oProperties = new Properties();
108-
$this->assertFalse($oProperties->propertyExists('-moz-new-content'));
107+
$properties = new Properties();
108+
$this->assertFalse($properties->propertyExists('-moz-new-content'));
109109

110-
$oProperties->mergeNonStandards(['new-content' => true]);
111-
$this->assertTrue($oProperties->propertyExists('-moz-new-content'));
110+
$properties->mergeNonStandards(['new-content' => true]);
111+
$this->assertTrue($properties->propertyExists('-moz-new-content'));
112112
}
113113

114114
public function testSetOptionsAllowedIndentationChars()
115115
{
116-
$oProperties = new Properties();
117-
$this->assertFalse($oProperties->isAllowedIndentationChar("\t"));
116+
$properties = new Properties();
117+
$this->assertFalse($properties->isAllowedIndentationChar("\t"));
118118

119-
$oProperties->setOptions([
119+
$properties->setOptions([
120120
'allowedIndentationChars' => ["\t"],
121121
]);
122-
$this->assertTrue($oProperties->isAllowedIndentationChar("\t"));
122+
$this->assertTrue($properties->isAllowedIndentationChar("\t"));
123123
}
124124

125125
public function testSetOptionsConstructors()
126126
{
127-
$oProperties = new Properties();
128-
$this->assertFalse($oProperties->propertyExists('-new-font-smoothing'));
127+
$properties = new Properties();
128+
$this->assertFalse($properties->propertyExists('-new-font-smoothing'));
129129

130-
$oProperties->setOptions([
130+
$properties->setOptions([
131131
'constructors' => ['new' => true],
132132
]);
133-
$this->assertTrue($oProperties->propertyExists('-new-font-smoothing'));
133+
$this->assertTrue($properties->propertyExists('-new-font-smoothing'));
134134
}
135135

136136
public function testSetOptionsStandards()
137137
{
138-
$oProperties = new Properties();
139-
$this->assertFalse($oProperties->propertyExists('new-content'));
138+
$properties = new Properties();
139+
$this->assertFalse($properties->propertyExists('new-content'));
140140

141-
$oProperties->setOptions([
141+
$properties->setOptions([
142142
'standards' => ['new-content' => true],
143143
]);
144-
$this->assertTrue($oProperties->propertyExists('new-content'));
144+
$this->assertTrue($properties->propertyExists('new-content'));
145145
}
146146

147147
public function testSetOptionsNonStandards()
148148
{
149-
$oProperties = new Properties();
150-
$this->assertFalse($oProperties->propertyExists('-moz-new-content'));
149+
$properties = new Properties();
150+
$this->assertFalse($properties->propertyExists('-moz-new-content'));
151151

152-
$oProperties->setOptions([
152+
$properties->setOptions([
153153
'nonStandards' => ['new-content' => true],
154154
]);
155-
$this->assertTrue($oProperties->propertyExists('-moz-new-content'));
155+
$this->assertTrue($properties->propertyExists('-moz-new-content'));
156156
}
157157
}

0 commit comments

Comments
 (0)