| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503 |
- /**
- * 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.
- */
- const packageConfig = require('./package.json');
- const importCoreModules = [];
- Object.entries(packageConfig.dependencies).forEach(([pkg]) => {
- if (/@superset-ui/.test(pkg)) {
- importCoreModules.push(pkg);
- }
- });
- // ignore files in production mode
- let ignorePatterns = [];
- if (process.env.NODE_ENV === 'production') {
- ignorePatterns = [
- '*.test.{js,ts,jsx,tsx}',
- 'plugins/**/test/**/*',
- 'packages/**/test/**/*',
- 'packages/generator-superset/**/*',
- ];
- }
- const restrictedImportsRules = {
- 'no-design-icons': {
- name: '@ant-design/icons',
- message:
- 'Avoid importing icons directly from @ant-design/icons. Use the src/components/Icons component instead.',
- },
- 'no-moment': {
- name: 'moment',
- message:
- 'Please use the dayjs library instead of moment.js. See https://day.js.org',
- },
- 'no-lodash-memoize': {
- name: 'lodash/memoize',
- message: 'Lodash Memoize is unsafe! Please use memoize-one instead',
- },
- 'no-testing-library-react': {
- name: '@superset-ui/core/spec',
- message: 'Please use spec/helpers/testing-library instead',
- },
- 'no-testing-library-react-dom-utils': {
- name: '@testing-library/react-dom-utils',
- message: 'Please use spec/helpers/testing-library instead',
- },
- 'no-antd': {
- name: 'antd',
- message: 'Please import Ant components from the index of src/components',
- },
- 'no-superset-theme': {
- name: '@superset-ui/core',
- importNames: ['supersetTheme'],
- message:
- 'Please use the theme directly from the ThemeProvider rather than importing supersetTheme.',
- },
- 'no-query-string': {
- name: 'query-string',
- message: 'Please use the URLSearchParams API instead of query-string.',
- },
- };
- module.exports = {
- extends: [
- 'eslint:recommended',
- 'plugin:import/recommended',
- 'plugin:react/recommended',
- 'plugin:jsx-a11y/recommended',
- 'plugin:react-hooks/recommended',
- 'plugin:react-prefer-function-component/recommended',
- 'plugin:storybook/recommended',
- 'prettier',
- ],
- parser: '@babel/eslint-parser',
- parserOptions: {
- ecmaVersion: 2020,
- sourceType: 'module',
- ecmaFeatures: {
- jsx: true,
- },
- requireConfigFile: false,
- babelOptions: {
- presets: ['@babel/preset-react', '@babel/preset-env'],
- },
- },
- env: {
- browser: true,
- node: true,
- es2020: true,
- },
- settings: {
- 'import/resolver': {
- node: {
- extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
- moduleDirectory: ['node_modules', '.'],
- },
- typescript: {
- alwaysTryTypes: true,
- project: [
- './tsconfig.json',
- './packages/superset-ui-core/tsconfig.json',
- './packages/superset-ui-chart-controls/',
- './plugins/*/tsconfig.json',
- ],
- },
- },
- 'import/core-modules': importCoreModules,
- react: {
- version: 'detect',
- },
- },
- plugins: [
- 'import',
- 'react',
- 'jsx-a11y',
- 'react-hooks',
- 'file-progress',
- 'lodash',
- 'theme-colors',
- 'icons',
- 'i18n-strings',
- 'react-prefer-function-component',
- 'prettier',
- ],
- rules: {
- // === Essential Superset customizations ===
- // Prettier integration
- 'prettier/prettier': 'error',
- // Custom Superset rules
- 'theme-colors/no-literal-colors': 'error',
- 'icons/no-fa-icons-usage': 'error',
- 'i18n-strings/no-template-vars': ['error', true],
- // Core ESLint overrides for Superset
- 'no-console': 'warn',
- 'no-unused-vars': 'off', // TypeScript handles this
- camelcase: [
- 'error',
- {
- allow: ['^UNSAFE_', '__REDUX_DEVTOOLS_EXTENSION_COMPOSE__'],
- properties: 'never',
- },
- ],
- 'prefer-destructuring': ['error', { object: true, array: false }],
- 'no-prototype-builtins': 0,
- curly: 'off',
- // Import plugin overrides
- 'import/extensions': [
- 'error',
- 'ignorePackages',
- {
- js: 'never',
- jsx: 'never',
- ts: 'never',
- tsx: 'never',
- },
- ],
- 'import/no-cycle': 0,
- 'import/prefer-default-export': 0,
- 'import/no-named-as-default-member': 0,
- 'import/no-extraneous-dependencies': [
- 'error',
- {
- devDependencies: [
- 'test/**',
- 'tests/**',
- 'spec/**',
- '**/__tests__/**',
- '**/__mocks__/**',
- '*.test.{js,jsx,ts,tsx}',
- '*.spec.{js,jsx,ts,tsx}',
- '**/*.test.{js,jsx,ts,tsx}',
- '**/*.spec.{js,jsx,ts,tsx}',
- '**/jest.config.js',
- '**/jest.setup.js',
- '**/webpack.config.js',
- '**/webpack.config.*.js',
- '**/.eslintrc.js',
- ],
- optionalDependencies: false,
- },
- ],
- // React plugin overrides
- 'react/prop-types': 0,
- 'react/require-default-props': 0,
- 'react/forbid-prop-types': 0,
- 'react/forbid-component-props': 1,
- 'react/jsx-filename-extension': [1, { extensions: ['.jsx', '.tsx'] }],
- 'react/jsx-fragments': 1,
- 'react/jsx-no-bind': 0,
- 'react/jsx-props-no-spreading': 0,
- 'react/no-array-index-key': 0,
- 'react/no-string-refs': 0,
- 'react/no-unescaped-entities': 0,
- 'react/no-unused-prop-types': 0,
- 'react/destructuring-assignment': 0,
- 'react/sort-comp': 0,
- 'react/static-property-placement': 0,
- 'react-prefer-function-component/react-prefer-function-component': 1,
- 'react/react-in-jsx-scope': 0,
- 'react/no-unknown-property': 0,
- 'react/no-void-elements': 0,
- 'react/function-component-definition': [
- 0,
- {
- namedComponents: 'arrow-function',
- },
- ],
- 'react/no-unstable-nested-components': 0,
- 'react/jsx-no-useless-fragment': 0,
- 'react/no-unused-class-component-methods': 0,
- // JSX-a11y overrides
- 'jsx-a11y/anchor-is-valid': 1,
- 'jsx-a11y/click-events-have-key-events': 0,
- 'jsx-a11y/mouse-events-have-key-events': 0,
- 'jsx-a11y/no-static-element-interactions': 0,
- // Lodash
- 'lodash/import-scope': [2, 'member'],
- // File progress
- 'file-progress/activate': 1,
- // Restricted imports
- 'no-restricted-imports': [
- 'error',
- {
- paths: Object.values(restrictedImportsRules).filter(Boolean),
- patterns: ['antd/*'],
- },
- ],
- // Temporarily disabled for migration
- 'no-unsafe-optional-chaining': 0,
- 'no-import-assign': 0,
- 'import/no-relative-packages': 0,
- 'no-promise-executor-return': 0,
- 'import/no-import-module-exports': 0,
- // Restrict certain syntax patterns
- 'no-restricted-syntax': [
- 'error',
- {
- selector:
- "ImportDeclaration[source.value='react'] :matches(ImportDefaultSpecifier, ImportNamespaceSpecifier)",
- message:
- 'Default React import is not required due to automatic JSX runtime in React 16.4',
- },
- {
- selector: 'ImportNamespaceSpecifier[parent.source.value!=/^(\\.|src)/]',
- message: 'Wildcard imports are not allowed',
- },
- ],
- },
- overrides: [
- {
- files: ['*.ts', '*.tsx'],
- parser: '@typescript-eslint/parser',
- parserOptions: {
- ecmaFeatures: {
- jsx: true,
- },
- tsconfigRootDir: __dirname,
- project: ['./tsconfig.json'],
- },
- extends: ['plugin:@typescript-eslint/recommended', 'prettier'],
- plugins: ['@typescript-eslint/eslint-plugin'],
- rules: {
- // TypeScript-specific rule overrides
- '@typescript-eslint/ban-ts-ignore': 0,
- '@typescript-eslint/ban-ts-comment': 0,
- '@typescript-eslint/ban-types': 0,
- '@typescript-eslint/naming-convention': [
- 'error',
- {
- selector: 'enum',
- format: ['PascalCase'],
- },
- {
- selector: 'enumMember',
- format: ['PascalCase'],
- },
- ],
- '@typescript-eslint/no-empty-function': 0,
- '@typescript-eslint/no-explicit-any': 0,
- '@typescript-eslint/no-use-before-define': 1,
- '@typescript-eslint/no-non-null-assertion': 0,
- '@typescript-eslint/explicit-function-return-type': 0,
- '@typescript-eslint/explicit-module-boundary-types': 0,
- '@typescript-eslint/no-unused-vars': 'warn',
- '@typescript-eslint/prefer-optional-chain': 'error',
- // Disable base rules that conflict with TS versions
- 'no-unused-vars': 'off',
- 'no-use-before-define': 'off',
- 'no-shadow': 'off',
- // Import overrides for TypeScript
- 'import/extensions': [
- 'error',
- 'ignorePackages',
- {
- js: 'never',
- jsx: 'never',
- ts: 'never',
- tsx: 'never',
- },
- ],
- },
- settings: {
- 'import/resolver': {
- typescript: {},
- },
- },
- },
- {
- files: ['packages/**'],
- rules: {
- 'import/no-extraneous-dependencies': [
- 'error',
- { devDependencies: true },
- ],
- 'no-restricted-imports': [
- 'error',
- {
- paths: [
- restrictedImportsRules['no-moment'],
- restrictedImportsRules['no-lodash-memoize'],
- restrictedImportsRules['no-superset-theme'],
- ],
- patterns: [],
- },
- ],
- },
- },
- {
- files: ['plugins/**'],
- rules: {
- 'no-restricted-imports': [
- 'error',
- {
- paths: [
- restrictedImportsRules['no-moment'],
- restrictedImportsRules['no-lodash-memoize'],
- ],
- patterns: [],
- },
- ],
- },
- },
- {
- files: ['src/components/**', 'src/theme/**'],
- rules: {
- 'no-restricted-imports': [
- 'error',
- {
- paths: Object.values(restrictedImportsRules).filter(
- r => r.name !== 'antd',
- ),
- patterns: [],
- },
- ],
- },
- },
- {
- files: [
- '*.test.ts',
- '*.test.tsx',
- '*.test.js',
- '*.test.jsx',
- '*.stories.tsx',
- '*.stories.jsx',
- 'fixtures.*',
- '**/test/**/*',
- '**/tests/**/*',
- 'spec/**/*',
- '**/fixtures/**/*',
- '**/__mocks__/**/*',
- '**/spec/**/*',
- ],
- excludedFiles: 'cypress-base/cypress/**/*',
- plugins: ['jest', 'jest-dom', 'no-only-tests', 'testing-library'],
- env: {
- 'jest/globals': true,
- },
- settings: {
- jest: {
- version: 'detect',
- },
- },
- extends: [
- 'plugin:jest/recommended',
- 'plugin:jest-dom/recommended',
- 'plugin:testing-library/react',
- ],
- rules: {
- 'import/no-extraneous-dependencies': [
- 'error',
- { devDependencies: true },
- ],
- 'jest/consistent-test-it': 'error',
- 'no-only-tests/no-only-tests': 'error',
- 'prefer-promise-reject-errors': 0,
- 'max-classes-per-file': 0,
- // Temporary for migration
- 'testing-library/await-async-queries': 0,
- 'testing-library/await-async-utils': 0,
- 'testing-library/no-await-sync-events': 0,
- 'testing-library/no-render-in-lifecycle': 0,
- 'testing-library/no-unnecessary-act': 0,
- 'testing-library/no-wait-for-multiple-assertions': 0,
- 'testing-library/prefer-screen-queries': 0,
- 'testing-library/await-async-events': 0,
- 'testing-library/no-node-access': 0,
- 'testing-library/no-wait-for-side-effects': 0,
- 'testing-library/prefer-presence-queries': 0,
- 'testing-library/render-result-naming-convention': 0,
- 'testing-library/no-container': 0,
- 'testing-library/prefer-find-by': 0,
- 'testing-library/no-manual-cleanup': 0,
- 'no-restricted-syntax': [
- 'error',
- {
- selector:
- "ImportDeclaration[source.value='react'] :matches(ImportDefaultSpecifier, ImportNamespaceSpecifier)",
- message:
- 'Default React import is not required due to automatic JSX runtime in React 16.4',
- },
- ],
- 'no-restricted-imports': 0,
- },
- },
- {
- files: [
- '*.test.ts',
- '*.test.tsx',
- '*.test.js',
- '*.test.jsx',
- '*.stories.tsx',
- '*.stories.jsx',
- 'fixtures.*',
- '**/test/**/*',
- '**/tests/**/*',
- 'spec/**/*',
- '**/fixtures/**/*',
- '**/__mocks__/**/*',
- '**/spec/**/*',
- 'cypress-base/cypress/**/*',
- 'Stories.tsx',
- 'packages/superset-ui-core/src/theme/index.tsx',
- ],
- rules: {
- 'theme-colors/no-literal-colors': 0,
- 'icons/no-fa-icons-usage': 0,
- 'i18n-strings/no-template-vars': 0,
- 'no-restricted-imports': 0,
- 'react/no-void-elements': 0,
- },
- },
- {
- files: [
- 'packages/**/*.stories.*',
- 'packages/**/*.overview.*',
- 'packages/**/fixtures.*',
- ],
- rules: {
- 'import/no-extraneous-dependencies': 'off',
- },
- },
- {
- files: ['playwright/**/*.ts', 'playwright/**/*.js'],
- rules: {
- 'import/no-extraneous-dependencies': [
- 'error',
- { devDependencies: true },
- ],
- },
- },
- ],
- ignorePatterns,
- };
|