@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.
- package/CHANGELOG.md +737 -0
- package/LICENSE +24 -0
- package/README.md +34 -0
- package/package.json +62 -0
- package/src/bin/eslint.cjs +11 -0
- package/src/configs/eslint-base.js +124 -0
- package/src/configs/eslint-complexity.js +28 -0
- package/src/configs/eslint-ignores.js +51 -0
- package/src/configs/eslint-recommended.js +9 -0
- package/src/configs/eslint-style.js +23 -0
- package/src/custom/index.js +11 -0
- package/src/custom/instance-of-array.js +72 -0
- package/src/custom/loose-types.js +204 -0
- package/src/custom/no-useless-expression.js +28 -0
- package/src/custom/sequence-expression.js +21 -0
- package/src/index.js +86 -0
- package/src/plugins/eslint-comments.js +27 -0
- package/src/plugins/import.js +139 -0
- package/src/plugins/jest.js +124 -0
- package/src/plugins/jsdoc.js +70 -0
- package/src/plugins/json.js +37 -0
- package/src/plugins/jsx-a11y.js +100 -0
- package/src/plugins/node.js +129 -0
- package/src/plugins/promise.js +16 -0
- package/src/plugins/react.js +128 -0
- package/src/plugins/regexp.js +13 -0
- package/src/plugins/sca.js +41 -0
- package/src/plugins/security.js +15 -0
- package/src/plugins/sonarjs.js +28 -0
- package/src/plugins/style.js +249 -0
- package/src/plugins/typescript.js +87 -0
- package/src/plugins/unicorn.js +58 -0
- package/src/plugins/unused-imports.js +52 -0
- package/src/types.d.ts +118 -0
- package/src/utilities/editorconfig.js +210 -0
- package/src/utilities/eslint-files.js +65 -0
- package/src/utilities/expand-glob.js +49 -0
- package/src/utilities/filesystem.js +73 -0
- package/src/utilities/make-compat.js +17 -0
- 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
|
+
}
|