Skip to content

Commit 65eda98

Browse files
committed
Merge branch 'develop' of https://github.com/magento/magento-coding-standard into AC-662
2 parents 7d317ba + c5dbf03 commit 65eda98

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+3652
-0
lines changed

.github/workflows/php.yml

+8
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ jobs:
2525
name: Tests with PHP ${{ matrix.php-version }} and ${{ matrix.dependencies }} dependencies
2626

2727
steps:
28+
- name: Setup node
29+
uses: actions/setup-node@v2
30+
2831
- uses: actions/checkout@v2
2932

3033
- name: Setup PHP
@@ -34,6 +37,11 @@ jobs:
3437
env:
3538
COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3639

40+
- name: Install dependencies
41+
run: npm install
42+
- name: Run ESLint
43+
run: npm run eslint -- eslint/rules
44+
3745
- name: Validate composer
3846
run: composer validate
3947

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/vendor/*
22
/bin/*
3+
/node_modules
34

45
# IDE files
56
.idea/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento2\Sniffs\Html;
10+
11+
use PHP_CodeSniffer\Sniffs\Sniff;
12+
use PHP_CodeSniffer\Files\File;
13+
14+
/**
15+
* Sniff for self-closing tags
16+
*/
17+
class HtmlSelfClosingTagsSniff implements Sniff
18+
{
19+
/**
20+
* List of void elements
21+
*
22+
* https://www.w3.org/TR/html51/syntax.html#writing-html-documents-elements
23+
*
24+
* @var string[]
25+
*/
26+
private $voidElements = [
27+
'area',
28+
'base',
29+
'br',
30+
'col',
31+
'embed',
32+
'hr',
33+
'img',
34+
'input',
35+
'keygen',
36+
'link',
37+
'menuitem',
38+
'meta',
39+
'param',
40+
'source',
41+
'track',
42+
'wbr',
43+
];
44+
45+
/**
46+
* @inheritDoc
47+
*/
48+
public function register()
49+
{
50+
return [T_INLINE_HTML];
51+
}
52+
53+
/**
54+
* Detect use of self-closing tag with non-void html element
55+
*
56+
* @param File $phpcsFile
57+
* @param int $stackPtr
58+
* @return int|void
59+
*/
60+
public function process(File $phpcsFile, $stackPtr)
61+
{
62+
if ($stackPtr !== 0) {
63+
return;
64+
}
65+
$html = $phpcsFile->getTokensAsString($stackPtr, count($phpcsFile->getTokens()));
66+
67+
if (empty($html)) {
68+
return;
69+
}
70+
71+
if (preg_match_all('$<(\w{2,})\s?[^<]*\/>$', $html, $matches, PREG_SET_ORDER)) {
72+
foreach ($matches as $match) {
73+
if (!in_array($match[1], $this->voidElements)) {
74+
$phpcsFile->addError(
75+
'Avoid using self-closing tag with non-void html element'
76+
. ' - "' . $match[0] . PHP_EOL,
77+
null,
78+
'HtmlSelfClosingNonVoidTag'
79+
);
80+
}
81+
}
82+
}
83+
}
84+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
<?php
2+
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
8+
namespace Magento2\Sniffs\Legacy;
9+
10+
use DOMDocument;
11+
use PHP_CodeSniffer\Sniffs\Sniff;
12+
use PHP_CodeSniffer\Files\File;
13+
14+
class ObsoleteConfigNodesSniff implements Sniff
15+
{
16+
private const ERROR_MESSAGE_CONFIG = "Nodes identified by XPath '%s' are obsolete. %s";
17+
private const ERROR_CODE_CONFIG = 'ObsoleteNodeInConfig';
18+
19+
/**
20+
* @inheritdoc
21+
*/
22+
public function register()
23+
{
24+
return [
25+
T_INLINE_HTML,
26+
];
27+
}
28+
29+
/**
30+
* @inheritdoc
31+
*/
32+
public function process(File $phpcsFile, $stackPtr)
33+
{
34+
if ($stackPtr > 0) {
35+
return;
36+
}
37+
38+
// We need to format the incoming XML to avoid tags split into several lines. In that case, PHP's DOMElement
39+
// returns the position of the closing /> as the position of the tag, and we need the position of <
40+
// instead, as it is the one we compare with $stackPtr later on.
41+
$xml = simplexml_load_string($this->getFormattedXML($phpcsFile));
42+
if ($xml === false) {
43+
$phpcsFile->addError(
44+
sprintf(
45+
"Couldn't parse contents of '%s', check that they are in valid XML format",
46+
$phpcsFile->getFilename(),
47+
),
48+
$stackPtr,
49+
self::ERROR_CODE_CONFIG
50+
);
51+
}
52+
53+
foreach ($this->getObsoleteNodes() as $xpath => $suggestion) {
54+
$matches = $xml->xpath($xpath);
55+
if (empty($matches)) {
56+
continue;
57+
}
58+
foreach ($matches as $match) {
59+
$phpcsFile->addError(
60+
sprintf(
61+
self::ERROR_MESSAGE_CONFIG,
62+
$xpath,
63+
$suggestion
64+
),
65+
dom_import_simplexml($match)->getLineNo()-1,
66+
self::ERROR_CODE_CONFIG
67+
);
68+
}
69+
}
70+
}
71+
72+
/**
73+
* Format the incoming XML to avoid tags split into several lines.
74+
*
75+
* @param File $phpcsFile
76+
* @return false|string
77+
*/
78+
private function getFormattedXML(File $phpcsFile)
79+
{
80+
$doc = new DomDocument('1.0');
81+
$doc->formatOutput = true;
82+
$doc->loadXML($phpcsFile->getTokensAsString(0, 999999));
83+
return $doc->saveXML();
84+
}
85+
86+
/**
87+
* Get a list of obsolete nodes in the format <class_name> => <replacement>
88+
*
89+
* @return array
90+
*/
91+
private function getObsoleteNodes(): array
92+
{
93+
return [
94+
'/config/global/fieldsets' => '',
95+
'/config/global/cache/betatypes' => '',
96+
'/config/admin/fieldsets' => '',
97+
'/config/general/locale' =>
98+
'This configuration moved to Di configuration of \Magento\Framework\Locale\ConfigInterface',
99+
'/config/global/can_use_base_url' =>
100+
'This configuration moved to Di configuration of \Magento\Backend\App\Action\Context class',
101+
'/config/global/locale/allow/codes' =>
102+
'This configuration moved to Di configuration of \Magento\Framework\Locale\ConfigInterface',
103+
'/config/global/locale/allow/currencies' =>
104+
'This configuration moved to Di configuration of \Magento\Framework\Locale\ConfigInterface',
105+
'/config/global/mime/types' =>
106+
'This configuration moved to Di configuration for \Magento\Downloadable\Helper\File class',
107+
'/config/global/models/*/deprecatedNode' => '',
108+
'/config/global/models/*/entities/*/table' => '',
109+
'/config/global/models/*/class' => '',
110+
'/config/global/helpers/*/class' => '',
111+
'/config/global/blocks/*/class' => '',
112+
'/config/global/models/*/resourceModel' => '',
113+
'/config/global/page/layouts' => 'Moved to page_layouts.xml',
114+
'/config/global/cms/layouts' => 'This was never used and is no longer supported',
115+
'/config/global/payment/cc/types/*/validator' =>
116+
'This configuration was moved to DI configuration of \Magento\Centinel\Model\StateFactory',
117+
'/config/global/payment' => 'Move them to payment.xml.',
118+
'/config/adminhtml/menu' => 'Move them to adminhtml.xml.',
119+
'/config/adminhtml/acl' => 'Move them to adminhtml.xml.',
120+
'/config/adminhtml/global_search' =>
121+
'This configuration moved to Di configuration of \Magento\Backend\Controller\Index',
122+
'/config/*[self::global|self::adminhtml|self::frontend]/di' => 'This configuration moved to di.xml file',
123+
'/config/*[self::global|self::adminhtml|self::frontend]/events' =>
124+
'This configuration moved to events.xml file',
125+
'/config/*[self::global|self::adminhtml|self::frontend]/routers' =>
126+
'Routes configuration moved to routes.xml file,' .
127+
'routers list can be set through Di configuration of \Magento\Framework\App\RouterList model',
128+
'/config/global/importexport' => 'This configuration moved to import.xml and export.xml files',
129+
'/config/global/catalog/product/type' => 'This configuration moved to product_types.xml file',
130+
'/config/global/catalog/product/options' => 'This configuration moved to product_options.xml file',
131+
'/config/global/catalog/product/media/image_types' => 'This configuration moved to Di configuration of ' .
132+
'\Magento\Backend\Block\Catalog\Product\Frontend\Product\Watermark',
133+
'/config/global/eav_attributes' => 'This configuration moved to eav_attributes.xml file',
134+
'/config/global/index' => 'This configuration moved to indexers.xml file',
135+
'/config/global/catalogrule' =>
136+
'This configuration moved to Di configuration of \Magento\CatalogRule\Model\Rule',
137+
'/config/global/salesrule' =>
138+
'This configuration moved to Di configuration of \Magento\SalesRule\Helper\Coupon',
139+
'/config/global/session' =>
140+
'This configuration moved to Di configuration of \Magento\Framework\Session\Validator',
141+
'/config/global/ignore_user_agents' =>
142+
'This configuration moved to Di configuration of \Magento\Log\Model\Visitor',
143+
'/config/global/request' =>
144+
'This configuration moved to Di configuration of \Magento\Framework\App\RequestInterface',
145+
'/config/global/secure_url' =>
146+
'This configuration moved to Di configuration of \Magento\Framework\Url\SecurityInfo',
147+
'/config/global/dev' =>
148+
'This configuration moved to Di configuration of \Magento\Framework\App\Action\Context',
149+
'/config/global/webapi' =>
150+
'This configuration moved to Di configuration of '.
151+
' \Magento\Webapi\Controller\Request\Rest\Interpreter\Factory' .
152+
' and \Magento\Webapi\Controller\Response\Rest\Renderer\Factory',
153+
'/config/global/cms' =>
154+
'This configuration moved to Di configuration of \Magento\Cms\Model\Wysiwyg\Images\Storage' .
155+
' and \Magento\Cms\Model\Wysiwyg\Config',
156+
'/config/global/widget' =>
157+
'This configuration moved to Di configuration of \Magento\Cms\Model\Template\FilterProvider',
158+
'/config/global/catalog/product/flat/max_index_count' =>
159+
'This configuration moved to Di configuration of '.
160+
'\Magento\Catalog\Model\ResourceModel\Product\Flat\Indexer',
161+
'/config/global/catalog/product/flat/attribute_groups' =>
162+
'This configuration moved to Di configuration of '.
163+
'\Magento\Catalog\Model\ResourceModel\Product\Flat\Indexer',
164+
'/config/global/catalog/product/flat/add_filterable_attributes' =>
165+
'This configuration moved to Di configuration of \Magento\Catalog\Helper\Product\Flat\Indexer',
166+
'/config/global/catalog/product/flat/add_child_data' =>
167+
'This configuration moved to Di configuration of \Magento\Catalog\Helper\Product\Flat\Indexer',
168+
'/config/global/catalog/content/template_filter' =>
169+
'This configuration moved to Di configuration of \Magento\Catalog\Helper\Data',
170+
'/config/frontend/catalog/per_page_values/list' =>
171+
'This configuration moved to Di configuration of \Magento\Catalog\Model\Config\Source\ListPerPage',
172+
'/config/frontend/catalog/per_page_values/grid' =>
173+
'This configuration moved to Di configuration of \Magento\Catalog\Model\Config\Source\GridPerPage',
174+
'/config/global/catalog/product/design' => 'This configuration moved to Di configuration of' .
175+
' \Magento\Catalog\Model\Entity\Product\Attribute\Design\Option\Container',
176+
'/config/global/catalog/product/attributes' => 'This configuration moved catalog_attributes.xml',
177+
'/config/global/eav_frontendclasses' => 'This configuration was removed. ' .
178+
'Please pluginize \Magento\Eav\Helper\Data::getFrontendClasses to extend frontend classes list',
179+
'/config/global/resources' =>
180+
'This configuration moved to Di configuration of \Magento\Framework\App\ResourceConnection',
181+
'/config/global/resource' =>
182+
'This configuration moved to Di configuration of \Magento\Framework\App\ResourceConnection',
183+
'/config/*/events/core_block_abstract_to_html_after' =>
184+
'Event has been replaced with "core_layout_render_element"',
185+
'/config/*/events/catalog_controller_product_delete' => '',
186+
'/config//observers/*/args' => 'This was an undocumented and unused feature in event subscribers',
187+
'/config/default/design/theme' => 'Relocated to /config/<area>/design/theme',
188+
'/config/global/theme' => 'Configuration moved to DI file settings',
189+
'/config/default/web/*/base_js_url' => '',
190+
'/config/default/web/*/base_skin_url' => '/config/default/web/*/base_static_url',
191+
'/config/default/web/*/base_cache_url' => '/config/default/web/*/base_static_url',
192+
'/config/global/cache/types/*/tags' => 'use /config/global/cache/types/*/class node instead',
193+
'/config/global/disable_local_modules' => '',
194+
'/config/global/newsletter/tempate_filter' => 'Use DI configs to setup model for template processing',
195+
'/config/*/layout' => 'Use convention for layout files placement instead of configuration',
196+
'/config/frontend/product/collection/attributes' =>
197+
'Use /config/group[@name="catalog_product"] of catalog_attributes.xml',
198+
'/config/frontend/category/collection/attributes' =>
199+
'Use /config/group[@name="catalog_category"] of catalog_attributes.xml',
200+
'/config/global/sales/quote/item/product_attributes' =>
201+
'Use /config/group[@name="quote_item"] of catalog_attributes.xml',
202+
'/config/global/wishlist/item/product_attributes' =>
203+
'Use /config/group[@name="wishlist_item"] of catalog_attributes.xml',
204+
'/config/global/catalog/product/flat/attribute_nodes' =>
205+
'Use /config/global/catalog/product/flat/attribute_groups',
206+
'/config/global/customer/address/formats' => 'Use /config/format of address_formats.xml',
207+
'/config/global/pdf' => 'Use configuration in pdf.xml',
208+
'/config/install' => 'Configurations moved to DI file settings',
209+
'/config/install/design' => 'Configurations moved to DI file settings',
210+
'/config/adminhtml/design' => 'Configurations moved to DI file settings',
211+
'/config/frontend/design' => 'Configurations moved to DI file settings',
212+
'/config/crontab' => 'All cron configurations moved to crontab.xml',
213+
'/config/global/areas' => 'Configurations moved to DI file settings',
214+
'/config/vde' => 'Was moved to di',
215+
'/config/global/ignoredModules' => 'Was replaced using di',
216+
'/config/global/helpers' => 'Was replaced using di',
217+
'/config/global/external_cache' => 'Was replaced using di',
218+
'/config/global/currency/import/services' => 'Configurations moved to DI file settings',
219+
'/config/global/template' => 'Use /config/template of email_templates.xml',
220+
'/config/default/general/file/sitemap_generate_valid_paths' => '/config/default/sitemap/file/valid_paths',
221+
'/config/dev/css/minify_adapter' => 'Was replaced using di',
222+
'/config/dev/js/minify_adapter' => 'Was replaced using di',
223+
'/config/global/full_page_cache' => '/config/global/cache_advanced/full_page',
224+
'/config/adminhtml/enterprise/admingws' => 'This configuration moved to admingws.xml file',
225+
'/config/adminhtml/enterprise/websiterestriction' =>
226+
'This configuration moved to websiterestrictions.xml file',
227+
'/config/global/enterprise_cms' => 'This configuration moved to menu_hierarchy.xml file',
228+
'/config/global/enterprise/banner' =>
229+
'This configuration moved to Di configuration of \Magento\Banner\Model\Config',
230+
'/config/global/enterprise/giftcardaccount' =>
231+
'This configuration moved to Di configuration of \Magento\GiftCardAccountModelPool',
232+
'/config/global/skip_process_modules_updates' => 'Was replaced using di',
233+
'/config/system/page_cache' => 'Module is eliminated. Use PageCache module instead',
234+
'/config/system/cms/content/versioning' => 'Functionality is eliminated',
235+
];
236+
}
237+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento2\Tests\Eslint;
9+
10+
use PHPUnit\Framework\TestCase;
11+
12+
/**
13+
* Abstract class AbstractEslintTestCase
14+
*
15+
* Test Eslint Rules (magento-coding-standard/eslint/rules)
16+
*/
17+
abstract class AbstractEslintTestCase extends TestCase
18+
{
19+
/**
20+
* @param string $testFile
21+
* @param array $expectedMessages
22+
*/
23+
protected function assertFileContainsError(string $testFile, array $expectedMessages): void
24+
{
25+
exec(
26+
'npm run eslint -- Magento2/Tests/Eslint/' . $testFile,
27+
$output
28+
);
29+
30+
foreach ($expectedMessages as $message) {
31+
$this->assertStringContainsString($message, implode(' ',$output));
32+
}
33+
}
34+
}

Magento2/Tests/Eslint/AndSelfTest.js

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
$(document).ready(function() {
2+
'use strict';
3+
$("div").find("p").andSelf().addClass("border");
4+
});

0 commit comments

Comments
 (0)