Skip to content

Commit 436084e

Browse files
committed
Automatically fix closing tags when possible
1 parent 8752629 commit 436084e

File tree

6 files changed

+255
-5
lines changed

6 files changed

+255
-5
lines changed

Magento2/Sniffs/Html/HtmlClosingVoidTagsSniff.php

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,41 @@ public function process(File $phpcsFile, $stackPtr): void
8282
if (preg_match_all('$<(\w{2,})\s?[^<]*\/>$', $html, $matches, PREG_SET_ORDER)) {
8383
foreach ($matches as $match) {
8484
if (in_array($match[1], self::HTML_VOID_ELEMENTS)) {
85-
$phpcsFile->addWarning(
85+
$fix = $phpcsFile->addFixableWarning(
8686
sprintf(self::WARNING_MESSAGE, $match[0]),
8787
null,
8888
self::WARNING_CODE
8989
);
90+
91+
if ($fix) {
92+
$this->fixClosingTag($phpcsFile, $match[0]);
93+
}
9094
}
9195
}
9296
}
9397
}
98+
99+
/**
100+
* Apply a fix for the detected issue
101+
*
102+
* @param File $phpcsFile
103+
* @param string $needle
104+
*/
105+
public function fixClosingTag(File $phpcsFile, string $needle): void
106+
{
107+
foreach ($phpcsFile->getTokens() as $ptr => $token) {
108+
if ($token['code'] !== T_INLINE_HTML) {
109+
continue;
110+
}
111+
112+
if (str_contains($token['content'], $needle)) {
113+
$original = $needle;
114+
$replacement = str_replace('/>', '>', $original);
115+
116+
$phpcsFile->fixer->replaceToken($ptr, str_replace($original, $replacement, $token['content']));
117+
118+
break;
119+
}
120+
}
121+
}
94122
}

Magento2/Sniffs/Html/HtmlSelfClosingTagsSniff.php

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,42 @@ public function process(File $phpcsFile, $stackPtr)
6868
if (preg_match_all('$<(\w{2,})\s?[^<]*\/>$', $html, $matches, PREG_SET_ORDER)) {
6969
foreach ($matches as $match) {
7070
if (!in_array($match[1], self::HTML_VOID_ELEMENTS)) {
71-
$phpcsFile->addError(
71+
$fix = $phpcsFile->addFixableError(
7272
'Avoid using self-closing tag with non-void html element'
7373
. ' - "' . $match[0] . PHP_EOL,
7474
null,
7575
'HtmlSelfClosingNonVoidTag'
7676
);
77+
78+
if ($fix) {
79+
$this->fixClosingTag($phpcsFile, $match);
80+
}
7781
}
7882
}
7983
}
8084
}
85+
86+
/**
87+
* Apply a fix for the detected issue
88+
*
89+
* @param File $phpcsFile
90+
* @param array $match
91+
*/
92+
private function fixClosingTag(File $phpcsFile, array $match): void
93+
{
94+
foreach ($phpcsFile->getTokens() as $ptr => $token) {
95+
if ($token['code'] !== T_INLINE_HTML) {
96+
continue;
97+
}
98+
99+
if (str_contains($token['content'], $match[0])) {
100+
$original = $match[0];
101+
$replacement = str_replace('/>', '></' . $match[1] . '>', $original);
102+
103+
$phpcsFile->fixer->replaceToken($ptr, str_replace($original, $replacement, $token['content']));
104+
105+
return;
106+
}
107+
}
108+
}
81109
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<!--
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
-->
7+
8+
<html>
9+
<head>
10+
<base>
11+
<link>
12+
</head>
13+
<body>
14+
<area alt="">
15+
<br>
16+
<table>
17+
<colgroup>
18+
<col>
19+
</colgroup>
20+
</table>
21+
<embed>
22+
<hr>
23+
<img src="" alt="">
24+
<input type="text" id="test_input">
25+
<link>
26+
<meta>
27+
<video>
28+
<source>
29+
<track src="">
30+
</video>
31+
<wbr>
32+
</body>
33+
</html>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<!--
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
-->
7+
8+
<html>
9+
<head>
10+
<base/>
11+
<link/>
12+
</head>
13+
<body>
14+
<area alt=""/>
15+
<br/>
16+
<table>
17+
<colgroup>
18+
<col/>
19+
</colgroup>
20+
</table>
21+
<embed/>
22+
<hr/>
23+
<img src="" alt=""/>
24+
<input type="text" id="test_input"/>
25+
<link/>
26+
<meta/>
27+
<video>
28+
<source/>
29+
<track src=""/>
30+
</video>
31+
<wbr/>
32+
33+
<label for="test_input"></label>
34+
<style type="text/css"></style>
35+
<div></div>
36+
<span></span>
37+
<text></text>
38+
<render></render>
39+
<each></each>
40+
<translate></translate>
41+
<scope></scope>
42+
</body>
43+
</html>

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"ext-dom": "*",
1515
"phpcompatibility/php-compatibility": "^9.3",
1616
"squizlabs/php_codesniffer": "^3.6.1",
17-
"rector/rector": "^0.14.8"
17+
"rector/rector": "^0.14.8",
18+
"symfony/polyfill": "^1.15"
1819
},
1920
"require-dev": {
2021
"phpunit/phpunit": "^9.5.8"

composer.lock

Lines changed: 119 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)