eslint-config-vylda-vanilla-react 4.0.0
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.
- package/.editorconfig +12 -0
- package/.gitlab-ci.yml +13 -0
- package/.husky/pre-commit +1 -0
- package/.husky/pre-push +1 -0
- package/.vscode/extensions.json +8 -0
- package/.vscode/settings.json +6 -0
- package/Changelog.md +112 -0
- package/LICENSE +24 -0
- package/README.md +294 -0
- package/eslint.config.mjs +55 -0
- package/index.js +150 -0
- package/package.json +43 -0
- package/rules/a11y.mjs +333 -0
- package/rules/best-practices.mjs +57 -0
- package/rules/constants.mjs +20 -0
- package/rules/hooks.mjs +129 -0
- package/rules/imports.mjs +12 -0
- package/rules/index.mjs +37 -0
- package/rules/perfectionist.mjs +33 -0
- package/rules/react.mjs +610 -0
- package/rules/refresh.mjs +10 -0
- package/rules/stylistic.mjs +154 -0
package/index.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import {
|
|
2
|
+
barrels, barrelsFiles, customs, errors, es6, getImportConfig, ignores, mapFiles, node,
|
|
3
|
+
plus, strict, stylistic, variables,
|
|
4
|
+
} from 'eslint-config-vylda-vanilla';
|
|
5
|
+
import config, {
|
|
6
|
+
files, plugins, reactPlugins, refreshFiles,
|
|
7
|
+
} from './eslint.config.mjs';
|
|
8
|
+
import bestPractices from './rules/best-practices.mjs';
|
|
9
|
+
import * as constants from './rules/constants.mjs';
|
|
10
|
+
import {
|
|
11
|
+
defaultImportExtensions,
|
|
12
|
+
defaultImportExtensionsRuleGranularOption,
|
|
13
|
+
defaultImportNoExtraneousDependenciesDevDependencies,
|
|
14
|
+
defaultImportResolverNodeExtensions,
|
|
15
|
+
} from './rules/imports.mjs';
|
|
16
|
+
import {
|
|
17
|
+
a11y, hooks, perfectionist, react, reactStylistic, refresh,
|
|
18
|
+
} from './rules/index.mjs';
|
|
19
|
+
|
|
20
|
+
const dineddd = defaultImportNoExtraneousDependenciesDevDependencies;
|
|
21
|
+
const diergo = defaultImportExtensionsRuleGranularOption;
|
|
22
|
+
|
|
23
|
+
const defaultOptions = {
|
|
24
|
+
barrelsFiles,
|
|
25
|
+
files,
|
|
26
|
+
importExtensions: defaultImportExtensions,
|
|
27
|
+
importExtensionsRuleGranularOption: diergo,
|
|
28
|
+
importNoExtraneousDependenciesDevDependencies: dineddd,
|
|
29
|
+
importResolverNodeExtensions: defaultImportResolverNodeExtensions,
|
|
30
|
+
plugins,
|
|
31
|
+
refreshFiles,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Create Vanilla ESLint configs
|
|
36
|
+
* @param {Array.<Object>} importConfigs - Array of import configs
|
|
37
|
+
* @returns {Array.<Object>} - ESLint Flat config
|
|
38
|
+
*/
|
|
39
|
+
const createVanillaConfigs = (importConfigs) => [
|
|
40
|
+
...importConfigs,
|
|
41
|
+
...es6,
|
|
42
|
+
...strict,
|
|
43
|
+
...stylistic,
|
|
44
|
+
...bestPractices,
|
|
45
|
+
...errors,
|
|
46
|
+
...node,
|
|
47
|
+
...variables,
|
|
48
|
+
...customs,
|
|
49
|
+
...perfectionist,
|
|
50
|
+
...plus,
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
const reactConfigs = [
|
|
54
|
+
...a11y,
|
|
55
|
+
...hooks,
|
|
56
|
+
...react,
|
|
57
|
+
...reactStylistic,
|
|
58
|
+
...refresh,
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* returns eslint config for typescript
|
|
63
|
+
* @param {string} baseDir - base directory for tsconfig.json
|
|
64
|
+
* @param {object} [options={}] - options
|
|
65
|
+
* @param {Array.<string>} [options.barrelsFiles=['**\/index.{js,mjs}']] - file patterns for barrel files
|
|
66
|
+
* @param {Array.<string>} [options.files=['**\/*.{cjs,js,jsx,mjs}']] - file patterns to lint
|
|
67
|
+
* @param {Array.<string>} [options.importExtensions=['.js', '.jsx', '.mjs']] - extensions for module settings import/extensions
|
|
68
|
+
* @param {Object.<string, string>} [options.importExtensionsRuleGranularOption] - granural oprions for import/extensions rule; for default values see Readme.md
|
|
69
|
+
* @param {Array.<string>} [options.importNoExtraneousDependenciesDevDependencies=['see Readme.md']] - devDependencies for import/no-extraneous-dependencies rule
|
|
70
|
+
* @param {Array.<string>} [options.importResolverNodeExtensions=['.js', '.jsx', '.json', '.mjs']] - extensions for module settings import/resolver.node.extensions
|
|
71
|
+
* @param {Object.<string, Object>} [options.plugins] - default plugins; for default values see Readme.md
|
|
72
|
+
* @param {Array.<string>} [options.refreshFiles=['**\/*.jsx']] - file patterns for refresh rules
|
|
73
|
+
* @returns {Array.<Object>} - ESLint Flat config
|
|
74
|
+
*/
|
|
75
|
+
const getConfig = (options = defaultOptions) => {
|
|
76
|
+
const {
|
|
77
|
+
barrelsFiles: customBarrelsFiles = barrelsFiles,
|
|
78
|
+
files: customFiles = files,
|
|
79
|
+
importExtensions: ie = defaultImportExtensions,
|
|
80
|
+
importExtensionsRuleGranularOption: iergo = diergo,
|
|
81
|
+
importNoExtraneousDependenciesDevDependencies: ineddd = dineddd,
|
|
82
|
+
importResolverNodeExtensions: irne = defaultImportResolverNodeExtensions,
|
|
83
|
+
plugins: customPlugins = plugins,
|
|
84
|
+
refreshFiles: customRefreshFiles = refreshFiles,
|
|
85
|
+
} = options;
|
|
86
|
+
|
|
87
|
+
const importConfigs = getImportConfig({
|
|
88
|
+
importExtensions: ie,
|
|
89
|
+
importExtensionsRuleGranularOption: iergo,
|
|
90
|
+
importNoExtraneousDependenciesDevDependencies: ineddd,
|
|
91
|
+
importResolverNodeExtensions: irne,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const vanillaConfigs = createVanillaConfigs(importConfigs);
|
|
95
|
+
const configsWithFiles = mapFiles(vanillaConfigs, customFiles);
|
|
96
|
+
const reactConfigWithFiles = mapFiles(reactConfigs, customRefreshFiles);
|
|
97
|
+
const barrelsConfigWithFiles = mapFiles(barrels, customBarrelsFiles);
|
|
98
|
+
|
|
99
|
+
const eslintConfig = [
|
|
100
|
+
{
|
|
101
|
+
name: 'vanilla-react/base',
|
|
102
|
+
plugins: customPlugins,
|
|
103
|
+
},
|
|
104
|
+
...configsWithFiles,
|
|
105
|
+
...reactConfigWithFiles,
|
|
106
|
+
...barrelsConfigWithFiles,
|
|
107
|
+
...ignores,
|
|
108
|
+
];
|
|
109
|
+
|
|
110
|
+
return eslintConfig;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const vanillaConfigs = createVanillaConfigs([]);
|
|
114
|
+
|
|
115
|
+
export {
|
|
116
|
+
a11y,
|
|
117
|
+
barrels,
|
|
118
|
+
barrelsFiles,
|
|
119
|
+
bestPractices,
|
|
120
|
+
constants,
|
|
121
|
+
customs,
|
|
122
|
+
defaultImportExtensions,
|
|
123
|
+
defaultImportExtensionsRuleGranularOption,
|
|
124
|
+
defaultImportNoExtraneousDependenciesDevDependencies,
|
|
125
|
+
defaultImportResolverNodeExtensions,
|
|
126
|
+
errors,
|
|
127
|
+
es6,
|
|
128
|
+
files,
|
|
129
|
+
getConfig,
|
|
130
|
+
getImportConfig,
|
|
131
|
+
hooks,
|
|
132
|
+
ignores,
|
|
133
|
+
mapFiles,
|
|
134
|
+
node,
|
|
135
|
+
perfectionist,
|
|
136
|
+
plugins,
|
|
137
|
+
plus,
|
|
138
|
+
react,
|
|
139
|
+
reactConfigs,
|
|
140
|
+
reactPlugins,
|
|
141
|
+
reactStylistic,
|
|
142
|
+
refresh,
|
|
143
|
+
refreshFiles,
|
|
144
|
+
strict,
|
|
145
|
+
stylistic,
|
|
146
|
+
vanillaConfigs,
|
|
147
|
+
variables,
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
export default config;
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "eslint-config-vylda-vanilla-react",
|
|
3
|
+
"version": "4.0.0",
|
|
4
|
+
"description": "Eslint rules for JS React projects",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"eslint",
|
|
9
|
+
"react"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"inspect": "npx @eslint/config-inspector",
|
|
13
|
+
"lint": "eslint .",
|
|
14
|
+
"test": "eslint .",
|
|
15
|
+
"prepare": "husky"
|
|
16
|
+
},
|
|
17
|
+
"author": "Vilem Lipold, vilem.lipold@seznam.cz",
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://gitlab.com/Vylda/eslint-config-vylda-vanilla-react/-/issues"
|
|
20
|
+
},
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://gitlab.com/Vylda/eslint-config-vylda-vanilla-react.git"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://gitlab.com/Vylda/eslint-config-vylda-vanilla-react",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"eslint-config-vylda-vanilla": "^4.3.0",
|
|
32
|
+
"eslint-plugin-jsx-a11y": "^6.10.2",
|
|
33
|
+
"eslint-plugin-react": "^7.37.5",
|
|
34
|
+
"eslint-plugin-react-hooks": "^7.0.1",
|
|
35
|
+
"eslint-plugin-react-refresh": "^0.4.20",
|
|
36
|
+
"globals": "^16.5.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@eslint/config-inspector": "^1.0.2",
|
|
40
|
+
"eslint": "^9.39.0",
|
|
41
|
+
"husky": "^9.1.7"
|
|
42
|
+
}
|
|
43
|
+
}
|
package/rules/a11y.mjs
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import jsxA11y from 'eslint-plugin-jsx-a11y';
|
|
2
|
+
import globals from 'globals';
|
|
3
|
+
import { CONTROL_HAS_ASSOCIATE_LABELL_DEPTH, LABEL_HAS_ASSOCIATE_CONTROL_DEPTH } from './constants.mjs';
|
|
4
|
+
|
|
5
|
+
const strictRules = {
|
|
6
|
+
// aria-activedescendant is used to manage focus within a composite widget.
|
|
7
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-activedescendant-has-tabindex.md
|
|
8
|
+
'jsx-a11y/aria-activedescendant-has-tabindex': 'error',
|
|
9
|
+
|
|
10
|
+
// Elements cannot use an invalid ARIA attribute. This will fail if it finds an aria-* property that is not listed in WAI-ARIA States and Properties spec.
|
|
11
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-props.md
|
|
12
|
+
'jsx-a11y/aria-props': 'error',
|
|
13
|
+
|
|
14
|
+
// ARIA state and property values must be valid.
|
|
15
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-proptypes.md
|
|
16
|
+
'jsx-a11y/aria-proptypes': 'error',
|
|
17
|
+
|
|
18
|
+
// Certain reserved DOM elements do not support ARIA roles, states and properties. This is often because they are not visible, for example meta, html, script, style.
|
|
19
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-unsupported-elements.md
|
|
20
|
+
'jsx-a11y/aria-unsupported-elements': 'error',
|
|
21
|
+
|
|
22
|
+
// <html> elements must have the lang prop.
|
|
23
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/html-has-lang.md
|
|
24
|
+
'jsx-a11y/html-has-lang': 'error',
|
|
25
|
+
|
|
26
|
+
// <iframe> elements must have a unique title property to indicate its content to the user.
|
|
27
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/iframe-has-title.md
|
|
28
|
+
'jsx-a11y/iframe-has-title': 'error',
|
|
29
|
+
|
|
30
|
+
// Enforce img alt attribute does not contain the word image, picture, or photo. Screen readers already announce img elements as an image.
|
|
31
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/img-redundant-alt.md
|
|
32
|
+
'jsx-a11y/img-redundant-alt': 'error',
|
|
33
|
+
|
|
34
|
+
// Elements with an interactive role and interaction handlers (mouse or key press) must be focusable.
|
|
35
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/interactive-supports-focus.md
|
|
36
|
+
'jsx-a11y/interactive-supports-focus': [
|
|
37
|
+
'error',
|
|
38
|
+
{
|
|
39
|
+
tabbable: [
|
|
40
|
+
'button',
|
|
41
|
+
'checkbox',
|
|
42
|
+
'link',
|
|
43
|
+
'progressbar',
|
|
44
|
+
'searchbox',
|
|
45
|
+
'slider',
|
|
46
|
+
'spinbutton',
|
|
47
|
+
'switch',
|
|
48
|
+
'textbox',
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
|
|
53
|
+
// Enforce onmouseover/onmouseout are accompanied by onfocus/onblur.
|
|
54
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/mouse-events-have-key-events.md
|
|
55
|
+
'jsx-a11y/mouse-events-have-key-events': [
|
|
56
|
+
'error',
|
|
57
|
+
{
|
|
58
|
+
hoverInHandlers: [
|
|
59
|
+
'onMouseOver',
|
|
60
|
+
'onMouseEnter',
|
|
61
|
+
'onPointerOver',
|
|
62
|
+
'onPointerEnter',
|
|
63
|
+
],
|
|
64
|
+
hoverOutHandlers: [
|
|
65
|
+
'onMouseOut',
|
|
66
|
+
'onMouseLeave',
|
|
67
|
+
'onPointerOut',
|
|
68
|
+
'onPointerLeave',
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
|
|
73
|
+
// Enforce no accessKey prop on element. Access keys are HTML attributes that allow web developers to assign keyboard shortcuts to elements.
|
|
74
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-access-key.md
|
|
75
|
+
'jsx-a11y/no-access-key': 'error',
|
|
76
|
+
|
|
77
|
+
// Enforce that autoFocus prop is not used on elements.
|
|
78
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-autofocus.md
|
|
79
|
+
'jsx-a11y/no-autofocus': 'error',
|
|
80
|
+
|
|
81
|
+
// Enforces that no distracting elements are used.
|
|
82
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-distracting-elements.md
|
|
83
|
+
'jsx-a11y/no-distracting-elements': 'error',
|
|
84
|
+
|
|
85
|
+
// Elements with ARIA roles must have all required attributes for that role.
|
|
86
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/role-has-required-aria-props.md
|
|
87
|
+
'jsx-a11y/role-has-required-aria-props': 'error',
|
|
88
|
+
|
|
89
|
+
// Enforce that elements with explicit or implicit roles defined contain only aria-* properties supported by that role.
|
|
90
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/role-supports-aria-props.md
|
|
91
|
+
'jsx-a11y/role-supports-aria-props': 'error',
|
|
92
|
+
|
|
93
|
+
// The scope prop should be used only on <th> elements.
|
|
94
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/scope.md
|
|
95
|
+
'jsx-a11y/scope': 'error',
|
|
96
|
+
|
|
97
|
+
// Avoid positive tabIndex property values to synchronize the flow of the page with keyboard tab order.
|
|
98
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/tabindex-no-positive.md
|
|
99
|
+
'jsx-a11y/tabindex-no-positive': 'error',
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const config = [
|
|
103
|
+
{
|
|
104
|
+
languageOptions: {
|
|
105
|
+
...jsxA11y.flatConfigs.recommended.languageOptions,
|
|
106
|
+
globals: {
|
|
107
|
+
...globals.serviceworker,
|
|
108
|
+
...globals.browser,
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
name: 'jsx-a11y/a11y',
|
|
112
|
+
rules: {
|
|
113
|
+
...strictRules,
|
|
114
|
+
|
|
115
|
+
// Enforce that all elements that require alternative text have meaningful information
|
|
116
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/alt-text.md
|
|
117
|
+
'jsx-a11y/alt-text': [
|
|
118
|
+
'error',
|
|
119
|
+
{
|
|
120
|
+
area: [],
|
|
121
|
+
elements: ['img', 'object', 'area', 'input[type="image"]'],
|
|
122
|
+
img: ['Image'],
|
|
123
|
+
'input[type="image"]': [],
|
|
124
|
+
object: [],
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
|
|
128
|
+
// Ensures anchor text is not ambiguous
|
|
129
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/anchor-ambiguous-text.md
|
|
130
|
+
'jsx-a11y/anchor-ambiguous-text': 'off',
|
|
131
|
+
|
|
132
|
+
// Enforce that anchors have content
|
|
133
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/anchor-has-content.md
|
|
134
|
+
'jsx-a11y/anchor-has-content': [
|
|
135
|
+
'error',
|
|
136
|
+
{ components: ['Link', 'LinkButton', 'LinkText'] },
|
|
137
|
+
],
|
|
138
|
+
|
|
139
|
+
// ensure <a> tags are valid
|
|
140
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/anchor-is-valid.md
|
|
141
|
+
'jsx-a11y/anchor-is-valid': [
|
|
142
|
+
'error',
|
|
143
|
+
{
|
|
144
|
+
aspects: ['noHref', 'invalidHref', 'preferButton'],
|
|
145
|
+
components: ['Link'],
|
|
146
|
+
specialLink: ['to'],
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
|
|
150
|
+
// Require ARIA roles to be valid and non-abstract
|
|
151
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-role.md
|
|
152
|
+
'jsx-a11y/aria-role': [
|
|
153
|
+
'error',
|
|
154
|
+
{ ignoreNonDOM: false },
|
|
155
|
+
],
|
|
156
|
+
|
|
157
|
+
// Ensure the autocomplete attribute is correct and suitable for the form field it is used with
|
|
158
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/autocomplete-valid.md
|
|
159
|
+
'jsx-a11y/autocomplete-valid': [
|
|
160
|
+
'error',
|
|
161
|
+
{ inputComponents: ['Input'] },
|
|
162
|
+
],
|
|
163
|
+
|
|
164
|
+
// require onClick be accompanied by onKeyUp/onKeyDown/onKeyPress
|
|
165
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/click-events-have-key-events.md
|
|
166
|
+
'jsx-a11y/click-events-have-key-events': 'error',
|
|
167
|
+
|
|
168
|
+
// Enforce that a control (an interactive element) has a text label.
|
|
169
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/control-has-associated-label.md
|
|
170
|
+
'jsx-a11y/control-has-associated-label': [
|
|
171
|
+
'error',
|
|
172
|
+
{
|
|
173
|
+
controlComponents: [],
|
|
174
|
+
depth: CONTROL_HAS_ASSOCIATE_LABELL_DEPTH,
|
|
175
|
+
ignoreElements: [
|
|
176
|
+
'audio',
|
|
177
|
+
'canvas',
|
|
178
|
+
'embed',
|
|
179
|
+
'input',
|
|
180
|
+
'textarea',
|
|
181
|
+
'tr',
|
|
182
|
+
'video',
|
|
183
|
+
],
|
|
184
|
+
ignoreRoles: [
|
|
185
|
+
'grid',
|
|
186
|
+
'listbox',
|
|
187
|
+
'menu',
|
|
188
|
+
'menubar',
|
|
189
|
+
'radiogroup',
|
|
190
|
+
'row',
|
|
191
|
+
'tablist',
|
|
192
|
+
'toolbar',
|
|
193
|
+
'tree',
|
|
194
|
+
'treegrid',
|
|
195
|
+
],
|
|
196
|
+
includeRoles: ['alert', 'dialog'],
|
|
197
|
+
labelAttributes: ['label'],
|
|
198
|
+
},
|
|
199
|
+
],
|
|
200
|
+
|
|
201
|
+
// ensure <hX> tags have content and are not aria-hidden
|
|
202
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/heading-has-content.md
|
|
203
|
+
'jsx-a11y/heading-has-content': [
|
|
204
|
+
'error',
|
|
205
|
+
{ components: ['Heading'] },
|
|
206
|
+
],
|
|
207
|
+
|
|
208
|
+
// Enforce that a label tag has a text label and an associated control.
|
|
209
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/label-has-associated-control.md
|
|
210
|
+
'jsx-a11y/label-has-associated-control': [
|
|
211
|
+
'error',
|
|
212
|
+
{
|
|
213
|
+
assert: 'both',
|
|
214
|
+
controlComponents: [],
|
|
215
|
+
depth: LABEL_HAS_ASSOCIATE_CONTROL_DEPTH,
|
|
216
|
+
labelAttributes: [],
|
|
217
|
+
labelComponents: [],
|
|
218
|
+
},
|
|
219
|
+
],
|
|
220
|
+
|
|
221
|
+
// require HTML element's lang prop to be valid
|
|
222
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/lang.md
|
|
223
|
+
'jsx-a11y/lang': 'error',
|
|
224
|
+
|
|
225
|
+
// media elements must have captions
|
|
226
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/media-has-caption.md
|
|
227
|
+
'jsx-a11y/media-has-caption': ['error', {
|
|
228
|
+
audio: [],
|
|
229
|
+
track: [],
|
|
230
|
+
video: [],
|
|
231
|
+
}],
|
|
232
|
+
|
|
233
|
+
// Enforce that aria-hidden="true" is not set on focusable elements.
|
|
234
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-aria-hidden-on-focusable.md
|
|
235
|
+
'jsx-a11y/no-aria-hidden-on-focusable': 'error',
|
|
236
|
+
|
|
237
|
+
// prohibit autoFocus prop
|
|
238
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-autofocus.md
|
|
239
|
+
'jsx-a11y/no-autofocus': [
|
|
240
|
+
'error',
|
|
241
|
+
{ ignoreNonDOM: true },
|
|
242
|
+
],
|
|
243
|
+
|
|
244
|
+
// prevent distracting elements, like <marquee> and <blink>
|
|
245
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-distracting-elements.md
|
|
246
|
+
'jsx-a11y/no-distracting-elements': [
|
|
247
|
+
'error',
|
|
248
|
+
{ elements: ['marquee', 'blink'] },
|
|
249
|
+
],
|
|
250
|
+
|
|
251
|
+
// WAI-ARIA roles should not be used to convert an interactive element to non-interactive
|
|
252
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-interactive-element-to-noninteractive-role.md
|
|
253
|
+
'jsx-a11y/no-interactive-element-to-noninteractive-role': [
|
|
254
|
+
'error',
|
|
255
|
+
{ tr: ['none', 'presentation'] },
|
|
256
|
+
],
|
|
257
|
+
|
|
258
|
+
// A non-interactive element does not support event handlers (mouse and key handlers)
|
|
259
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-noninteractive-element-interactions.md
|
|
260
|
+
'jsx-a11y/no-noninteractive-element-interactions': [
|
|
261
|
+
'error',
|
|
262
|
+
{
|
|
263
|
+
body: ['onError', 'onLoad'],
|
|
264
|
+
handlers: [
|
|
265
|
+
'onClick',
|
|
266
|
+
'onMouseDown',
|
|
267
|
+
'onMouseUp',
|
|
268
|
+
'onKeyPress',
|
|
269
|
+
'onKeyDown',
|
|
270
|
+
'onKeyUp',
|
|
271
|
+
],
|
|
272
|
+
iframe: ['onError', 'onLoad'],
|
|
273
|
+
img: ['onError', 'onLoad'],
|
|
274
|
+
},
|
|
275
|
+
],
|
|
276
|
+
|
|
277
|
+
// WAI-ARIA roles should not be used to convert a non-interactive element to interactive
|
|
278
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-noninteractive-element-to-interactive-role.md
|
|
279
|
+
'jsx-a11y/no-noninteractive-element-to-interactive-role': [
|
|
280
|
+
'error',
|
|
281
|
+
{
|
|
282
|
+
li: ['menuitem', 'option', 'row', 'tab', 'treeitem'],
|
|
283
|
+
ol: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'],
|
|
284
|
+
table: ['grid'],
|
|
285
|
+
td: ['gridcell'],
|
|
286
|
+
ul: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'],
|
|
287
|
+
},
|
|
288
|
+
],
|
|
289
|
+
|
|
290
|
+
// Tab key navigation should be limited to elements on the page that can be interacted with.
|
|
291
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-noninteractive-tabindex.md
|
|
292
|
+
'jsx-a11y/no-noninteractive-tabindex': [
|
|
293
|
+
'error',
|
|
294
|
+
{
|
|
295
|
+
allowExpressionValues: true,
|
|
296
|
+
roles: ['tabpanel'],
|
|
297
|
+
tags: [],
|
|
298
|
+
},
|
|
299
|
+
],
|
|
300
|
+
|
|
301
|
+
// ensure HTML elements do not specify redundant ARIA roles
|
|
302
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-redundant-roles.md
|
|
303
|
+
'jsx-a11y/no-redundant-roles': [
|
|
304
|
+
'error',
|
|
305
|
+
{
|
|
306
|
+
nav: ['navigation'],
|
|
307
|
+
},
|
|
308
|
+
],
|
|
309
|
+
|
|
310
|
+
// Enforce that DOM elements without semantic behavior not have interaction handlers
|
|
311
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-static-element-interactions.md
|
|
312
|
+
'jsx-a11y/no-static-element-interactions': [
|
|
313
|
+
'error',
|
|
314
|
+
{
|
|
315
|
+
handlers: [
|
|
316
|
+
'onClick',
|
|
317
|
+
'onMouseDown',
|
|
318
|
+
'onMouseUp',
|
|
319
|
+
'onKeyPress',
|
|
320
|
+
'onKeyDown',
|
|
321
|
+
'onKeyUp',
|
|
322
|
+
],
|
|
323
|
+
},
|
|
324
|
+
],
|
|
325
|
+
|
|
326
|
+
// Enforces using semantic DOM elements over the ARIA role property.
|
|
327
|
+
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/prefer-tag-over-role.md
|
|
328
|
+
'jsx-a11y/prefer-tag-over-role': 'off',
|
|
329
|
+
},
|
|
330
|
+
},
|
|
331
|
+
];
|
|
332
|
+
|
|
333
|
+
export default config;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { bestPractices } from 'eslint-config-vylda-vanilla';
|
|
2
|
+
|
|
3
|
+
const getOldRule = (ruleName) => {
|
|
4
|
+
const oldRuleSet = bestPractices.find((ruleSet) => {
|
|
5
|
+
const { rules } = ruleSet;
|
|
6
|
+
const rule = rules[ruleName];
|
|
7
|
+
|
|
8
|
+
return rule;
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
if (!oldRuleSet) {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { rules } = oldRuleSet;
|
|
16
|
+
const oldRule = rules[ruleName];
|
|
17
|
+
|
|
18
|
+
return oldRule;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const updateOldRules = () => {
|
|
22
|
+
const classMethodsUseThisRule = getOldRule('class-methods-use-this');
|
|
23
|
+
|
|
24
|
+
if (!!classMethodsUseThisRule) {
|
|
25
|
+
const [, cmutRuleOptions] = classMethodsUseThisRule;
|
|
26
|
+
|
|
27
|
+
const newCmutRuleOptions = {
|
|
28
|
+
...cmutRuleOptions,
|
|
29
|
+
exceptMethods: [
|
|
30
|
+
'render',
|
|
31
|
+
'getInitialState',
|
|
32
|
+
'getDefaultProps',
|
|
33
|
+
'getChildContext',
|
|
34
|
+
'componentWillMount',
|
|
35
|
+
'UNSAFE_componentWillMount',
|
|
36
|
+
'componentDidMount',
|
|
37
|
+
'componentWillReceiveProps',
|
|
38
|
+
'UNSAFE_componentWillReceiveProps',
|
|
39
|
+
'shouldComponentUpdate',
|
|
40
|
+
'componentWillUpdate',
|
|
41
|
+
'UNSAFE_componentWillUpdate',
|
|
42
|
+
'componentDidUpdate',
|
|
43
|
+
'componentWillUnmount',
|
|
44
|
+
'componentDidCatch',
|
|
45
|
+
'getSnapshotBeforeUpdate',
|
|
46
|
+
],
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
classMethodsUseThisRule[1] = newCmutRuleOptions;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return structuredClone(bestPractices);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const config = updateOldRules();
|
|
56
|
+
|
|
57
|
+
export default config;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { constants } from 'eslint-config-vylda-vanilla';
|
|
2
|
+
|
|
3
|
+
export const {
|
|
4
|
+
COMPLEXITY,
|
|
5
|
+
CURLY_NEWLINE_PROPERTY_MIN_ELEMENTS,
|
|
6
|
+
IGNORE_CHAIN_WITH_DEPTH,
|
|
7
|
+
INDENT, MAX_DEPENDENCIES,
|
|
8
|
+
MAX_FUNCTION_PARAMS,
|
|
9
|
+
MAX_LINE_CODE_LENGTH,
|
|
10
|
+
MAX_LINE_COMMENTS_LENGTH,
|
|
11
|
+
MAX_LINE_PER_FILE,
|
|
12
|
+
MAX_LINE_PER_FUNCTION,
|
|
13
|
+
MAX_NESTED_BLOCKS,
|
|
14
|
+
MAX_NESTED_CALLBACKS,
|
|
15
|
+
OBJECT_CURLY_MIN_PROPS,
|
|
16
|
+
} = constants;
|
|
17
|
+
|
|
18
|
+
export const CONTROL_HAS_ASSOCIATE_LABELL_DEPTH = 5;
|
|
19
|
+
export const JSX_MAX_DEPTH = 4;
|
|
20
|
+
export const LABEL_HAS_ASSOCIATE_CONTROL_DEPTH = 25;
|