mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Frontend: Update to Eslint 9 (#94823)
* chore(eslint): bump all eslint related packages to latest * chore(eslint): update linting scripts work with v9 * chore(eslint): introduce flat config * chore(eslint): delete legacy configs * feat(grafana-eslint-rules): update rules to use eslint 9 APIs * chore(eslint): migrate all nested eslintrc files over to root config * chore(packages): bump eslint dependencies * feat(betterer): make it work with eslint 9 * style(grafana-data): remove non-existant ban-types rule from disable declarations * chore(wip): [wip] link eslint-config-grafana * chore(packages): add @eslint/compat * chore(eslint): add compat to testing library and fix alerting rules * chore(eslint): bump grafana eslint-config to v8 * chore(explore): delete legacy eslint config * chore: clean codeowners file, remove grafana/eslint-config from e2e plugins * test(eslint-rules): fix no-border-radius-literal and no-aria-label-e2e-selectors rule tests * Add .js to prettier checks so new eslint.config.js file isn't missed * chore(eslint): move emotion/syntax-preference to grafana/defaults * test(eslint): use core-js structured-clone * revert(services): undo merge backend-format githook changes * test(eslint-rules): remove structured-clone polyfill from tests * chore(eslint): add back public/lib/monaco to ignore list, sort alphabetically * chore(e2e-plugins): remove eslint config 7 from plugins package.json --------- Co-authored-by: Tom Ratcliffe <tom.ratcliffe@grafana.com>
This commit is contained in:
parent
8956400498
commit
8c41137bcf
88
.betterer.ts
88
.betterer.ts
@ -1,8 +1,6 @@
|
||||
import { BettererFileTest } from '@betterer/betterer';
|
||||
import { promises as fs } from 'fs';
|
||||
import { ESLint, Linter } from 'eslint';
|
||||
import path from 'path';
|
||||
import { glob } from 'glob';
|
||||
import { promises as fs } from 'fs';
|
||||
|
||||
// Why are we ignoring these?
|
||||
// They're all deprecated/being removed so doesn't make sense to fix types
|
||||
@ -82,11 +80,6 @@ function countEslintErrors() {
|
||||
}
|
||||
|
||||
const { baseDirectory } = resolver;
|
||||
const cli = new ESLint({ cwd: baseDirectory });
|
||||
|
||||
// Get the base config to set up parsing etc correctly
|
||||
// this is by far the slowest part of this code. It takes eslint about 2 seconds just to find the config
|
||||
const baseConfig = await cli.calculateConfigForFile(filePaths[0]);
|
||||
|
||||
const baseRules: Partial<Linter.RulesRecord> = {
|
||||
'@typescript-eslint/no-explicit-any': 'error',
|
||||
@ -105,57 +98,52 @@ function countEslintErrors() {
|
||||
],
|
||||
};
|
||||
|
||||
const config: Linter.Config = {
|
||||
...baseConfig,
|
||||
rules: baseRules,
|
||||
|
||||
// Be careful when specifying overrides for the same rules as in baseRules - it will... override
|
||||
// the same rule, not merge them with different configurations
|
||||
overrides: [
|
||||
{
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
excludedFiles: ['*.{test,spec}.{ts,tsx}', '**/__mocks__/**', '**/public/test/**'],
|
||||
rules: {
|
||||
'@typescript-eslint/consistent-type-assertions': ['error', { assertionStyle: 'never' }],
|
||||
},
|
||||
const config: Linter.Config[] = [
|
||||
{
|
||||
files: ['**/*.{js,jsx,ts,tsx}'],
|
||||
rules: baseRules,
|
||||
},
|
||||
{
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
ignores: ['**/*.{test,spec}.{ts,tsx}', '**/__mocks__/**', '**/public/test/**'],
|
||||
rules: {
|
||||
'@typescript-eslint/consistent-type-assertions': ['error', { assertionStyle: 'never' }],
|
||||
},
|
||||
|
||||
{
|
||||
files: ['public/app/**/*.{ts,tsx}'],
|
||||
rules: {
|
||||
'no-barrel-files/no-barrel-files': 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['public/app/**/*.{ts,tsx}'],
|
||||
rules: {
|
||||
'no-barrel-files/no-barrel-files': 'error',
|
||||
},
|
||||
{
|
||||
files: ['public/**/*.tsx', 'packages/grafana-ui/**/*.tsx'],
|
||||
excludedFiles: [
|
||||
'public/app/plugins/**',
|
||||
'*.story.tsx',
|
||||
'*.{test,spec}.{ts,tsx}',
|
||||
'**/__mocks__/**',
|
||||
'public/test/**',
|
||||
],
|
||||
rules: {
|
||||
'@grafana/no-untranslated-strings': 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['public/**/*.tsx', 'packages/grafana-ui/**/*.tsx'],
|
||||
ignores: [
|
||||
'public/app/plugins/**',
|
||||
'**/*.story.tsx',
|
||||
'**/*.{test,spec}.{ts,tsx}',
|
||||
'**/__mocks__/',
|
||||
'public/test',
|
||||
],
|
||||
rules: {
|
||||
'@grafana/no-untranslated-strings': 'error',
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
];
|
||||
|
||||
const runner = new ESLint({
|
||||
baseConfig: config,
|
||||
useEslintrc: false,
|
||||
overrideConfig: config,
|
||||
cwd: baseDirectory,
|
||||
warnIgnored: false,
|
||||
});
|
||||
|
||||
const lintResults = await runner.lintFiles(Array.from(filePaths));
|
||||
lintResults
|
||||
.filter((lintResult) => lintResult.source)
|
||||
.forEach(({ messages, filePath }) => {
|
||||
const file = fileTestResult.addFile(filePath, '');
|
||||
messages.forEach((message, index) => {
|
||||
file.addIssue(0, 0, message.message, `${index}`);
|
||||
});
|
||||
|
||||
lintResults.forEach(({ messages, filePath }) => {
|
||||
const file = fileTestResult.addFile(filePath, '');
|
||||
messages.forEach((message, index) => {
|
||||
file.addIssue(0, 0, message.message, `${index}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -1,27 +0,0 @@
|
||||
.git
|
||||
.github
|
||||
.yarn
|
||||
build
|
||||
compiled
|
||||
/data
|
||||
deployment_tools_config.json
|
||||
/devenv
|
||||
dist
|
||||
/e2e/tmp
|
||||
node_modules
|
||||
/pkg
|
||||
/public/lib/monaco
|
||||
/scripts/grafana-server/tmp
|
||||
vendor
|
||||
e2e/test-plugins
|
||||
playwright-report
|
||||
|
||||
# TS generate from cue by cuetsy
|
||||
**/*.gen.ts
|
||||
|
||||
# Auto-generated internationalization files
|
||||
/public/locales/_build/
|
||||
/public/locales/**/*.js
|
||||
|
||||
# Auto-generated icon file
|
||||
/packages/grafana-ui/src/components/Icon/iconBundle.ts
|
171
.eslintrc
171
.eslintrc
@ -1,171 +0,0 @@
|
||||
{
|
||||
"extends": ["@grafana/eslint-config", "plugin:react/jsx-runtime"],
|
||||
"root": true,
|
||||
"plugins": [
|
||||
"@emotion",
|
||||
"lodash",
|
||||
"jest",
|
||||
"import",
|
||||
"jsx-a11y",
|
||||
"@grafana",
|
||||
"no-barrel-files",
|
||||
// Included so betterer doesn't fail when processing all files,
|
||||
// as other parts of the code use testing-library plugin
|
||||
"testing-library",
|
||||
],
|
||||
"settings": {
|
||||
"import/internal-regex": "^(app/)|(@grafana)",
|
||||
"import/external-module-folders": ["node_modules", ".yarn"],
|
||||
},
|
||||
"rules": {
|
||||
"@emotion/syntax-preference": [2, "object"],
|
||||
"@grafana/no-border-radius-literal": "error",
|
||||
"@grafana/no-unreduced-motion": "error",
|
||||
"react/prop-types": "off",
|
||||
// need to ignore emotion's `css` prop, see https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-unknown-property.md#rule-options
|
||||
"react/no-unknown-property": ["error", { "ignore": ["css"] }],
|
||||
"@emotion/jsx-import": "error",
|
||||
"lodash/import-scope": [2, "member"],
|
||||
"jest/no-focused-tests": "error",
|
||||
"import/order": [
|
||||
"error",
|
||||
{
|
||||
"groups": [["builtin", "external"], "internal", "parent", "sibling", "index"],
|
||||
"newlines-between": "always",
|
||||
"alphabetize": { "order": "asc" },
|
||||
},
|
||||
],
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"paths": [
|
||||
{
|
||||
"name": "react-redux",
|
||||
"importNames": ["useDispatch", "useSelector"],
|
||||
"message": "Please import from app/types instead.",
|
||||
},
|
||||
{
|
||||
"name": "react-i18next",
|
||||
"importNames": ["Trans", "t"],
|
||||
"message": "Please import from app/core/internationalization instead",
|
||||
},
|
||||
{
|
||||
"name": "react-router-dom",
|
||||
"message": "Please import from react-router-dom-v5-compat instead"
|
||||
},
|
||||
{
|
||||
"name": "react-router",
|
||||
"message": "Please import from react-router-dom-v5-compat instead"
|
||||
}
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
// Use typescript's no-redeclare for compatibility with overrides
|
||||
"no-redeclare": "off",
|
||||
"@typescript-eslint/no-redeclare": ["error"],
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["packages/grafana-ui/src/components/uPlot/**/*.{ts,tsx}"],
|
||||
"rules": {
|
||||
"react-hooks/rules-of-hooks": "off",
|
||||
"react-hooks/exhaustive-deps": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
"files": ["packages/grafana-ui/src/components/ThemeDemos/**/*.{ts,tsx}"],
|
||||
"rules": {
|
||||
"@emotion/jsx-import": "off",
|
||||
"react/jsx-uses-react": "off",
|
||||
"react/react-in-jsx-scope": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
"files": ["public/dashboards/scripted*.js"],
|
||||
"rules": {
|
||||
"no-redeclare": "error",
|
||||
"@typescript-eslint/no-redeclare": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
"extends": ["plugin:jsx-a11y/recommended"],
|
||||
"files": ["**/*.tsx"],
|
||||
"excludedFiles": ["**/*.{spec,test}.tsx"],
|
||||
"rules": {
|
||||
// rules marked "off" are those left in the recommended preset we need to fix
|
||||
// we should remove the corresponding line and fix them one by one
|
||||
// any marked "error" contain specific overrides we'll need to keep
|
||||
"jsx-a11y/no-autofocus": [
|
||||
"error",
|
||||
{
|
||||
"ignoreNonDOM": true,
|
||||
},
|
||||
],
|
||||
"jsx-a11y/label-has-associated-control": [
|
||||
"error",
|
||||
{
|
||||
"controlComponents": ["NumberInput"],
|
||||
"depth": 2,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"public/app/plugins/datasource/azuremonitor/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/azuremonitor/**/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/cloud-monitoring/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/cloud-monitoring/**/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/elasticsearch/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/elasticsearch/**/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/grafana-postgresql-datasource/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/grafana-postgresql-datasource/**/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/grafana-pyroscope-datasource/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/grafana-pyroscope-datasource/**/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/grafana-testdata-datasource/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/grafana-testdata-datasource/**/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/jaeger/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/jaeger/**/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/loki/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/loki/**/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/mysql/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/mysql/**/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/parca/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/parca/**/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/tempo/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/tempo/**/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/loki/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/loki/**/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/elasticsearch/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/elasticsearch/**/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/cloudwatch/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/cloudwatch/**/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/zipkin/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/zipkin/**/*.{ts,tsx}",
|
||||
],
|
||||
"settings": {
|
||||
"import/resolver": {
|
||||
"node": {
|
||||
"extensions": [".ts", ".tsx"],
|
||||
},
|
||||
},
|
||||
},
|
||||
"rules": {
|
||||
"import/no-restricted-paths": [
|
||||
"error",
|
||||
{
|
||||
"zones": [
|
||||
{
|
||||
"target": "./public/app/plugins",
|
||||
"from": "./public",
|
||||
"except": ["./app/plugins"],
|
||||
"message": "Core plugins are not allowed to depend on Grafana core packages",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
3
.github/CODEOWNERS
vendored
3
.github/CODEOWNERS
vendored
@ -382,7 +382,7 @@
|
||||
/.nxignore @grafana/frontend-ops
|
||||
/tsconfig.json @grafana/frontend-ops
|
||||
/.editorconfig @grafana/frontend-ops
|
||||
/.eslintignore @grafana/frontend-ops
|
||||
/eslint.config.js @grafana/frontend-ops
|
||||
/.gitattributes @grafana/frontend-ops
|
||||
/.gitignore @grafana/frontend-ops
|
||||
/.nvmrc @grafana/frontend-ops
|
||||
@ -392,7 +392,6 @@
|
||||
/yarn.lock @grafana/frontend-ops
|
||||
/lerna.json @grafana/frontend-ops
|
||||
/.prettierrc.js @grafana/frontend-ops
|
||||
/.eslintrc @grafana/frontend-ops
|
||||
/.vim @zoltanbedi
|
||||
/jest.config.js @grafana/frontend-ops
|
||||
/latest.json @grafana/frontend-ops
|
||||
|
@ -11,7 +11,6 @@
|
||||
"author": "Grafana Labs",
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@grafana/eslint-config": "7.0.0",
|
||||
"@grafana/plugin-configs": "11.4.0-pre",
|
||||
"@types/lodash": "4.17.7",
|
||||
"@types/node": "20.14.14",
|
||||
|
@ -11,7 +11,6 @@
|
||||
"author": "Grafana",
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@grafana/eslint-config": "7.0.0",
|
||||
"@grafana/plugin-configs": "11.4.0-pre",
|
||||
"@types/lodash": "4.17.7",
|
||||
"@types/node": "20.14.14",
|
||||
|
312
eslint.config.js
Normal file
312
eslint.config.js
Normal file
@ -0,0 +1,312 @@
|
||||
// @ts-check
|
||||
const emotionPlugin = require('@emotion/eslint-plugin');
|
||||
const { fixupPluginRules } = require('@eslint/compat');
|
||||
const importPlugin = require('eslint-plugin-import');
|
||||
const jestPlugin = require('eslint-plugin-jest');
|
||||
const jestDomPlugin = require('eslint-plugin-jest-dom');
|
||||
const jsxA11yPlugin = require('eslint-plugin-jsx-a11y');
|
||||
const lodashPlugin = require('eslint-plugin-lodash');
|
||||
const barrelPlugin = require('eslint-plugin-no-barrel-files');
|
||||
const reactPlugin = require('eslint-plugin-react');
|
||||
const testingLibraryPlugin = require('eslint-plugin-testing-library');
|
||||
|
||||
const grafanaConfig = require('@grafana/eslint-config/flat');
|
||||
const grafanaPlugin = require('@grafana/eslint-plugin');
|
||||
|
||||
/**
|
||||
* @type {Array<import('eslint').Linter.Config>}
|
||||
*/
|
||||
module.exports = [
|
||||
{
|
||||
name: 'grafana/ignores',
|
||||
ignores: [
|
||||
'.github',
|
||||
'.yarn',
|
||||
'**/.*', // dotfiles aren't ignored by default in FlatConfig
|
||||
'**/*.gen.ts',
|
||||
'**/build/',
|
||||
'**/compiled/',
|
||||
'**/dist/',
|
||||
'data/',
|
||||
'deployment_tools_config.json',
|
||||
'devenv',
|
||||
'e2e/test-plugins',
|
||||
'e2e/tmp',
|
||||
'packages/grafana-ui/src/components/Icon/iconBundle.ts',
|
||||
'pkg',
|
||||
'playwright-report',
|
||||
'public/lib/monaco/', // this path is no longer required but local dev environments may still have it
|
||||
'public/locales/_build',
|
||||
'public/locales/**/*.js',
|
||||
'public/vendor/',
|
||||
'scripts/grafana-server/tmp',
|
||||
],
|
||||
},
|
||||
grafanaConfig,
|
||||
{
|
||||
name: 'react/jsx-runtime',
|
||||
// @ts-ignore - not sure why but flat config is typed as a maybe?
|
||||
...reactPlugin.configs.flat['jsx-runtime'],
|
||||
},
|
||||
{
|
||||
name: 'grafana/defaults',
|
||||
linterOptions: {
|
||||
// This reports unused disable directives that we can clean up but
|
||||
// it also conflicts with the betterer eslint rules so disabled
|
||||
reportUnusedDisableDirectives: false,
|
||||
},
|
||||
files: ['**/*.{ts,tsx,js}'],
|
||||
plugins: {
|
||||
'@emotion': emotionPlugin,
|
||||
lodash: lodashPlugin,
|
||||
jest: jestPlugin,
|
||||
import: importPlugin,
|
||||
'jsx-a11y': jsxA11yPlugin,
|
||||
'no-barrel-files': barrelPlugin,
|
||||
'@grafana': grafanaPlugin,
|
||||
},
|
||||
|
||||
settings: {
|
||||
'import/internal-regex': '^(app/)|(@grafana)',
|
||||
'import/external-module-folders': ['node_modules', '.yarn'],
|
||||
},
|
||||
|
||||
rules: {
|
||||
'@grafana/no-border-radius-literal': 'error',
|
||||
'@grafana/no-unreduced-motion': 'error',
|
||||
'react/prop-types': 'off',
|
||||
// need to ignore emotion's `css` prop, see https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-unknown-property.md#rule-options
|
||||
'react/no-unknown-property': ['error', { ignore: ['css'] }],
|
||||
'@emotion/jsx-import': 'error',
|
||||
'@emotion/syntax-preference': [2, 'object'],
|
||||
'lodash/import-scope': [2, 'member'],
|
||||
'jest/no-focused-tests': 'error',
|
||||
'import/order': [
|
||||
'error',
|
||||
{
|
||||
groups: [['builtin', 'external'], 'internal', 'parent', 'sibling', 'index'],
|
||||
'newlines-between': 'always',
|
||||
alphabetize: { order: 'asc' },
|
||||
},
|
||||
],
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
paths: [
|
||||
{
|
||||
name: 'react-redux',
|
||||
importNames: ['useDispatch', 'useSelector'],
|
||||
message: 'Please import from app/types instead.',
|
||||
},
|
||||
{
|
||||
name: 'react-i18next',
|
||||
importNames: ['Trans', 't'],
|
||||
message: 'Please import from app/core/internationalization instead',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
// Use typescript's no-redeclare for compatibility with overrides
|
||||
'no-redeclare': 'off',
|
||||
'@typescript-eslint/no-redeclare': ['error'],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'grafana/uplot-overrides',
|
||||
files: ['packages/grafana-ui/src/components/uPlot/**/*.{ts,tsx}'],
|
||||
rules: {
|
||||
'react-hooks/rules-of-hooks': 'off',
|
||||
'react-hooks/exhaustive-deps': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'grafana/theme-demo-overrides',
|
||||
files: ['packages/grafana-ui/src/components/ThemeDemos/**/*.{ts,tsx}'],
|
||||
rules: {
|
||||
'@emotion/jsx-import': 'off',
|
||||
'react/jsx-uses-react': 'off',
|
||||
'react/react-in-jsx-scope': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'grafana/public-dashboards-overrides',
|
||||
files: ['public/dashboards/scripted*.js'],
|
||||
rules: {
|
||||
'no-redeclare': 'error',
|
||||
'@typescript-eslint/no-redeclare': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'grafana/jsx-a11y-overrides',
|
||||
files: ['**/*.tsx'],
|
||||
ignores: ['**/*.{spec,test}.tsx'],
|
||||
rules: {
|
||||
// rules marked "off" are those left in the recommended preset we need to fix
|
||||
// we should remove the corresponding line and fix them one by one
|
||||
// any marked "error" contain specific overrides we'll need to keep
|
||||
'jsx-a11y/no-autofocus': [
|
||||
'error',
|
||||
{
|
||||
ignoreNonDOM: true,
|
||||
},
|
||||
],
|
||||
'jsx-a11y/label-has-associated-control': [
|
||||
'error',
|
||||
{
|
||||
controlComponents: ['NumberInput'],
|
||||
depth: 2,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'grafana/data-overrides',
|
||||
files: ['packages/grafana-data/**/*.{ts,tsx}'],
|
||||
ignores: ['packages/grafana-data/src/**/*.{spec,test}.{ts,tsx}'],
|
||||
rules: {
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
patterns: ['@grafana/runtime', '@grafana/ui', '@grafana/data'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'grafana/ui-overrides',
|
||||
files: ['packages/grafana-ui/**/*.{ts,tsx}'],
|
||||
ignores: ['packages/grafana-ui/**/*.{test,story}.{ts,tsx}'],
|
||||
rules: {
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
patterns: ['@grafana/runtime', '@grafana/data/*', '@grafana/ui', '@grafana/e2e-selectors/*'],
|
||||
paths: [
|
||||
{
|
||||
name: 'react-i18next',
|
||||
importNames: ['Trans', 't'],
|
||||
message: 'Please import from grafana-ui/src/utils/i18n instead',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'grafana/schema-overrides',
|
||||
files: ['packages/grafana-schema/**/*.{ts,tsx}'],
|
||||
ignores: ['packages/grafana-schema/**/*.test.{ts,tsx}'],
|
||||
rules: {
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
patterns: ['@grafana/*'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'grafana/runtime-overrides',
|
||||
files: ['packages/grafana-runtime/**/*.{ts,tsx}'],
|
||||
rules: {
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
patterns: ['@grafana/runtime', '@grafana/data/*', '@grafana/ui/*', '@grafana/e2e/*'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'grafana/flamegraph-overrides',
|
||||
files: ['packages/grafana-flamegraph/**/*.{ts,tsx}'],
|
||||
ignores: ['packages/grafana-flamegraph/**/*.{test,story}.{ts,tsx}'],
|
||||
rules: {
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
patterns: ['@grafana/runtime', '@grafana/e2e', '@grafana/e2e-selectors/*'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'grafana/alerting-overrides',
|
||||
files: ['public/app/features/alerting/**/*.{ts,tsx,js,jsx}'],
|
||||
rules: {
|
||||
'dot-notation': 'error',
|
||||
'prefer-const': 'error',
|
||||
'react/no-unused-prop-types': 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'grafana/alerting-test-overrides',
|
||||
plugins: {
|
||||
'testing-library': fixupPluginRules({ rules: testingLibraryPlugin.rules }),
|
||||
'jest-dom': jestDomPlugin,
|
||||
},
|
||||
files: [
|
||||
'public/app/features/alerting/**/__tests__/**/*.[jt]s?(x)',
|
||||
'public/app/features/alerting/**/?(*.)+(spec|test).[jt]s?(x)',
|
||||
],
|
||||
rules: {
|
||||
...testingLibraryPlugin.configs['flat/react'].rules,
|
||||
...jestDomPlugin.configs['flat/recommended'].rules,
|
||||
'testing-library/prefer-user-event': 'error',
|
||||
'jest/expect-expect': ['error', { assertFunctionNames: ['expect*', 'reducerTester'] }],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'grafana/explore-traceview-overrides',
|
||||
files: ['public/app/features/explore/TraceView/components/demo/**/*.{ts,tsx,js,jsx}'],
|
||||
rules: {
|
||||
'import/no-extraneous-dependencies': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'grafana/decoupled-plugins-overrides',
|
||||
files: [
|
||||
'public/app/plugins/datasource/azuremonitor/**/*.{ts,tsx}',
|
||||
'public/app/plugins/datasource/cloud-monitoring/**/*.{ts,tsx}',
|
||||
'public/app/plugins/datasource/cloudwatch/**/*.{ts,tsx}',
|
||||
'public/app/plugins/datasource/elasticsearch/**/*.{ts,tsx}',
|
||||
'public/app/plugins/datasource/elasticsearch/**/*.{ts,tsx}',
|
||||
'public/app/plugins/datasource/grafana-postgresql-datasource/**/*.{ts,tsx}',
|
||||
'public/app/plugins/datasource/grafana-pyroscope-datasource/**/*.{ts,tsx}',
|
||||
'public/app/plugins/datasource/grafana-testdata-datasource/**/*.{ts,tsx}',
|
||||
'public/app/plugins/datasource/jaeger/**/*.{ts,tsx}',
|
||||
'public/app/plugins/datasource/loki/**/*.{ts,tsx}',
|
||||
'public/app/plugins/datasource/loki/**/*.{ts,tsx}',
|
||||
'public/app/plugins/datasource/mysql/**/*.{ts,tsx}',
|
||||
'public/app/plugins/datasource/parca/**/*.{ts,tsx}',
|
||||
'public/app/plugins/datasource/tempo/**/*.{ts,tsx}',
|
||||
'public/app/plugins/datasource/zipkin/**/*.{ts,tsx}',
|
||||
],
|
||||
plugins: {
|
||||
import: importPlugin,
|
||||
},
|
||||
settings: {
|
||||
'import/resolver': {
|
||||
node: {
|
||||
extensions: ['.ts', '.tsx'],
|
||||
},
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'import/no-restricted-paths': [
|
||||
'error',
|
||||
{
|
||||
zones: [
|
||||
{
|
||||
target: './public/app/plugins',
|
||||
from: './public',
|
||||
except: ['./app/plugins'],
|
||||
message: 'Core plugins are not allowed to depend on Grafana core packages',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
30
package.json
30
package.json
@ -27,7 +27,7 @@
|
||||
"test:coverage:changes": "jest --coverage --changedSince=origin/main",
|
||||
"test:accessibility-report": "./scripts/generate-a11y-report.sh",
|
||||
"lint": "yarn run lint:ts && yarn run lint:sass",
|
||||
"lint:ts": "eslint . --ext .js,.tsx,.ts --cache",
|
||||
"lint:ts": "eslint . --cache",
|
||||
"lint:sass": "yarn stylelint '{public/sass,packages}/**/*.scss' --cache",
|
||||
"test:ci": "mkdir -p reports/junit && JEST_JUNIT_OUTPUT_DIR=reports/junit jest --ci --reporters=default --reporters=jest-junit -w ${TEST_MAX_WORKERS:-100%}",
|
||||
"lint:fix": "yarn lint:ts --fix",
|
||||
@ -36,7 +36,7 @@
|
||||
"packages:prepare": "lerna version --no-push --no-git-tag-version --force-publish --exact",
|
||||
"packages:pack": "mkdir -p ./npm-artifacts && lerna exec --no-private -- yarn pack --out \"../../npm-artifacts/%s-%v.tgz\"",
|
||||
"packages:typecheck": "nx run-many -t typecheck --projects='tag:scope:package'",
|
||||
"prettier:check": "prettier --check --list-different=false --log-level=warn \"**/*.{ts,tsx,scss,md,mdx,json}\"",
|
||||
"prettier:check": "prettier --check --list-different=false --log-level=warn \"**/*.{ts,tsx,scss,md,mdx,json,js}\"",
|
||||
"prettier:checkDocs": "prettier --check --list-different=false --log-level=warn \"docs/**/*.md\" \"*.md\" \"packages/**/*.{ts,tsx,scss,md,mdx,json}\"",
|
||||
"prettier:write": "prettier --list-different \"**/*.{js,ts,tsx,scss,md,mdx,json}\" --write",
|
||||
"start": "NODE_ENV=dev nx exec -- webpack --config scripts/webpack/webpack.dev.js --watch",
|
||||
@ -46,7 +46,7 @@
|
||||
"storybook": "yarn workspace @grafana/ui storybook --ci",
|
||||
"storybook:build": "yarn workspace @grafana/ui storybook:build",
|
||||
"themes-generate": "esbuild --target=es6 ./scripts/cli/generateSassVariableFiles.ts --bundle --platform=node --tsconfig=./scripts/cli/tsconfig.json | node",
|
||||
"themes:usage": "eslint . --ext .tsx,.ts --ignore-pattern '*.test.ts*' --ignore-pattern '*.spec.ts*' --cache --rule '{ @grafana/theme-token-usage: \"error\" }'",
|
||||
"themes:usage": "eslint . --ignore-pattern '*.test.ts*' --ignore-pattern '*.spec.ts*' --cache --plugin '@grafana' --rule '{ @grafana/theme-token-usage: \"error\" }'",
|
||||
"typecheck": "tsc --noEmit && yarn run packages:typecheck",
|
||||
"plugins:build-bundled": "find plugins-bundled -name package.json -not -path '*/node_modules/*' -execdir yarn build \\;",
|
||||
"watch": "yarn start -d watch,start core:start --watchTheme",
|
||||
@ -77,7 +77,8 @@
|
||||
"@betterer/eslint": "5.4.0",
|
||||
"@cypress/webpack-preprocessor": "6.0.2",
|
||||
"@emotion/eslint-plugin": "11.12.0",
|
||||
"@grafana/eslint-config": "7.0.0",
|
||||
"@eslint/compat": "^1.2.0",
|
||||
"@grafana/eslint-config": "8.0.0",
|
||||
"@grafana/eslint-plugin": "link:./packages/grafana-eslint-rules",
|
||||
"@grafana/plugin-e2e": "^1.11.0",
|
||||
"@grafana/tsconfig": "^2.0.0",
|
||||
@ -90,6 +91,7 @@
|
||||
"@react-types/shared": "3.25.0",
|
||||
"@rtk-query/codegen-openapi": "^1.2.0",
|
||||
"@rtsao/plugin-proposal-class-properties": "7.0.1-patch.1",
|
||||
"@stylistic/eslint-plugin-ts": "^2.9.0",
|
||||
"@swc/core": "1.4.2",
|
||||
"@swc/helpers": "0.5.13",
|
||||
"@testing-library/dom": "10.4.0",
|
||||
@ -152,8 +154,8 @@
|
||||
"@types/webpack-assets-manifest": "^5",
|
||||
"@types/webpack-env": "^1.18.4",
|
||||
"@types/yargs": "17.0.33",
|
||||
"@typescript-eslint/eslint-plugin": "6.21.0",
|
||||
"@typescript-eslint/parser": "6.21.0",
|
||||
"@typescript-eslint/eslint-plugin": "8.9.0",
|
||||
"@typescript-eslint/parser": "8.9.0",
|
||||
"autoprefixer": "10.4.20",
|
||||
"babel-loader": "9.2.1",
|
||||
"blob-polyfill": "9.0.20240710",
|
||||
@ -171,19 +173,19 @@
|
||||
"esbuild": "0.24.0",
|
||||
"esbuild-loader": "4.2.2",
|
||||
"esbuild-plugin-browserslist": "^0.15.0",
|
||||
"eslint": "8.57.0",
|
||||
"eslint": "9.12.0",
|
||||
"eslint-config-prettier": "9.1.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-jest": "28.8.3",
|
||||
"eslint-plugin-jest-dom": "^5.4.0",
|
||||
"eslint-plugin-jsdoc": "48.11.0",
|
||||
"eslint-plugin-jsdoc": "50.4.1",
|
||||
"eslint-plugin-jsx-a11y": "6.10.2",
|
||||
"eslint-plugin-lodash": "7.4.0",
|
||||
"eslint-plugin-no-barrel-files": "^1.1.0",
|
||||
"eslint-plugin-lodash": "8.0.0",
|
||||
"eslint-plugin-no-barrel-files": "^1.1.1",
|
||||
"eslint-plugin-react": "7.37.2",
|
||||
"eslint-plugin-react-hooks": "4.6.0",
|
||||
"eslint-plugin-testing-library": "^6.2.2",
|
||||
"eslint-scope": "^8.0.0",
|
||||
"eslint-plugin-react-hooks": "5.0.0",
|
||||
"eslint-plugin-testing-library": "^6.3.0",
|
||||
"eslint-scope": "^8.1.0",
|
||||
"eslint-webpack-plugin": "4.2.0",
|
||||
"expose-loader": "5.0.0",
|
||||
"fork-ts-checker-webpack-plugin": "9.0.2",
|
||||
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"rules": {
|
||||
"no-restricted-imports": ["error", { "patterns": ["@grafana/runtime", "@grafana/ui", "@grafana/data"] }],
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["**/*.test.{ts,tsx}"],
|
||||
"rules": {
|
||||
"no-restricted-imports": "off",
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
/* eslint-disable id-blacklist, no-restricted-imports, @typescript-eslint/ban-types */
|
||||
/* eslint-disable id-blacklist, no-restricted-imports */
|
||||
import moment, { Moment } from 'moment-timezone';
|
||||
|
||||
import { TimeZone } from '../types/time';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import moment, { Moment, MomentInput, DurationInputArg1, DurationInputArg2 } from 'moment';
|
||||
|
||||
import { TimeZone } from '../types/time';
|
||||
/* eslint-disable id-blacklist, no-restricted-imports, @typescript-eslint/ban-types */
|
||||
/* eslint-disable id-blacklist, no-restricted-imports */
|
||||
export interface DateTimeBuiltinFormat {
|
||||
__momentBuiltinFormatBrand: any;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* eslint-disable id-blacklist, no-restricted-imports, @typescript-eslint/ban-types */
|
||||
/* eslint-disable id-blacklist, no-restricted-imports */
|
||||
import { lowerCase } from 'lodash';
|
||||
import moment from 'moment-timezone';
|
||||
|
||||
|
@ -14,11 +14,11 @@
|
||||
"directory": "packages/grafana-eslint-rules"
|
||||
},
|
||||
"dependencies": {
|
||||
"@typescript-eslint/utils": "^6.0.0"
|
||||
"@typescript-eslint/utils": "^8.9.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/types": "^6.0.0",
|
||||
"eslint": "8.57.0",
|
||||
"@typescript-eslint/types": "^8.9.0",
|
||||
"eslint": "9.12.0",
|
||||
"tslib": "2.7.0"
|
||||
},
|
||||
"private": true
|
||||
|
@ -39,7 +39,7 @@ const rule = createRule({
|
||||
const identifiers = findIdentifiers(node.value.expression);
|
||||
|
||||
for (const identifier of identifiers) {
|
||||
const scope = context.getScope();
|
||||
const scope = context.sourceCode.getScope(node);
|
||||
|
||||
// Find the actual "scoped variable" to inspect it's import
|
||||
// This is relatively fragile, and will fail to find the import if the variable is reassigned
|
||||
|
@ -9,7 +9,7 @@ const noUntranslatedStrings = createRule({
|
||||
create(context) {
|
||||
return {
|
||||
JSXText(node) {
|
||||
const ancestors = context.getAncestors();
|
||||
const ancestors = context.sourceCode.getAncestors(node);
|
||||
const isEmpty = !node.value.trim();
|
||||
const hasTransAncestor = ancestors.some((ancestor) => {
|
||||
return (
|
||||
|
@ -8,7 +8,7 @@ const themeTokenUsage = createRule({
|
||||
return {
|
||||
Identifier: function (node) {
|
||||
if (node.name === 'theme') {
|
||||
const ancestors = context.getAncestors().reverse();
|
||||
const ancestors = context.sourceCode.getAncestors(node).reverse();
|
||||
const paths = [];
|
||||
let lastAncestor = null;
|
||||
for (const ancestor of ancestors) {
|
||||
|
@ -3,11 +3,13 @@ import { RuleTester } from 'eslint';
|
||||
import noAriaLabelE2ESelector from '../rules/no-aria-label-e2e-selectors.cjs';
|
||||
|
||||
RuleTester.setDefaultConfig({
|
||||
parserOptions: {
|
||||
languageOptions: {
|
||||
ecmaVersion: 2018,
|
||||
sourceType: 'module',
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -3,11 +3,13 @@ import { RuleTester } from 'eslint';
|
||||
import noBorderRadiusLiteral from '../rules/no-border-radius-literal.cjs';
|
||||
|
||||
RuleTester.setDefaultConfig({
|
||||
parserOptions: {
|
||||
languageOptions: {
|
||||
ecmaVersion: 2018,
|
||||
sourceType: 'module',
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -1,19 +0,0 @@
|
||||
{
|
||||
"rules": {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"patterns": ["@grafana/runtime", "@grafana/e2e", "@grafana/e2e-selectors/*"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["**/*.{test,story}.{ts,tsx}"],
|
||||
"rules": {
|
||||
"no-restricted-imports": "off",
|
||||
"react/prop-types": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -11,7 +11,7 @@
|
||||
"@swc/core": "1.4.2",
|
||||
"@types/eslint": "9.6.1",
|
||||
"copy-webpack-plugin": "12.0.2",
|
||||
"eslint": "8.57.0",
|
||||
"eslint": "9.12.0",
|
||||
"eslint-webpack-plugin": "4.2.0",
|
||||
"fork-ts-checker-webpack-plugin": "9.0.2",
|
||||
"glob": "11.0.0",
|
||||
|
@ -101,20 +101,20 @@
|
||||
"@types/react-window": "1.8.8",
|
||||
"@types/semver": "7.5.8",
|
||||
"@types/uuid": "9.0.8",
|
||||
"@typescript-eslint/eslint-plugin": "6.21.0",
|
||||
"@typescript-eslint/parser": "6.21.0",
|
||||
"@typescript-eslint/eslint-plugin": "8.9.0",
|
||||
"@typescript-eslint/parser": "8.9.0",
|
||||
"copy-webpack-plugin": "12.0.2",
|
||||
"css-loader": "7.1.2",
|
||||
"esbuild": "0.24.0",
|
||||
"eslint": "8.57.0",
|
||||
"eslint": "9.12.0",
|
||||
"eslint-config-prettier": "9.1.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-jest": "28.8.3",
|
||||
"eslint-plugin-jsdoc": "48.11.0",
|
||||
"eslint-plugin-jsdoc": "50.4.1",
|
||||
"eslint-plugin-jsx-a11y": "6.10.2",
|
||||
"eslint-plugin-lodash": "7.4.0",
|
||||
"eslint-plugin-lodash": "8.0.0",
|
||||
"eslint-plugin-react": "7.37.2",
|
||||
"eslint-plugin-react-hooks": "4.6.0",
|
||||
"eslint-plugin-react-hooks": "5.0.0",
|
||||
"eslint-webpack-plugin": "4.2.0",
|
||||
"fork-ts-checker-webpack-plugin": "9.0.2",
|
||||
"glob": "11.0.0",
|
||||
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
"rules": {
|
||||
"no-restricted-imports": ["error", { "patterns": ["@grafana/runtime", "@grafana/data/*", "@grafana/ui/*", "@grafana/e2e/*"] }]
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"rules": {
|
||||
"no-restricted-imports": ["error", { "patterns": ["@grafana/*"] }]
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["**/*.test.{ts,tsx}"],
|
||||
"rules": {
|
||||
"no-restricted-imports": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
{
|
||||
"rules": {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"patterns": ["@grafana/runtime", "@grafana/data/*", "@grafana/ui", "@grafana/e2e-selectors/*"],
|
||||
"paths": [
|
||||
{
|
||||
"name": "react-i18next",
|
||||
"importNames": ["Trans", "t"],
|
||||
"message": "Please import from grafana-ui/src/utils/i18n instead",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["**/*.{test,story}.{ts,tsx}"],
|
||||
"rules": {
|
||||
"no-restricted-imports": "off",
|
||||
"react/prop-types": "off",
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
{
|
||||
"plugins": ["testing-library", "jest-dom"],
|
||||
"extends": ["plugin:jest-dom/recommended"],
|
||||
"rules": {
|
||||
"dot-notation": "error",
|
||||
"prefer-const": "error",
|
||||
"react/no-unused-prop-types": "error",
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["**/__tests__/**/*.[jt]s?(x)", "**/?(*.)+(spec|test).[jt]s?(x)"],
|
||||
"extends": ["plugin:testing-library/react"],
|
||||
"rules": {
|
||||
"testing-library/prefer-user-event": "error",
|
||||
"jest/expect-expect": ["error", { "assertFunctionNames": ["expect*", "reducerTester"] }],
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
"rules": {
|
||||
"import/no-extraneous-dependencies": 0
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user