You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by di...@apache.org on 2025/03/10 18:45:57 UTC
(superset) branch geido/chore/enforce-usage-icons-eslint created (now 8dd732987b)
This is an automated email from the ASF dual-hosted git repository.
diegopucci pushed a change to branch geido/chore/enforce-usage-icons-eslint
in repository https://gitbox.apache.org/repos/asf/superset.git
at 8dd732987b chore(ESLint): Enforce usage of Icons component
This branch includes the following new commits:
new 8dd732987b chore(ESLint): Enforce usage of Icons component
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(superset) 01/01: chore(ESLint): Enforce usage of Icons component
Posted by di...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
diegopucci pushed a commit to branch geido/chore/enforce-usage-icons-eslint
in repository https://gitbox.apache.org/repos/asf/superset.git
commit 8dd732987bf7b9ec1bbdeaff670eea370d544573
Author: Diego Pucci <di...@gmail.com>
AuthorDate: Mon Mar 10 19:45:28 2025 +0100
chore(ESLint): Enforce usage of Icons component
---
superset-frontend/.eslintrc.js | 5 ++
.../eslint-rules/eslint-plugin-icons/index.js | 92 ++++++++++++++++++++++
.../no-direct-ant-icons-import.test.js | 59 ++++++++++++++
.../eslint-plugin-icons/no-fontawesome.test.js | 61 ++++++++++++++
.../eslint-rules/eslint-plugin-icons/package.json | 16 ++++
superset-frontend/package-lock.json | 10 +++
superset-frontend/package.json | 1 +
.../src/components/Icons/AntdEnhanced.tsx | 1 +
superset-frontend/src/components/Icons/Icon.tsx | 1 +
superset-frontend/src/components/Icons/IconType.ts | 1 +
10 files changed, 247 insertions(+)
diff --git a/superset-frontend/.eslintrc.js b/superset-frontend/.eslintrc.js
index 3d5e04cde0..14aa783587 100644
--- a/superset-frontend/.eslintrc.js
+++ b/superset-frontend/.eslintrc.js
@@ -74,6 +74,7 @@ module.exports = {
'file-progress',
'lodash',
'theme-colors',
+ 'icons',
'i18n-strings',
'react-prefer-function-component',
'prettier',
@@ -284,6 +285,8 @@ module.exports = {
],
rules: {
'theme-colors/no-literal-colors': 0,
+ 'icons/no-direct-ant-icons-import': 0,
+ 'icons/no-fa-icons-usage': 0,
'i18n-strings/no-template-vars': 0,
'no-restricted-imports': 0,
'react/no-void-elements': 0,
@@ -292,6 +295,8 @@ module.exports = {
],
rules: {
'theme-colors/no-literal-colors': 'error',
+ 'icons/no-direct-ant-icons-import': 'error',
+ 'icons/no-fa-icons-usage': 'error',
'i18n-strings/no-template-vars': ['error', true],
camelcase: [
'error',
diff --git a/superset-frontend/eslint-rules/eslint-plugin-icons/index.js b/superset-frontend/eslint-rules/eslint-plugin-icons/index.js
new file mode 100644
index 0000000000..f25a20aff4
--- /dev/null
+++ b/superset-frontend/eslint-rules/eslint-plugin-icons/index.js
@@ -0,0 +1,92 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * @fileoverview Rule to warn about direct imports from @ant-design/icons
+ * @author Apache
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+/** @type {import('eslint').Rule.RuleModule} */
+module.exports = {
+ rules: {
+ 'no-direct-ant-icons-import': {
+ meta: {
+ type: 'problem',
+ docs: {
+ description:
+ 'Warn when importing icons directly from @ant-design/icons',
+ category: 'Best Practices',
+ },
+ schema: [],
+ },
+ create(context) {
+ return {
+ ImportDeclaration(node) {
+ if (node.source.value.startsWith('@ant-design/icons')) {
+ context.report({
+ node,
+ message:
+ "Avoid importing icons directly from '@ant-design/icons'. Use the src/components/Icons component instead.",
+ });
+ }
+ },
+ };
+ },
+ },
+ 'no-fa-icons-usage': {
+ meta: {
+ type: 'problem',
+ docs: {
+ description:
+ 'Disallow the usage of FontAwesome icons in the codebase',
+ category: 'Best Practices',
+ },
+ schema: [],
+ },
+ create(context) {
+ return {
+ // Check for JSX elements with class names containing "fa"
+ JSXElement(node) {
+ if (
+ node.openingElement &&
+ node.openingElement.name.name === 'i' &&
+ node.openingElement.attributes &&
+ node.openingElement.attributes.some(
+ attr =>
+ attr.name &&
+ attr.name.name === 'className' &&
+ /fa fa-/.test(attr.value.value),
+ )
+ ) {
+ context.report({
+ node,
+ message:
+ 'FontAwesome icons should not be used. Use the src/components/Icons component instead.',
+ });
+ }
+ },
+ };
+ },
+ },
+ },
+};
diff --git a/superset-frontend/eslint-rules/eslint-plugin-icons/no-direct-ant-icons-import.test.js b/superset-frontend/eslint-rules/eslint-plugin-icons/no-direct-ant-icons-import.test.js
new file mode 100644
index 0000000000..ac88dd2bf2
--- /dev/null
+++ b/superset-frontend/eslint-rules/eslint-plugin-icons/no-direct-ant-icons-import.test.js
@@ -0,0 +1,59 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * @fileoverview Test file for the no-direct-ant-icons-import rule
+ * @author Apache
+ */
+
+const { RuleTester } = require('eslint');
+const plugin = require('.');
+
+//------------------------------------------------------------------------------
+// Tests
+//------------------------------------------------------------------------------
+
+const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
+const rule = plugin.rules['no-direct-ant-icons-import'];
+
+const errors = [
+ { message: "Avoid importing icons directly from '@ant-design/icons'." },
+];
+
+ruleTester.run('no-direct-ant-icons-import', rule, {
+ valid: ["import { BarChartOutlined } from 'src/components/icons';"],
+ invalid: [
+ {
+ code: "import { BarChartOutlined } from '@ant-design/icons';",
+ errors,
+ },
+ {
+ code: "import { LineChartOutlined, PieChartOutlined } from '@ant-design/icons';",
+ errors,
+ },
+ {
+ code: "import * as AntIcons from '@ant-design/icons';",
+ errors,
+ },
+ {
+ code: "import * as Icons from '@ant-design/icons/lib';",
+ errors,
+ },
+ ],
+});
diff --git a/superset-frontend/eslint-rules/eslint-plugin-icons/no-fontawesome.test.js b/superset-frontend/eslint-rules/eslint-plugin-icons/no-fontawesome.test.js
new file mode 100644
index 0000000000..61ec372ad3
--- /dev/null
+++ b/superset-frontend/eslint-rules/eslint-plugin-icons/no-fontawesome.test.js
@@ -0,0 +1,61 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * @fileoverview Test file for the no-direct-ant-icons-import rule
+ * @author Apache
+ */
+
+const { RuleTester } = require('eslint');
+const plugin = require('.');
+
+//------------------------------------------------------------------------------
+// Tests
+//------------------------------------------------------------------------------
+const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
+const rule = plugin.rules['no-fa-icons-usage'];
+
+const errors = [
+ {
+ message:
+ 'FontAwesome icons should not be used. Use the src/components/Icons component instead.',
+ },
+];
+
+ruleTester.run('no-fa-icons-usage', rule, {
+ valid: ['<Icons.Database />', '<Icons.Search />'],
+ invalid: [
+ {
+ code: '<i className="fa fa-database"></i>',
+ errors,
+ },
+ {
+ code: '<i className="fa fa-search"></i>',
+ errors,
+ },
+ {
+ code: '<i className="fa fa-home"></i>',
+ errors,
+ },
+ {
+ code: '<i className="fa fa-arrow-right"></i>',
+ errors,
+ },
+ ],
+});
diff --git a/superset-frontend/eslint-rules/eslint-plugin-icons/package.json b/superset-frontend/eslint-rules/eslint-plugin-icons/package.json
new file mode 100644
index 0000000000..f2118e936c
--- /dev/null
+++ b/superset-frontend/eslint-rules/eslint-plugin-icons/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "eslint-plugin-icons",
+ "version": "1.0.0",
+ "description": "Warns about direct usage of Ant Design icons",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "keywords": [],
+ "license": "Apache-2.0",
+ "author": "Apache",
+ "dependencies": {},
+ "peerDependencies": {
+ "eslint": ">=0.8.0"
+ }
+}
diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json
index b98a96fc36..6379ca795a 100644
--- a/superset-frontend/package-lock.json
+++ b/superset-frontend/package-lock.json
@@ -243,6 +243,7 @@
"eslint-import-resolver-typescript": "^3.7.0",
"eslint-plugin-cypress": "^3.6.0",
"eslint-plugin-file-progress": "^1.5.0",
+ "eslint-plugin-icons": "file:eslint-rules/eslint-plugin-icons",
"eslint-plugin-import": "^2.24.2",
"eslint-plugin-jest": "^27.8.0",
"eslint-plugin-jest-dom": "^5.5.0",
@@ -317,6 +318,11 @@
"eslint": ">=0.8.0"
}
},
+ "eslint-rules/eslint-plugin-icons": {
+ "version": "1.0.0",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
"eslint-rules/eslint-plugin-theme-colors": {
"version": "1.0.0",
"dev": true,
@@ -21906,6 +21912,10 @@
"resolved": "eslint-rules/eslint-plugin-i18n-strings",
"link": true
},
+ "node_modules/eslint-plugin-icons": {
+ "resolved": "eslint-rules/eslint-plugin-icons",
+ "link": true
+ },
"node_modules/eslint-plugin-import": {
"version": "2.31.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz",
diff --git a/superset-frontend/package.json b/superset-frontend/package.json
index 7e0bb92d9b..7f207f1972 100644
--- a/superset-frontend/package.json
+++ b/superset-frontend/package.json
@@ -310,6 +310,7 @@
"eslint-import-resolver-typescript": "^3.7.0",
"eslint-plugin-cypress": "^3.6.0",
"eslint-plugin-file-progress": "^1.5.0",
+ "eslint-plugin-icons": "file:eslint-rules/eslint-plugin-icons",
"eslint-plugin-import": "^2.24.2",
"eslint-plugin-jest": "^27.8.0",
"eslint-plugin-jest-dom": "^5.5.0",
diff --git a/superset-frontend/src/components/Icons/AntdEnhanced.tsx b/superset-frontend/src/components/Icons/AntdEnhanced.tsx
index 423e2b39ee..6715dd6e44 100644
--- a/superset-frontend/src/components/Icons/AntdEnhanced.tsx
+++ b/superset-frontend/src/components/Icons/AntdEnhanced.tsx
@@ -18,6 +18,7 @@
*/
// NOTE: Targeted import (as opposed to `import *`) is important here for proper tree-shaking
+// eslint-disable-next-line icons/no-direct-ant-icons-import
import {
AlignCenterOutlined,
AlignLeftOutlined,
diff --git a/superset-frontend/src/components/Icons/Icon.tsx b/superset-frontend/src/components/Icons/Icon.tsx
index 39e5627235..46e76b8742 100644
--- a/superset-frontend/src/components/Icons/Icon.tsx
+++ b/superset-frontend/src/components/Icons/Icon.tsx
@@ -18,6 +18,7 @@
*/
import { FC, SVGProps, useEffect, useRef, useState } from 'react';
+// eslint-disable-next-line icons/no-direct-ant-icons-import
import AntdIcon from '@ant-design/icons';
import { styled } from '@superset-ui/core';
import TransparentIcon from 'src/assets/images/icons/transparent.svg';
diff --git a/superset-frontend/src/components/Icons/IconType.ts b/superset-frontend/src/components/Icons/IconType.ts
index 41a4089e12..ecc22c34ad 100644
--- a/superset-frontend/src/components/Icons/IconType.ts
+++ b/superset-frontend/src/components/Icons/IconType.ts
@@ -16,6 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
+// eslint-disable-next-line icons/no-direct-ant-icons-import
import { IconComponentProps } from '@ant-design/icons/lib/components/Icon';
type AntdIconType = IconComponentProps;