@darksheep/eslint 4.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/CHANGELOG.md +737 -0
  2. package/LICENSE +24 -0
  3. package/README.md +34 -0
  4. package/package.json +62 -0
  5. package/src/bin/eslint.cjs +11 -0
  6. package/src/configs/eslint-base.js +124 -0
  7. package/src/configs/eslint-complexity.js +28 -0
  8. package/src/configs/eslint-ignores.js +51 -0
  9. package/src/configs/eslint-recommended.js +9 -0
  10. package/src/configs/eslint-style.js +23 -0
  11. package/src/custom/index.js +11 -0
  12. package/src/custom/instance-of-array.js +72 -0
  13. package/src/custom/loose-types.js +204 -0
  14. package/src/custom/no-useless-expression.js +28 -0
  15. package/src/custom/sequence-expression.js +21 -0
  16. package/src/index.js +86 -0
  17. package/src/plugins/eslint-comments.js +27 -0
  18. package/src/plugins/import.js +139 -0
  19. package/src/plugins/jest.js +124 -0
  20. package/src/plugins/jsdoc.js +70 -0
  21. package/src/plugins/json.js +37 -0
  22. package/src/plugins/jsx-a11y.js +100 -0
  23. package/src/plugins/node.js +129 -0
  24. package/src/plugins/promise.js +16 -0
  25. package/src/plugins/react.js +128 -0
  26. package/src/plugins/regexp.js +13 -0
  27. package/src/plugins/sca.js +41 -0
  28. package/src/plugins/security.js +15 -0
  29. package/src/plugins/sonarjs.js +28 -0
  30. package/src/plugins/style.js +249 -0
  31. package/src/plugins/typescript.js +87 -0
  32. package/src/plugins/unicorn.js +58 -0
  33. package/src/plugins/unused-imports.js +52 -0
  34. package/src/types.d.ts +118 -0
  35. package/src/utilities/editorconfig.js +210 -0
  36. package/src/utilities/eslint-files.js +65 -0
  37. package/src/utilities/expand-glob.js +49 -0
  38. package/src/utilities/filesystem.js +73 -0
  39. package/src/utilities/make-compat.js +17 -0
  40. package/src/utilities/package.js +49 -0
@@ -0,0 +1,28 @@
1
+ const selector = [
2
+ // test || false, false || test
3
+ 'LogicalExpression[operator="||"] > [type=/Literal$/]',
4
+ // true && test, test && true
5
+ 'LogicalExpression[operator="&&"] > [type=/Literal$/]',
6
+ ].join(', ');
7
+
8
+ /** @type {import('eslint').Rule.RuleModule} */
9
+ const rule = {
10
+ meta: { type: 'suggestion' },
11
+
12
+ create: function (context) {
13
+ return {
14
+ /**
15
+ * @param {import('estree').Literal} node The AST function node
16
+ * @returns {void}
17
+ */
18
+ [selector]: (node) => {
19
+ context.report({
20
+ node: node,
21
+ message: 'Unexpected Literal in LogicalExpression',
22
+ });
23
+ },
24
+ };
25
+ },
26
+ };
27
+
28
+ export default rule;
@@ -0,0 +1,21 @@
1
+ /** @type {import('eslint').Rule.RuleModule} */
2
+ const rule = {
3
+ meta: { type: 'suggestion' },
4
+
5
+ create: function (context) {
6
+ return {
7
+ /**
8
+ * @param {import('estree').SequenceExpression} node The AST function node
9
+ * @returns {void}
10
+ */
11
+ SequenceExpression: (node) => {
12
+ context.report({
13
+ node: node,
14
+ message: 'Unexpected use of a SequenceExpression',
15
+ });
16
+ },
17
+ };
18
+ },
19
+ };
20
+
21
+ export default rule;
package/src/index.js ADDED
@@ -0,0 +1,86 @@
1
+ import { pathToFileURL, URL } from 'node:url';
2
+
3
+ import { createEslintIgnoresConfig } from './configs/eslint-ignores.js';
4
+ import { createEslintBaseConfig } from './configs/eslint-base.js';
5
+ import { createEslintRecommendsConfig } from './configs/eslint-recommended.js';
6
+ import { createEslintComplexityConfig } from './configs/eslint-complexity.js';
7
+ import { createStyleConfigs } from './configs/eslint-style.js';
8
+
9
+ import { createEslintCommentsConfig } from './plugins/eslint-comments.js';
10
+ import { createEslintImportConfig } from './plugins/import.js';
11
+ import { createEslintJestConfig } from './plugins/jest.js';
12
+ import { createEslintJSDocConfig } from './plugins/jsdoc.js';
13
+ import { createEslintJsonConfig } from './plugins/json.js';
14
+ import { createEslintJsxA11yConfig } from './plugins/jsx-a11y.js';
15
+ import { createEslintNodeConfigs } from './plugins/node.js';
16
+ import { createEslintPromiseConfig } from './plugins/promise.js';
17
+ import { createEslintReactConfig } from './plugins/react.js';
18
+ import { createEslintRegexpConfig } from './plugins/regexp.js';
19
+ import { createEslintSCAConfig } from './plugins/sca.js';
20
+ import { createEslintSecurityConfig } from './plugins/security.js';
21
+ import { createEslintSonarJSConfig } from './plugins/sonarjs.js';
22
+ import { createEslintStyleConfig } from './plugins/style.js';
23
+ import { createEslintTypescriptConfig } from './plugins/typescript.js';
24
+ import { createEslintUnicornConfig } from './plugins/unicorn.js';
25
+ import { createEslintUnusedImportsConfig } from './plugins/unused-imports.js';
26
+
27
+ const configBuilders = [
28
+ createEslintIgnoresConfig,
29
+ createEslintRecommendsConfig,
30
+ createEslintBaseConfig,
31
+ createEslintComplexityConfig,
32
+ createStyleConfigs,
33
+ createEslintCommentsConfig,
34
+ createEslintImportConfig,
35
+ createEslintNodeConfigs,
36
+ createEslintJsonConfig,
37
+ createEslintPromiseConfig,
38
+ createEslintTypescriptConfig,
39
+ createEslintReactConfig,
40
+ createEslintJsxA11yConfig,
41
+ createEslintSecurityConfig,
42
+ createEslintUnicornConfig,
43
+ createEslintRegexpConfig,
44
+ createEslintSCAConfig,
45
+ createEslintSonarJSConfig,
46
+ createEslintStyleConfig,
47
+ createEslintJestConfig,
48
+ createEslintUnusedImportsConfig,
49
+ createEslintJSDocConfig,
50
+ ];
51
+
52
+ /**
53
+ * @param {URL} root The root url object for the project config
54
+ * @returns {Promise<import('eslint').Linter.FlatConfig[]>}
55
+ */
56
+ async function createConfigUrl(root) {
57
+ const configs = await Promise.all(
58
+ configBuilders.map((builder) => builder(root)),
59
+ );
60
+
61
+ return configs.flat();
62
+ }
63
+
64
+ /**
65
+ * @param {string | URL} root root url
66
+ * @returns {Promise<import('eslint').Linter.FlatConfig[]>}
67
+ */
68
+ export async function createConfig(root) {
69
+ if (root instanceof URL) {
70
+ return createConfigUrl(root);
71
+ }
72
+
73
+ if (typeof root !== 'string') {
74
+ throw new TypeError('Invalid file root');
75
+ }
76
+
77
+ root = root
78
+ // This is to remove: file:/ or file:///
79
+ .replace(/^file:\/*/, '/')
80
+ // This is prevent ?time=<stamp>
81
+ .replace(/\?.*$/, '');
82
+
83
+ return createConfigUrl(pathToFileURL(root));
84
+ }
85
+
86
+ export * from 'eslint';
@@ -0,0 +1,27 @@
1
+ import eslintComments from '@eslint-community/eslint-plugin-eslint-comments';
2
+
3
+ /**
4
+ * Get ESLint config for comments check
5
+ * @returns {import('eslint').Linter.FlatConfig[]}
6
+ */
7
+ export function createEslintCommentsConfig() {
8
+ return [
9
+ {
10
+ plugins: {
11
+ 'eslint-comments': eslintComments,
12
+ },
13
+ rules: {
14
+ 'eslint-comments/disable-enable-pair': [ 'error', { allowWholeFile: true } ],
15
+ 'eslint-comments/no-aggregating-enable': 'error',
16
+ 'eslint-comments/no-duplicate-disable': 'error',
17
+ 'eslint-comments/no-unlimited-disable': 'error',
18
+ 'eslint-comments/no-unused-disable': 'error',
19
+ 'eslint-comments/no-unused-enable': 'error',
20
+
21
+ 'line-comment-position': 'off',
22
+ 'multiline-comment-style': 'off',
23
+ 'no-inline-comments': 'off',
24
+ },
25
+ },
26
+ ];
27
+ }
@@ -0,0 +1,139 @@
1
+ import importPlugin from 'eslint-plugin-import';
2
+
3
+ import {
4
+ getModuleFiles,
5
+ getTypescriptFiles,
6
+ } from '../utilities/eslint-files.js';
7
+
8
+ /** @type {import('eslint').Linter.RulesRecord} */
9
+ const rules = {
10
+ /*
11
+ *Static analysis
12
+ */
13
+ 'import/no-unresolved': 'off',
14
+ 'import/named': 'error',
15
+ 'import/default': 'warn',
16
+ 'import/namespace': [
17
+ 'error',
18
+ { allowComputed: true },
19
+ ],
20
+ 'import/no-restricted-paths': 'off',
21
+ 'import/no-absolute-path': 'error',
22
+ 'import/no-dynamic-require': 'error',
23
+ 'import/no-internal-modules': 'off',
24
+ 'import/no-webpack-loader-syntax': 'off',
25
+ 'import/no-self-import': 'error',
26
+ 'import/no-cycle': [
27
+ 'error',
28
+ { ignoreExternal: true },
29
+ ],
30
+ 'import/no-useless-path-segments': 'error',
31
+ 'import/no-relative-parent-imports': 'off',
32
+
33
+ /*
34
+ * Helpful warnings
35
+ */
36
+ 'import/export': 'error',
37
+ 'import/no-named-as-default': 'error',
38
+ 'import/no-named-as-default-member': 'error',
39
+ 'import/no-deprecated': 'error',
40
+ 'import/no-mutable-exports': 'warn',
41
+
42
+ // For some reason this seems to be broken :thinking:
43
+ // 'import/no-unused-modules': [ 'warn', { unusedExports: true } ],
44
+
45
+ /*
46
+ * Module systems
47
+ */
48
+ 'import/unambiguous': 'error',
49
+ 'import/no-commonjs': 'error',
50
+ 'import/no-amd': 'error',
51
+ 'import/no-nodejs-modules': 'off',
52
+ 'import/no-extraneous-dependencies': 'off',
53
+
54
+ /*
55
+ * Import Style
56
+ */
57
+ 'import/first': 'error',
58
+ 'import/exports-last': 'warn',
59
+ 'import/no-duplicates': 'error',
60
+ 'import/no-namespace': 'off',
61
+ 'import/extensions': 'off',
62
+ 'import/order': [
63
+ 'error', {
64
+ groups: [
65
+ 'builtin',
66
+ 'external',
67
+ [
68
+ 'internal',
69
+ 'sibling',
70
+ 'parent',
71
+ ],
72
+ 'index',
73
+ ],
74
+ },
75
+ ],
76
+ 'import/newline-after-import': 'error',
77
+ // Breaks babel.
78
+ 'import/prefer-default-export': 'off',
79
+ 'import/max-dependencies': 'off',
80
+ 'import/no-unassigned-import': 'error',
81
+ 'import/no-named-default': 'off',
82
+ 'import/no-default-export': 'off',
83
+ 'import/no-named-export': 'off',
84
+ // Breaks babel.
85
+ 'import/no-anonymous-default-export': 'off',
86
+ // This is sometimes painful
87
+ 'import/group-exports': 'off',
88
+ 'import/dynamic-import-chunkname': 'off',
89
+ };
90
+
91
+ /**
92
+ * Get ESLint config for imports check
93
+ * @param {import('node:url').URL} root The root of the eslint config directory
94
+ * @returns {Promise<import('eslint').Linter.FlatConfig[]>}
95
+ */
96
+ export async function createEslintImportConfig(root) {
97
+ return [
98
+ {
99
+ files: await getModuleFiles(root),
100
+ plugins: { import: importPlugin },
101
+ languageOptions: {
102
+ parserOptions: {
103
+ sourceType: 'module',
104
+ ecmaVersion: 2022,
105
+ },
106
+ },
107
+ settings: {
108
+ 'import/parsers': {
109
+ espree: [ '.js', '.cjs', '.mjs', '.jsx' ],
110
+ },
111
+ 'import/resolver': {
112
+ node: true,
113
+ },
114
+ },
115
+ rules: rules,
116
+ },
117
+ {
118
+ files: await getTypescriptFiles(),
119
+ plugins: { import: importPlugin },
120
+ languageOptions: {
121
+ parserOptions: {
122
+ sourceType: 'module',
123
+ ecmaVersion: 2022,
124
+ },
125
+ },
126
+ settings: {
127
+ ...importPlugin.configs.typescript.settings,
128
+
129
+ 'import/resolver': {
130
+ typescript: {
131
+ alwaysTryTypes: true,
132
+ },
133
+ },
134
+
135
+ },
136
+ rules: importPlugin.configs.typescript.rules,
137
+ },
138
+ ];
139
+ }
@@ -0,0 +1,124 @@
1
+ import jest from 'eslint-plugin-jest';
2
+ import { getPackageJson } from '../utilities/package.js';
3
+ import { expandGlob } from '../utilities/expand-glob.js';
4
+
5
+ const { globals } = jest.environments.globals;
6
+
7
+ /**
8
+ * Get ESLint config jest plugin
9
+ * @param {import('node:url').URL} root root url
10
+ * @returns {Promise<import('eslint').Linter.FlatConfig[]>}
11
+ */
12
+ export async function createEslintJestConfig(root) {
13
+ const packageJson = await getPackageJson(root, 'jest');
14
+
15
+ // Jest not installed
16
+ if (packageJson == null) {
17
+ return [];
18
+ }
19
+
20
+ return [
21
+ {
22
+ files: expandGlob('**/*.{test,spec}.{js,ts}'),
23
+ plugins: { jest },
24
+ languageOptions: { globals },
25
+ settings: {
26
+ jest: { version: packageJson?.version },
27
+ // node: { allowModules: [ '@jest/globals' ] },
28
+ },
29
+ rules: {
30
+ 'max-lines': 'off',
31
+ 'max-lines-per-function': 'off',
32
+ 'max-nested-callbacks': 'off',
33
+ 'class-methods-use-this': 'off',
34
+
35
+ 'i6-custom-rules/moment/no-date': 'off',
36
+ 'import/no-webpack-loader-syntax': 'off',
37
+ 'import/first': 'off',
38
+ // 'node/no-extraneous-import': 'off',
39
+ 'sonarjs/no-duplicate-string': 'off',
40
+
41
+ 'jest/consistent-test-it': [
42
+ 'error', {
43
+ fn: 'test',
44
+ withinDescribe: 'test',
45
+ },
46
+ ],
47
+ 'jest/expect-expect': [
48
+ 'error',
49
+ { assertFunctionNames: [ 'expect' ] },
50
+ ],
51
+ 'jest/lowercase-name': 'off',
52
+ 'jest/no-alias-methods': 'error',
53
+
54
+ 'jest/no-commented-out-tests': 'error',
55
+ 'jest/no-disabled-tests': 'warn',
56
+ 'jest/no-focused-tests': 'warn',
57
+
58
+ 'jest/no-duplicate-hooks': 'error',
59
+ 'jest/no-export': 'error',
60
+ 'jest/no-hooks': 'off',
61
+ 'jest/no-identical-title': 'error',
62
+ 'jest/no-jasmine-globals': 'error',
63
+ 'jest/no-large-snapshots': 'off',
64
+ 'jest/no-mocks-import': 'error',
65
+ 'jest/prefer-snapshot-hint': 'off',
66
+
67
+ 'jest/no-conditional-expect': 'error',
68
+ 'jest/no-conditional-in-test': 'warn',
69
+ 'jest/no-deprecated-functions': 'error',
70
+ 'jest/no-restricted-jest-methods': 'off',
71
+ 'jest/no-restricted-matchers': [
72
+ 'error',
73
+ {
74
+ toBeTruthy: 'Avoid `toBeTruthy`',
75
+ toBeFalsy: 'Avoid `toBeFalsy`',
76
+ resolves: 'Use `expect(await promise)` instead.',
77
+ },
78
+ ],
79
+
80
+ 'jest/no-done-callback': 'error',
81
+ 'jest/no-standalone-expect': 'error',
82
+ 'jest/no-test-prefixes': 'error',
83
+ 'jest/no-test-return-statement': 'error',
84
+ 'jest/prefer-called-with': 'warn',
85
+ 'jest/prefer-expect-assertions': [ 'warn', { onlyFunctionsWithAsyncKeyword: true } ],
86
+ 'jest/prefer-comparison-matcher': 'warn',
87
+ 'jest/prefer-equality-matcher': 'warn',
88
+ 'jest/prefer-hooks-in-order': 'warn',
89
+ 'jest/prefer-hooks-on-top': 'warn',
90
+ 'jest/prefer-to-be': 'warn',
91
+ 'jest/prefer-to-contain': 'warn',
92
+ 'jest/prefer-to-have-length': 'warn',
93
+ 'jest/prefer-todo': 'warn',
94
+ 'jest/require-to-throw-message': 'error',
95
+ 'jest/require-top-level-describe': 'error',
96
+ 'jest/valid-describe-callback': 'error',
97
+ 'jest/valid-expect': 'error',
98
+ 'jest/valid-expect-in-promise': 'error',
99
+ 'jest/valid-title': 'error',
100
+
101
+ 'jest/prefer-spy-on': 'warn',
102
+ 'jest/prefer-strict-equal': 'error',
103
+ },
104
+ },
105
+ {
106
+ files: [
107
+ '**/jest.{js,ts}',
108
+ '**/jest/**/*.{js,ts}',
109
+ '**/__mocks__/**/*.{js,ts}',
110
+ '**/test/**/*.{js,ts}',
111
+ '**/spec/**/*.{js,ts}',
112
+ '**/*.spec.ts',
113
+ '**/*.test.ts',
114
+ ],
115
+ languageOptions: {
116
+ globals: {
117
+ __filename: true,
118
+ __dirname: true,
119
+ ...globals,
120
+ },
121
+ },
122
+ },
123
+ ];
124
+ }
@@ -0,0 +1,70 @@
1
+ import jsdoc from 'eslint-plugin-jsdoc';
2
+
3
+ import { getTypescriptFiles } from '../utilities/eslint-files.js';
4
+ import { getPackageJson } from '../utilities/package.js';
5
+
6
+ /**
7
+ * Get ESLint config for js docs
8
+ * @param {URL} root The root of the package being linted
9
+ * @returns {Promise<import('eslint').Linter.FlatConfig[]>}
10
+ */
11
+ export async function createEslintJSDocConfig(root) {
12
+ const tsPackage = await getPackageJson(root, 'typescript');
13
+ const typeChecks = tsPackage == null ? 'warn' : 'off';
14
+
15
+ return [
16
+ {
17
+ plugins: { jsdoc },
18
+ settings: {
19
+ jsdoc: {
20
+ mode: 'typescript',
21
+ // Prefer 'Object' over 'object'
22
+ preferredTypes: { object: 'Object' },
23
+ },
24
+ },
25
+ rules: {
26
+ 'jsdoc/check-access': 'warn',
27
+ 'jsdoc/check-alignment': 'warn',
28
+ 'jsdoc/check-param-names': 'warn',
29
+ 'jsdoc/check-property-names': 'warn',
30
+ 'jsdoc/check-tag-names': 'warn',
31
+ 'jsdoc/check-values': 'warn',
32
+ 'jsdoc/empty-tags': 'warn',
33
+ 'jsdoc/implements-on-classes': 'error',
34
+ 'jsdoc/informative-docs': 'warn',
35
+ 'jsdoc/no-defaults': 'warn',
36
+ 'jsdoc/no-multi-asterisks': 'warn',
37
+ 'jsdoc/require-jsdoc': [ 1, { publicOnly: true } ],
38
+ 'jsdoc/require-param': 'warn',
39
+ 'jsdoc/require-param-description': 'warn',
40
+ 'jsdoc/require-param-name': 'warn',
41
+ 'jsdoc/require-param-type': 'warn',
42
+ 'jsdoc/require-property': 'warn',
43
+ 'jsdoc/require-property-description': 'warn',
44
+ 'jsdoc/require-property-name': 'warn',
45
+ 'jsdoc/require-property-type': 'warn',
46
+ 'jsdoc/require-returns': 'warn',
47
+ 'jsdoc/require-returns-check': 'warn',
48
+ 'jsdoc/require-returns-type': 'warn',
49
+
50
+ 'jsdoc/check-types': typeChecks,
51
+ 'jsdoc/no-undefined-types': typeChecks,
52
+ 'jsdoc/valid-types': typeChecks,
53
+ },
54
+ },
55
+ {
56
+ files: await getTypescriptFiles(),
57
+ rules: {
58
+ 'jsdoc/no-types': 'warn',
59
+ 'jsdoc/check-types': 'off',
60
+ 'jsdoc/no-undefined-types': 'off',
61
+ 'jsdoc/valid-types': 'off',
62
+ 'jsdoc/require-returns': 'off',
63
+ 'jsdoc/require-param-type': 'off',
64
+ 'jsdoc/require-property-type': 'off',
65
+ 'jsdoc/require-returns-type': 'off',
66
+
67
+ },
68
+ },
69
+ ];
70
+ }
@@ -0,0 +1,37 @@
1
+ import jsoncPlugin from 'eslint-plugin-jsonc';
2
+ import jsoncParser from 'jsonc-eslint-parser';
3
+
4
+ import { getJsonFiles } from '../utilities/eslint-files.js';
5
+
6
+ /**
7
+ * Get ESLint config for imports check
8
+ * @returns {Promise<import('eslint').Linter.FlatConfig[]>}
9
+ */
10
+ export async function createEslintJsonConfig() {
11
+ return [
12
+ {
13
+ files: await getJsonFiles(),
14
+ languageOptions: {
15
+ parser: /** @type {*} */ (jsoncParser),
16
+ },
17
+ plugins: {
18
+ jsonc: /** @type {*} */ (jsoncPlugin),
19
+ },
20
+ },
21
+ {
22
+ files: [ '**/*.json' ],
23
+ rules: /** @type {import('eslint').Linter.RulesRecord} */
24
+ (jsoncPlugin.configs['recommended-with-json'].rules),
25
+ },
26
+ {
27
+ files: [ '**/*.jsonc' ],
28
+ rules: /** @type {import('eslint').Linter.RulesRecord} */
29
+ (jsoncPlugin.configs['recommended-with-jsonc'].rules),
30
+ },
31
+ {
32
+ files: [ '**/*.json5' ],
33
+ rules: /** @type {import('eslint').Linter.RulesRecord} */
34
+ (jsoncPlugin.configs['recommended-with-json5'].rules),
35
+ },
36
+ ];
37
+ }
@@ -0,0 +1,100 @@
1
+ import jsxa11y from 'eslint-plugin-jsx-a11y';
2
+
3
+ /** @type {import('eslint').Linter.RulesRecord} */
4
+ const rules = {
5
+ 'jsx-a11y/alt-text': 'error',
6
+ 'jsx-a11y/anchor-ambiguous-text': 'off',
7
+ // TODO: error
8
+ 'jsx-a11y/anchor-has-content': 'error',
9
+ 'jsx-a11y/anchor-is-valid': 'error',
10
+ 'jsx-a11y/aria-activedescendant-has-tabindex': 'error',
11
+ 'jsx-a11y/aria-props': 'error',
12
+ 'jsx-a11y/aria-proptypes': 'error',
13
+ 'jsx-a11y/aria-role': 'error',
14
+ 'jsx-a11y/aria-unsupported-elements': 'error',
15
+ 'jsx-a11y/autocomplete-valid': 'error',
16
+ 'jsx-a11y/click-events-have-key-events': 'error',
17
+ 'jsx-a11y/control-has-associated-label': [ 'off', {
18
+ ignoreElements: [ 'audio', 'canvas', 'embed', 'input', 'textarea', 'tr', 'video' ],
19
+ ignoreRoles: [ 'grid', 'listbox', 'menu', 'menubar', 'radiogroup', 'row', 'tablist', 'toolbar', 'tree', 'treegrid' ],
20
+ includeRoles: [ 'alert', 'dialog' ],
21
+ } ],
22
+ 'jsx-a11y/heading-has-content': 'error',
23
+ 'jsx-a11y/html-has-lang': 'error',
24
+ 'jsx-a11y/iframe-has-title': 'error',
25
+ 'jsx-a11y/img-redundant-alt': 'error',
26
+ 'jsx-a11y/interactive-supports-focus': [ 'error', {
27
+ tabbable: [ 'button', 'checkbox', 'link', 'searchbox', 'spinbutton', 'switch', 'textbox' ],
28
+ } ],
29
+ 'jsx-a11y/label-has-associated-control': 'error',
30
+ 'jsx-a11y/label-has-for': 'off',
31
+ 'jsx-a11y/media-has-caption': 'error',
32
+ 'jsx-a11y/mouse-events-have-key-events': 'error',
33
+ 'jsx-a11y/no-access-key': 'error',
34
+ 'jsx-a11y/no-autofocus': 'error',
35
+ 'jsx-a11y/no-distracting-elements': 'error',
36
+ 'jsx-a11y/no-interactive-element-to-noninteractive-role': [ 'error', {
37
+ tr: [ 'none', 'presentation' ],
38
+ canvas: [ 'img' ],
39
+ } ],
40
+ 'jsx-a11y/no-noninteractive-element-interactions': [ 'error', {
41
+ handlers: [ 'onClick', 'onError', 'onLoad', 'onMouseDown', 'onMouseUp', 'onKeyPress', 'onKeyDown', 'onKeyUp' ],
42
+ alert: [ 'onKeyUp', 'onKeyDown', 'onKeyPress' ],
43
+ body: [ 'onError', 'onLoad' ],
44
+ dialog: [ 'onKeyUp', 'onKeyDown', 'onKeyPress' ],
45
+ iframe: [ 'onError', 'onLoad' ],
46
+ img: [ 'onError', 'onLoad' ],
47
+ } ],
48
+ 'jsx-a11y/no-noninteractive-element-to-interactive-role': [ 'error', {
49
+ ul: [ 'listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid' ],
50
+ ol: [ 'listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid' ],
51
+ li: [ 'menuitem', 'option', 'row', 'tab', 'treeitem' ],
52
+ table: [ 'grid' ],
53
+ td: [ 'gridcell' ],
54
+ fieldset: [ 'radiogroup', 'presentation' ],
55
+ } ],
56
+ 'jsx-a11y/no-noninteractive-tabindex': [ 'error', {
57
+ tags: [],
58
+ roles: [ 'tabpanel' ],
59
+ allowExpressionValues: true,
60
+ } ],
61
+ 'jsx-a11y/no-redundant-roles': 'error',
62
+ 'jsx-a11y/no-static-element-interactions': [ 'error', {
63
+ allowExpressionValues: true,
64
+ handlers: [ 'onClick', 'onMouseDown', 'onMouseUp', 'onKeyPress', 'onKeyDown', 'onKeyUp' ],
65
+ } ],
66
+ 'jsx-a11y/role-has-required-aria-props': 'error',
67
+ 'jsx-a11y/role-supports-aria-props': 'error',
68
+ 'jsx-a11y/scope': 'error',
69
+ 'jsx-a11y/tabindex-no-positive': 'error',
70
+ };
71
+
72
+ /**
73
+ * Get ESLint config for imports check
74
+ * @returns {Promise<import('eslint').Linter.FlatConfig[]>}
75
+ */
76
+ export async function createEslintJsxA11yConfig() {
77
+ return [
78
+ {
79
+ files: [ '**/*.jsx' ],
80
+ languageOptions: {
81
+ parserOptions: {
82
+ ecmaFeatures: { jsx: true },
83
+ },
84
+ },
85
+ plugins: { 'jsx-a11y': jsxa11y },
86
+ rules: rules,
87
+ },
88
+ {
89
+ files: [ '**/*.tsx' ],
90
+ languageOptions: {
91
+ parserOptions: {
92
+ ecmaFeatures: { jsx: true },
93
+ jsxPragma: null, // for @typescript/eslint-parser
94
+ },
95
+ },
96
+ plugins: { 'jsx-a11y': jsxa11y },
97
+ rules: rules,
98
+ },
99
+ ];
100
+ }