@innovixx/eslint-config 2.0.3-alpha.3 → 3.0.0-alpha.2
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/config/configs/base/index.mjs +46 -0
- package/{configs/base/rules/best-practices.js → config/configs/base/rules/best-practices.mjs} +7 -1
- package/{configs/base/rules/errors.js → config/configs/base/rules/errors.mjs} +5 -1
- package/{configs/base/rules/es6.js → config/configs/base/rules/es6.mjs} +12 -4
- package/{configs/base/rules/imports.js → config/configs/base/rules/imports.mjs} +24 -18
- package/{configs/base/rules/style.js → config/configs/base/rules/style.mjs} +5 -1
- package/{configs/base/rules/variables.js → config/configs/base/rules/variables.mjs} +4 -4
- package/config/configs/jest/index.mjs +33 -0
- package/{configs/jest/rules/jest-dom.js → config/configs/jest/rules/jest-dom.mjs} +5 -1
- package/{configs/jest/rules/jest.js → config/configs/jest/rules/jest.mjs} +5 -1
- package/config/configs/react/index.mjs +52 -0
- package/{configs/react/rules/react-a11y.js → config/configs/react/rules/react-a11y.mjs} +5 -1
- package/config/configs/react/rules/react-hooks.mjs +13 -0
- package/{configs/react/rules/react.js → config/configs/react/rules/react.mjs} +5 -1
- package/config/configs/typescript/index.mjs +30 -0
- package/{configs/typescript/rules/variables.js → config/configs/typescript/rules/variables.mjs} +5 -1
- package/{configs/typescript/rules/typescript.js → config/configs/typescript/settings/typescript.mjs} +8 -1
- package/config/deepMerge.mjs +62 -0
- package/config/index.mjs +150 -0
- package/demo/components/AnotherComponentTest/index.tsx +3 -0
- package/demo/components/ComponentTest/index.tsx +3 -0
- package/demo/components/TestComponent/index.tsx +3 -0
- package/demo/components/index.ts +3 -0
- package/demo/index.ts +1 -0
- package/eslint.config.mjs +40 -31
- package/package.json +23 -13
- package/configs/base/index.js +0 -19
- package/configs/index.js +0 -9
- package/configs/jest/index.js +0 -14
- package/configs/react/index.js +0 -22
- package/configs/react/rules/react-hooks.js +0 -11
- package/configs/typescript/index.js +0 -14
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { configs as regexpPluginConfigs } from 'eslint-plugin-regexp';
|
|
2
|
+
import * as esPluginImport from 'eslint-plugin-import';
|
|
3
|
+
import sortExportAllPlugin from 'eslint-plugin-sort-export-all';
|
|
4
|
+
|
|
5
|
+
import { deepMerge } from '../../deepMerge.mjs';
|
|
6
|
+
import bestPracticesRules from './rules/best-practices.mjs';
|
|
7
|
+
import errorRules from './rules/errors.mjs';
|
|
8
|
+
import es6Rules from './rules/es6.mjs';
|
|
9
|
+
import importRules from './rules/imports.mjs';
|
|
10
|
+
import styleRules from './rules/style.mjs';
|
|
11
|
+
import variableRules from './rules/variables.mjs';
|
|
12
|
+
|
|
13
|
+
/** @type {import('eslint').Linter.Config} */
|
|
14
|
+
|
|
15
|
+
export const index = deepMerge(
|
|
16
|
+
{
|
|
17
|
+
rules: bestPracticesRules.rules,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
rules: errorRules.rules,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
rules: es6Rules.rules,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
rules: importRules.rules,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
rules: styleRules.rules,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
rules: variableRules.rules,
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
plugins: {
|
|
36
|
+
regexp: regexpPluginConfigs,
|
|
37
|
+
import: esPluginImport,
|
|
38
|
+
'sort-export-all': sortExportAllPlugin,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
settings: importRules.settings,
|
|
43
|
+
},
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
export default index;
|
package/{configs/base/rules/best-practices.js → config/configs/base/rules/best-practices.mjs}
RENAMED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
/** @type {import('eslint').Linter.Config} */
|
|
2
|
+
|
|
3
|
+
const bestPracticesRules = {
|
|
2
4
|
rules: {
|
|
3
5
|
// enforces getter/setter pairs in objects
|
|
4
6
|
'accessor-pairs': 'off',
|
|
@@ -343,6 +345,8 @@ module.exports = {
|
|
|
343
345
|
// https://eslint.org/docs/rules/require-unicode-regexp
|
|
344
346
|
'require-unicode-regexp': 'off',
|
|
345
347
|
|
|
348
|
+
'sort-export-all/sort-export-all': 'warn',
|
|
349
|
+
|
|
346
350
|
// requires to declare all vars on top of their containing scope
|
|
347
351
|
'vars-on-top': 'error',
|
|
348
352
|
|
|
@@ -354,3 +358,5 @@ module.exports = {
|
|
|
354
358
|
yoda: 'error',
|
|
355
359
|
},
|
|
356
360
|
};
|
|
361
|
+
|
|
362
|
+
export default bestPracticesRules;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
/** @type {import('eslint').Linter.Config} */
|
|
2
|
+
|
|
3
|
+
const errorRules = {
|
|
2
4
|
rules: {
|
|
3
5
|
// Enforce “for” loop update clause moving the counter in the right direction
|
|
4
6
|
// https://eslint.org/docs/rules/for-direction
|
|
@@ -152,3 +154,5 @@ module.exports = {
|
|
|
152
154
|
'valid-typeof': ['error', { requireStringLiterals: true }],
|
|
153
155
|
},
|
|
154
156
|
};
|
|
157
|
+
|
|
158
|
+
export default errorRules;
|
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import globals from 'globals';
|
|
2
|
+
|
|
3
|
+
/** @type {import('eslint').Linter.Config} */
|
|
4
|
+
|
|
5
|
+
const es6Rules = {
|
|
6
|
+
languageOptions: {
|
|
7
|
+
globals: {
|
|
8
|
+
...globals.es2015,
|
|
9
|
+
},
|
|
4
10
|
},
|
|
5
11
|
parserOptions: {
|
|
6
|
-
ecmaVersion:
|
|
12
|
+
ecmaVersion: 'latest',
|
|
7
13
|
sourceType: 'module',
|
|
8
14
|
ecmaFeatures: {
|
|
9
15
|
generators: false,
|
|
@@ -174,3 +180,5 @@ module.exports = {
|
|
|
174
180
|
'yield-star-spacing': ['error', 'after'],
|
|
175
181
|
},
|
|
176
182
|
};
|
|
183
|
+
|
|
184
|
+
export default es6Rules;
|
|
@@ -1,30 +1,34 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import globals from "globals";
|
|
2
|
+
import importPlugin from "eslint-plugin-import";
|
|
3
|
+
|
|
4
|
+
/** @type {import('eslint').Linter.Config} */
|
|
5
|
+
|
|
6
|
+
const importRules = {
|
|
7
|
+
languageOptions: {
|
|
8
|
+
globals: {
|
|
9
|
+
globals: {
|
|
10
|
+
...globals.es2015,
|
|
11
|
+
}
|
|
12
|
+
}
|
|
4
13
|
},
|
|
5
14
|
parserOptions: {
|
|
6
|
-
ecmaVersion:
|
|
15
|
+
ecmaVersion: 'latest',
|
|
7
16
|
sourceType: 'module',
|
|
8
17
|
},
|
|
9
|
-
plugins:
|
|
10
|
-
|
|
11
|
-
|
|
18
|
+
plugins: {
|
|
19
|
+
import: importPlugin,
|
|
20
|
+
},
|
|
12
21
|
settings: {
|
|
13
22
|
'import/resolver': {
|
|
14
23
|
node: {
|
|
15
|
-
extensions: [
|
|
24
|
+
extensions: [
|
|
25
|
+
'.ts',
|
|
26
|
+
'.tsx',
|
|
27
|
+
'.jsx',
|
|
28
|
+
'.js',
|
|
29
|
+
],
|
|
16
30
|
},
|
|
17
31
|
},
|
|
18
|
-
'import/extensions': [
|
|
19
|
-
'.js',
|
|
20
|
-
'.mjs',
|
|
21
|
-
'.jsx',
|
|
22
|
-
],
|
|
23
|
-
'import/core-modules': [],
|
|
24
|
-
'import/ignore': [
|
|
25
|
-
'node_modules',
|
|
26
|
-
'\\.(coffee|scss|css|less|hbs|svg|json)$',
|
|
27
|
-
],
|
|
28
32
|
},
|
|
29
33
|
rules: {
|
|
30
34
|
// Static analysis:
|
|
@@ -237,3 +241,5 @@ module.exports = {
|
|
|
237
241
|
}],
|
|
238
242
|
},
|
|
239
243
|
};
|
|
244
|
+
|
|
245
|
+
export default importRules;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
/** @type {import('eslint').Linter.Config} */
|
|
2
|
+
|
|
3
|
+
const styleRules = {
|
|
2
4
|
rules: {
|
|
3
5
|
// enforce line breaks after opening and before closing array brackets
|
|
4
6
|
// https://eslint.org/docs/rules/array-bracket-newline
|
|
@@ -518,3 +520,5 @@ module.exports = {
|
|
|
518
520
|
'wrap-regex': 'off',
|
|
519
521
|
},
|
|
520
522
|
};
|
|
523
|
+
|
|
524
|
+
export default styleRules;
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
module.exports = {
|
|
1
|
+
const variableRules = {
|
|
4
2
|
rules: {
|
|
5
3
|
// enforce or disallow variable initializations at definition
|
|
6
4
|
'init-declarations': 'off',
|
|
@@ -16,7 +14,7 @@ module.exports = {
|
|
|
16
14
|
'no-label-var': 'error',
|
|
17
15
|
|
|
18
16
|
// disallow specific globals
|
|
19
|
-
'no-restricted-globals': ['error', 'isFinite', 'isNaN']
|
|
17
|
+
'no-restricted-globals': ['error', 'isFinite', 'isNaN'],
|
|
20
18
|
|
|
21
19
|
// disallow declaration of variables already declared in the outer scope
|
|
22
20
|
'no-shadow': 'error',
|
|
@@ -42,3 +40,5 @@ module.exports = {
|
|
|
42
40
|
'no-use-before-define': ['error', { functions: true, classes: true, variables: true }],
|
|
43
41
|
},
|
|
44
42
|
};
|
|
43
|
+
|
|
44
|
+
export default variableRules;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import jestPlugin from 'eslint-plugin-jest';
|
|
2
|
+
import jestDomPlugin from 'eslint-plugin-jest-dom';
|
|
3
|
+
import globals from 'globals';
|
|
4
|
+
import jestRules from './rules/jest.mjs';
|
|
5
|
+
import jestDomRules from './rules/jest-dom.mjs';
|
|
6
|
+
|
|
7
|
+
import { deepMerge } from '../../deepMerge.mjs';
|
|
8
|
+
|
|
9
|
+
/** @type {import ('eslint').Linter.Config} */
|
|
10
|
+
|
|
11
|
+
export const index = deepMerge(
|
|
12
|
+
{
|
|
13
|
+
languageOptions: {
|
|
14
|
+
globals: {
|
|
15
|
+
...globals.jest,
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
rules: jestRules.rules,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
rules: jestDomRules.rules,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
plugins: {
|
|
27
|
+
jest: jestPlugin,
|
|
28
|
+
'jest-dom': jestDomPlugin,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
export default index;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
/** @type {import ('eslint').Linter.Config} */
|
|
2
|
+
|
|
3
|
+
const jestDomRules = {
|
|
2
4
|
rules: {
|
|
3
5
|
'jest-dom/prefer-checked': 'error',
|
|
4
6
|
'jest-dom/prefer-enabled-disabled': 'error',
|
|
@@ -7,3 +9,5 @@ module.exports = {
|
|
|
7
9
|
'jest-dom/prefer-to-have-attribute': 'error',
|
|
8
10
|
},
|
|
9
11
|
};
|
|
12
|
+
|
|
13
|
+
export default jestDomRules;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
/** @type {import ('eslint').Linter.Config} */
|
|
2
|
+
|
|
3
|
+
const jestRules = {
|
|
2
4
|
rules: {
|
|
3
5
|
'jest/consistent-test-it': ['error', { fn: 'it' }],
|
|
4
6
|
'jest/expect-expect': 'error',
|
|
@@ -32,3 +34,5 @@ module.exports = {
|
|
|
32
34
|
'jest/valid-title': 'error',
|
|
33
35
|
},
|
|
34
36
|
};
|
|
37
|
+
|
|
38
|
+
export default jestRules;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import react from 'eslint-plugin-react';
|
|
2
|
+
import jsxA11y from 'eslint-plugin-jsx-a11y';
|
|
3
|
+
import reactHooks from 'eslint-plugin-react-hooks';
|
|
4
|
+
import globals from 'globals';
|
|
5
|
+
import reactRules from './rules/react.mjs';
|
|
6
|
+
import reactA11yRules from './rules/react-a11y.mjs';
|
|
7
|
+
import { deepMerge } from '../../deepMerge.mjs';
|
|
8
|
+
import reactHooksRules from './rules/react-hooks.mjs';
|
|
9
|
+
|
|
10
|
+
/** @type {import ('eslint').Linter.Config} */
|
|
11
|
+
|
|
12
|
+
export const index = deepMerge(
|
|
13
|
+
react.configs['recommended-type-checked'],
|
|
14
|
+
{
|
|
15
|
+
rules: reactRules.rules,
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
rules: reactA11yRules.rules,
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
rules: reactHooksRules,
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
rules: {
|
|
25
|
+
...reactHooks.configs.recommended.rules,
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
languageOptions: {
|
|
30
|
+
globals: {
|
|
31
|
+
...globals.browser,
|
|
32
|
+
},
|
|
33
|
+
parserOptions: {
|
|
34
|
+
ecmaFeatures: {
|
|
35
|
+
jsx: true,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
plugins: {
|
|
40
|
+
react,
|
|
41
|
+
'jsx-a11y': jsxA11y,
|
|
42
|
+
'react-hooks': reactHooks,
|
|
43
|
+
},
|
|
44
|
+
settings: {
|
|
45
|
+
react: {
|
|
46
|
+
version: 'detect',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
export default index;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
/** @type {import('eslint').Linter.Config} */
|
|
2
|
+
|
|
3
|
+
const reactA11yRules = {
|
|
2
4
|
rules: {
|
|
3
5
|
// Enforce that anchors have content
|
|
4
6
|
// https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/anchor-has-content.md
|
|
@@ -227,3 +229,5 @@ module.exports = {
|
|
|
227
229
|
}],
|
|
228
230
|
},
|
|
229
231
|
};
|
|
232
|
+
|
|
233
|
+
export default reactA11yRules;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** @type {import('eslint').Linter.Config} */
|
|
2
|
+
|
|
3
|
+
const reactHooksRules = {
|
|
4
|
+
// Enforce Rules of Hooks
|
|
5
|
+
// https://github.com/facebook/react/blob/c11015ff4f610ac2924d1fc6d569a17657a404fd/packages/eslint-plugin-react-hooks/src/RulesOfHooks.js
|
|
6
|
+
'react-hooks/rules-of-hooks': 'error',
|
|
7
|
+
|
|
8
|
+
// Verify the list of the dependencies for Hooks like useEffect and similar
|
|
9
|
+
// https://github.com/facebook/react/blob/1204c789776cb01fbaf3e9f032e7e2ba85a44137/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js
|
|
10
|
+
'react-hooks/exhaustive-deps': 'error',
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default reactHooksRules;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
/** @type {import('eslint').Linter.Config} */
|
|
2
|
+
|
|
3
|
+
const reactRules = {
|
|
2
4
|
rules: {
|
|
3
5
|
// View link below for react rules documentation
|
|
4
6
|
// https://github.com/yannickcr/eslint-plugin-react#list-of-supported-rules
|
|
@@ -495,3 +497,5 @@ module.exports = {
|
|
|
495
497
|
],
|
|
496
498
|
},
|
|
497
499
|
};
|
|
500
|
+
|
|
501
|
+
export default reactRules;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import tsPlugin from '@typescript-eslint/eslint-plugin';
|
|
2
|
+
import tsParser from '@typescript-eslint/parser';
|
|
3
|
+
import * as tsImportResolver from 'eslint-import-resolver-typescript';
|
|
4
|
+
import typeScriptSettings from './settings/typescript.mjs';
|
|
5
|
+
import variableRules from './rules/variables.mjs';
|
|
6
|
+
import { deepMerge } from '../../deepMerge.mjs';
|
|
7
|
+
|
|
8
|
+
/** @type {import('eslint').Linter.Config} */
|
|
9
|
+
|
|
10
|
+
export const index = deepMerge(
|
|
11
|
+
{
|
|
12
|
+
settings: typeScriptSettings.settings,
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
rules: variableRules.rules,
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
plugins: {
|
|
19
|
+
'@typescript-eslint': tsPlugin,
|
|
20
|
+
'eslint-import-resolver-typescript': tsImportResolver,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
languageOptions: {
|
|
25
|
+
parser: tsParser,
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
export default index;
|
package/{configs/typescript/rules/variables.js → config/configs/typescript/rules/variables.mjs}
RENAMED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
/** @type {import('eslint').Linter.Config} */
|
|
2
|
+
|
|
3
|
+
const variableRules = {
|
|
2
4
|
rules: {
|
|
3
5
|
// Disallow unused variables.
|
|
4
6
|
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
|
|
5
7
|
},
|
|
6
8
|
};
|
|
9
|
+
|
|
10
|
+
export default variableRules;
|
package/{configs/typescript/rules/typescript.js → config/configs/typescript/settings/typescript.mjs}
RENAMED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
/** @type {import('eslint').Linter.Config} */
|
|
2
|
+
|
|
3
|
+
const typeScriptSettings = {
|
|
2
4
|
settings: {
|
|
3
5
|
'import/resolver': {
|
|
4
6
|
node: {
|
|
@@ -6,5 +8,10 @@ module.exports = {
|
|
|
6
8
|
},
|
|
7
9
|
typescript: {},
|
|
8
10
|
},
|
|
11
|
+
react: {
|
|
12
|
+
version: 'detect',
|
|
13
|
+
},
|
|
9
14
|
},
|
|
10
15
|
};
|
|
16
|
+
|
|
17
|
+
export default typeScriptSettings;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* obj2 has priority over obj1
|
|
3
|
+
*
|
|
4
|
+
* Merges obj2 into obj1
|
|
5
|
+
*/
|
|
6
|
+
export function _deepMerge(obj1, obj2, doNotMergeInNulls = true) {
|
|
7
|
+
const output = { ...obj1 };
|
|
8
|
+
|
|
9
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
10
|
+
for (const key in obj2) {
|
|
11
|
+
if (Object.prototype.hasOwnProperty.call(obj2, key)) {
|
|
12
|
+
if (doNotMergeInNulls) {
|
|
13
|
+
if (
|
|
14
|
+
(obj2[key] === null || obj2[key] === undefined)
|
|
15
|
+
&& obj1[key] !== null
|
|
16
|
+
&& obj1[key] !== undefined
|
|
17
|
+
) {
|
|
18
|
+
// eslint-disable-next-line no-continue
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Check if both are arrays
|
|
24
|
+
if (Array.isArray(obj1[key]) && Array.isArray(obj2[key])) {
|
|
25
|
+
// Merge each element in the arrays
|
|
26
|
+
|
|
27
|
+
// We need the Array.from, map rather than a normal map because this handles holes in arrays properly. A simple .map would skip holes.
|
|
28
|
+
output[key] = Array.from(obj2[key], (item, index) => {
|
|
29
|
+
if (doNotMergeInNulls) {
|
|
30
|
+
if (
|
|
31
|
+
(item === undefined || item === null)
|
|
32
|
+
&& obj1[key][index] !== null
|
|
33
|
+
&& obj1[key][index] !== undefined
|
|
34
|
+
) {
|
|
35
|
+
return obj1[key][index];
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (typeof item === 'object' && !Array.isArray(item) && obj1[key][index]) {
|
|
40
|
+
// Deep merge for objects in arrays
|
|
41
|
+
// eslint-disable-next-line no-use-before-define
|
|
42
|
+
return deepMerge(obj1[key][index], item, doNotMergeInNulls);
|
|
43
|
+
}
|
|
44
|
+
return item;
|
|
45
|
+
});
|
|
46
|
+
} else if (typeof obj2[key] === 'object' && !Array.isArray(obj2[key]) && obj1[key]) {
|
|
47
|
+
// Existing behavior for objects
|
|
48
|
+
// eslint-disable-next-line no-use-before-define
|
|
49
|
+
output[key] = deepMerge(obj1[key], obj2[key], doNotMergeInNulls);
|
|
50
|
+
} else {
|
|
51
|
+
// Direct assignment for values
|
|
52
|
+
output[key] = obj2[key];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return output;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function deepMerge(...objs) {
|
|
61
|
+
return objs.reduce((acc, obj) => _deepMerge(acc, obj), {});
|
|
62
|
+
}
|
package/config/index.mjs
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import tseslint from 'typescript-eslint'
|
|
2
|
+
import { configs as regexpPluginConfigs } from 'eslint-plugin-regexp'
|
|
3
|
+
import reactExtends from './configs/react/index.mjs'
|
|
4
|
+
import jestExtends from './configs/jest/index.mjs'
|
|
5
|
+
import globals from 'globals'
|
|
6
|
+
import typescriptParser from '@typescript-eslint/parser'
|
|
7
|
+
import { deepMerge } from './deepMerge.mjs'
|
|
8
|
+
|
|
9
|
+
const baseRules = {
|
|
10
|
+
'class-methods-use-this': 'off',
|
|
11
|
+
curly: ['warn', 'all'],
|
|
12
|
+
'arrow-body-style': ['error', 'as-needed', {
|
|
13
|
+
requireReturnForObjectLiteral: false,
|
|
14
|
+
}],
|
|
15
|
+
'no-restricted-exports': ['warn', { restrictDefaultExports: { direct: true } }],
|
|
16
|
+
'no-console': 'warn',
|
|
17
|
+
'no-sparse-arrays': 'off',
|
|
18
|
+
'no-underscore-dangle': 'off',
|
|
19
|
+
'no-use-before-define': 'off',
|
|
20
|
+
'object-shorthand': 'warn',
|
|
21
|
+
'no-useless-escape': 'warn',
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const reactA11yRules = {
|
|
25
|
+
'jsx-a11y/anchor-is-valid': 'warn',
|
|
26
|
+
'jsx-a11y/control-has-associated-label': 'warn',
|
|
27
|
+
'jsx-a11y/no-static-element-interactions': 'warn',
|
|
28
|
+
'jsx-a11y/label-has-associated-control': 'warn',
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const typeScriptRules = {
|
|
32
|
+
'@typescript-eslint/no-use-before-define': 'off',
|
|
33
|
+
|
|
34
|
+
// Type-aware any rules:
|
|
35
|
+
'@typescript-eslint/no-unsafe-assignment': 'off',
|
|
36
|
+
'@typescript-eslint/no-unsafe-member-access': 'off',
|
|
37
|
+
'@typescript-eslint/no-unsafe-call': 'off',
|
|
38
|
+
'@typescript-eslint/no-unsafe-argument': 'off',
|
|
39
|
+
'@typescript-eslint/no-unsafe-return': 'off',
|
|
40
|
+
'@typescript-eslint/unbound-method': 'warn',
|
|
41
|
+
'@typescript-eslint/consistent-type-imports': 'warn',
|
|
42
|
+
'@typescript-eslint/no-explicit-any': 'warn',
|
|
43
|
+
// Type-aware any rules end
|
|
44
|
+
|
|
45
|
+
// ts-expect preferred over ts-ignore. It will error if the expected error is no longer present.
|
|
46
|
+
'@typescript-eslint/ban-ts-comment': 'warn', // Recommended over deprecated @typescript-eslint/prefer-ts-expect-error: https://github.com/typescript-eslint/typescript-eslint/issues/8333. Set to warn to ease migration.
|
|
47
|
+
// By default, it errors for unused variables. This is annoying, warnings are enough.
|
|
48
|
+
'@typescript-eslint/no-unused-vars': [
|
|
49
|
+
'warn',
|
|
50
|
+
{
|
|
51
|
+
vars: 'all',
|
|
52
|
+
args: 'after-used',
|
|
53
|
+
ignoreRestSiblings: false,
|
|
54
|
+
argsIgnorePattern: '^_',
|
|
55
|
+
varsIgnorePattern: '^_',
|
|
56
|
+
destructuredArrayIgnorePattern: '^_',
|
|
57
|
+
caughtErrorsIgnorePattern: '^(_|ignore)',
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
'@typescript-eslint/no-base-to-string': 'warn',
|
|
61
|
+
'@typescript-eslint/restrict-template-expressions': 'warn',
|
|
62
|
+
'@typescript-eslint/no-redundant-type-constituents': 'warn',
|
|
63
|
+
'@typescript-eslint/no-unnecessary-type-constraint': 'warn',
|
|
64
|
+
'@typescript-eslint/no-misused-promises': [
|
|
65
|
+
'error',
|
|
66
|
+
{
|
|
67
|
+
// See https://github.com/typescript-eslint/typescript-eslint/issues/4619 and https://github.com/typescript-eslint/typescript-eslint/pull/4623
|
|
68
|
+
// Don't want something like <button onClick={someAsyncFunction}> to error
|
|
69
|
+
checksVoidReturn: {
|
|
70
|
+
attributes: false,
|
|
71
|
+
arguments: false,
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
'@typescript-eslint/no-empty-object-type': 'warn',
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** @typedef {import('eslint').Linter.Config} Config */
|
|
79
|
+
|
|
80
|
+
/** @type {FlatConfig} */
|
|
81
|
+
const baseExtends = deepMerge(
|
|
82
|
+
regexpPluginConfigs['flat/recommended'],
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
/** @type {Config[]} */
|
|
86
|
+
export const rootEslintConfig = [
|
|
87
|
+
{
|
|
88
|
+
name: 'Settings',
|
|
89
|
+
languageOptions: {
|
|
90
|
+
parserOptions: {
|
|
91
|
+
ecmaFeatures: {
|
|
92
|
+
jsx: true,
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
ecmaVersion: 'latest',
|
|
96
|
+
sourceType: 'module',
|
|
97
|
+
globals: {
|
|
98
|
+
...globals.node
|
|
99
|
+
},
|
|
100
|
+
parser: typescriptParser,
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: 'TypeScript',
|
|
105
|
+
// has 3 entries: https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/src/configs/recommended-type-checked.ts
|
|
106
|
+
...deepMerge(
|
|
107
|
+
baseExtends,
|
|
108
|
+
tseslint.configs.recommendedTypeCheckedOnly[0],
|
|
109
|
+
tseslint.configs.recommendedTypeCheckedOnly[1],
|
|
110
|
+
tseslint.configs.recommendedTypeCheckedOnly[2],
|
|
111
|
+
{
|
|
112
|
+
rules: {
|
|
113
|
+
...baseRules,
|
|
114
|
+
...typeScriptRules,
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
),
|
|
118
|
+
files: ['**/*.ts'],
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: 'TypeScript-React',
|
|
122
|
+
...deepMerge(
|
|
123
|
+
baseExtends,
|
|
124
|
+
tseslint.configs.recommendedTypeCheckedOnly[0],
|
|
125
|
+
tseslint.configs.recommendedTypeCheckedOnly[1],
|
|
126
|
+
tseslint.configs.recommendedTypeCheckedOnly[2],
|
|
127
|
+
reactExtends,
|
|
128
|
+
{
|
|
129
|
+
rules: {
|
|
130
|
+
...baseRules,
|
|
131
|
+
...typeScriptRules,
|
|
132
|
+
...reactA11yRules,
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
),
|
|
136
|
+
files: ['**/*.tsx'],
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
name: 'Unit Tests',
|
|
140
|
+
...deepMerge(jestExtends, {
|
|
141
|
+
rules: {
|
|
142
|
+
...baseRules,
|
|
143
|
+
...typeScriptRules,
|
|
144
|
+
}
|
|
145
|
+
}),
|
|
146
|
+
files: ['**/*.test.ts', '**/*.test.tsx'],
|
|
147
|
+
}
|
|
148
|
+
]
|
|
149
|
+
|
|
150
|
+
export default rootEslintConfig
|
package/demo/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './components';
|
package/eslint.config.mjs
CHANGED
|
@@ -1,35 +1,44 @@
|
|
|
1
|
-
|
|
2
|
-
import { fileURLToPath } from 'node:url';
|
|
3
|
-
import { FlatCompat } from '@eslint/eslintrc';
|
|
4
|
-
import tsParser from '@typescript-eslint/parser';
|
|
5
|
-
import js from '@eslint/js';
|
|
1
|
+
/** @typedef {import('eslint').Linter.Config} Config */
|
|
6
2
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
baseDirectory: __dirname,
|
|
12
|
-
recommendedConfig: js.configs.recommended,
|
|
13
|
-
});
|
|
3
|
+
import baseConfig from './config/configs/base/index.mjs';
|
|
4
|
+
import reactConfig from './config/configs/react/index.mjs';
|
|
5
|
+
import typescriptConfig from './config/configs/typescript/index.mjs';
|
|
6
|
+
import jestConfig from './config/configs/jest/index.mjs';
|
|
14
7
|
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
8
|
+
export const defaultESLintIgnores = [
|
|
9
|
+
'**/.temp',
|
|
10
|
+
'**/.*',
|
|
11
|
+
'**/.git',
|
|
12
|
+
'**/.hg',
|
|
13
|
+
'**/.pnp.*',
|
|
14
|
+
'**/jest.config.js',
|
|
15
|
+
'**/tsconfig.tsbuildinfo',
|
|
16
|
+
'**/README.md',
|
|
17
|
+
'**/payload-types.ts',
|
|
18
|
+
'**/dist/',
|
|
19
|
+
'**/.yarn/',
|
|
20
|
+
'**/build/',
|
|
21
|
+
'**/node_modules/',
|
|
22
|
+
'**/temp/',
|
|
23
|
+
'next-env.d.ts',
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
/** @type {Config[]} */
|
|
27
|
+
export const rootEslintConfig = [
|
|
28
|
+
baseConfig,
|
|
29
|
+
reactConfig,
|
|
30
|
+
typescriptConfig,
|
|
31
|
+
jestConfig,
|
|
32
|
+
{
|
|
33
|
+
ignores: [
|
|
34
|
+
...defaultESLintIgnores,
|
|
35
|
+
],
|
|
26
36
|
},
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
node: {
|
|
30
|
-
extensions: ['.mjs', '.js', '.jsx', '.ts', '.tsx', '.json'],
|
|
31
|
-
},
|
|
32
|
-
typescript: {},
|
|
33
|
-
},
|
|
37
|
+
{
|
|
38
|
+
files: [`**/*.{js,jsx,ts,tsx}`],
|
|
34
39
|
},
|
|
35
|
-
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
export default [
|
|
43
|
+
...rootEslintConfig,
|
|
44
|
+
];
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@innovixx/eslint-config",
|
|
3
|
-
"version": "
|
|
4
|
-
"main": "configs/index.
|
|
5
|
-
"repository": "git@github.com:
|
|
3
|
+
"version": "3.0.0-alpha.2",
|
|
4
|
+
"main": "configs/index.mjs",
|
|
5
|
+
"repository": "git@github.com:innovixx/eslint-config.git",
|
|
6
6
|
"description": "Opinionated ESLint config for JavaScript developers",
|
|
7
7
|
"author": "service@innovixx.co.uk",
|
|
8
8
|
"license": "MIT",
|
|
@@ -12,27 +12,37 @@
|
|
|
12
12
|
"eslint-config",
|
|
13
13
|
"style-guide"
|
|
14
14
|
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"lint": "eslint demo/**/*.{js,jsx,ts,tsx}"
|
|
17
|
+
},
|
|
15
18
|
"dependencies": {
|
|
16
|
-
"@eslint/
|
|
17
|
-
"@eslint/js": "9.
|
|
18
|
-
"@
|
|
19
|
-
"@
|
|
20
|
-
"
|
|
21
|
-
"
|
|
19
|
+
"@eslint-react/eslint-plugin": "1.16.1",
|
|
20
|
+
"@eslint/js": "9.19.0",
|
|
21
|
+
"@types/eslint": "9.6.1",
|
|
22
|
+
"@types/eslint__js": "8.42.3",
|
|
23
|
+
"@types/node": "^22.12.0",
|
|
24
|
+
"@types/react": "^19.0.8",
|
|
25
|
+
"@types/react-dom": "^19.0.3",
|
|
26
|
+
"@typescript-eslint/eslint-plugin": "^8.23.0",
|
|
27
|
+
"@typescript-eslint/parser": "^8.23.0",
|
|
28
|
+
"eslint": "9.19.0",
|
|
22
29
|
"eslint-plugin-import": "^2.31.0",
|
|
23
30
|
"eslint-plugin-jest": "^28.11.0",
|
|
24
31
|
"eslint-plugin-jest-dom": "^5.5.0",
|
|
25
32
|
"eslint-plugin-jsx-a11y": "^6.10.2",
|
|
26
|
-
"eslint-plugin-node": "^11.1.0",
|
|
27
33
|
"eslint-plugin-react": "^7.37.4",
|
|
28
34
|
"eslint-plugin-react-hooks": "^5.1.0",
|
|
29
35
|
"eslint-plugin-react-refresh": "^0.4.18",
|
|
36
|
+
"eslint-plugin-regexp": "2.6.0",
|
|
30
37
|
"eslint-plugin-sort-export-all": "^1.4.1",
|
|
31
38
|
"eslint-plugin-sort-keys-fix": "^1.1.2",
|
|
32
|
-
"
|
|
33
|
-
"
|
|
39
|
+
"globals": "15.12.0",
|
|
40
|
+
"react": "^19.0.0",
|
|
41
|
+
"react-dom": "^19.0.0",
|
|
42
|
+
"typescript": "5.7.3",
|
|
43
|
+
"typescript-eslint": "8.23.0"
|
|
34
44
|
},
|
|
35
45
|
"devDependencies": {
|
|
36
|
-
"
|
|
46
|
+
"eslint-import-resolver-typescript": "^3.7.0"
|
|
37
47
|
}
|
|
38
48
|
}
|
package/configs/base/index.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
plugins: [
|
|
3
|
-
'node',
|
|
4
|
-
'eslint-plugin-sort-export-all',
|
|
5
|
-
'eslint-plugin-sort-keys-fix',
|
|
6
|
-
],
|
|
7
|
-
env: {
|
|
8
|
-
node: true,
|
|
9
|
-
},
|
|
10
|
-
extends: [
|
|
11
|
-
'./rules/best-practices',
|
|
12
|
-
'./rules/errors',
|
|
13
|
-
'./rules/es6',
|
|
14
|
-
'./rules/imports',
|
|
15
|
-
'./rules/style',
|
|
16
|
-
'./rules/variables',
|
|
17
|
-
].map(require.resolve),
|
|
18
|
-
rules: {},
|
|
19
|
-
};
|
package/configs/index.js
DELETED
package/configs/jest/index.js
DELETED
package/configs/react/index.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
env: {
|
|
3
|
-
browser: true,
|
|
4
|
-
},
|
|
5
|
-
plugins: [
|
|
6
|
-
'jsx-a11y',
|
|
7
|
-
'react-hooks',
|
|
8
|
-
'react',
|
|
9
|
-
'eslint-plugin-react-refresh',
|
|
10
|
-
],
|
|
11
|
-
settings: {
|
|
12
|
-
react: {
|
|
13
|
-
version: 'detect',
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
extends: [
|
|
17
|
-
'./rules/react-a11y',
|
|
18
|
-
'./rules/react-hooks',
|
|
19
|
-
'./rules/react',
|
|
20
|
-
].map(require.resolve),
|
|
21
|
-
rules: {},
|
|
22
|
-
};
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
rules: {
|
|
3
|
-
// Enforce Rules of Hooks
|
|
4
|
-
// https://github.com/facebook/react/blob/c11015ff4f610ac2924d1fc6d569a17657a404fd/packages/eslint-plugin-react-hooks/src/RulesOfHooks.js
|
|
5
|
-
'react-hooks/rules-of-hooks': 'error',
|
|
6
|
-
|
|
7
|
-
// Verify the list of the dependencies for Hooks like useEffect and similar
|
|
8
|
-
// https://github.com/facebook/react/blob/1204c789776cb01fbaf3e9f032e7e2ba85a44137/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js
|
|
9
|
-
'react-hooks/exhaustive-deps': 'error',
|
|
10
|
-
},
|
|
11
|
-
};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
plugins: ['@typescript-eslint'],
|
|
3
|
-
extends: [
|
|
4
|
-
'./rules/typescript',
|
|
5
|
-
'./rules/variables',
|
|
6
|
-
'plugin:@typescript-eslint/recommended',
|
|
7
|
-
].map((requirePath) => {
|
|
8
|
-
if (requirePath.startsWith('./')) {
|
|
9
|
-
return require.resolve(requirePath);
|
|
10
|
-
}
|
|
11
|
-
return requirePath;
|
|
12
|
-
}),
|
|
13
|
-
rules: {},
|
|
14
|
-
};
|