@foray1010/eslint-config 9.2.0 → 10.0.1
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 +30 -0
- package/README.md +69 -41
- package/bases/base.mjs +382 -0
- package/bases/browser.mjs +47 -0
- package/bases/ignores.mjs +14 -0
- package/bases/node.mjs +75 -0
- package/bases/prettier.mjs +18 -0
- package/bases/react.mjs +92 -0
- package/constants.mjs +15 -0
- package/index.mjs +31 -0
- package/package.json +21 -22
- package/tsconfig.json +1 -1
- package/utils/applyConfig.mjs +62 -0
- package/eslintignore +0 -6
- package/index.cjs +0 -6
- package/presets/base.cjs +0 -364
- package/presets/browser.cjs +0 -22
- package/presets/node.cjs +0 -61
- package/presets/react.cjs +0 -84
- package/presets/utils/testUtil.cjs +0 -9
- package/react.cjs +0 -9
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import eslintConfigPrettier from 'eslint-config-prettier'
|
|
2
|
+
// eslint-disable-next-line import/namespace, import/no-named-as-default, import/no-named-as-default-member
|
|
3
|
+
import eslintPluginPrettier from 'eslint-plugin-prettier'
|
|
4
|
+
|
|
5
|
+
/** @type {import('eslint').Linter.FlatConfig[]} */
|
|
6
|
+
const prettierConfig = [
|
|
7
|
+
// should be placed at the end to override other configs
|
|
8
|
+
{
|
|
9
|
+
plugins: {
|
|
10
|
+
prettier: eslintPluginPrettier,
|
|
11
|
+
},
|
|
12
|
+
rules: {
|
|
13
|
+
...eslintConfigPrettier.rules,
|
|
14
|
+
...eslintPluginPrettier.configs['recommended']?.rules,
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
]
|
|
18
|
+
export default prettierConfig
|
package/bases/react.mjs
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import eslintPluginReact from 'eslint-plugin-react'
|
|
2
|
+
import eslintPluginReactHooks from 'eslint-plugin-react-hooks'
|
|
3
|
+
import eslintPluginTestingLibrary from 'eslint-plugin-testing-library'
|
|
4
|
+
|
|
5
|
+
import { testFileGlobs } from '../constants.mjs'
|
|
6
|
+
|
|
7
|
+
/** @type {import('eslint').Linter.FlatConfig[]} */
|
|
8
|
+
const reactConfig = [
|
|
9
|
+
{
|
|
10
|
+
languageOptions: {
|
|
11
|
+
parserOptions: {
|
|
12
|
+
ecmaFeatures: {
|
|
13
|
+
jsx: true,
|
|
14
|
+
},
|
|
15
|
+
// copied from `eslintPluginReact.configs['jsx-runtime']`
|
|
16
|
+
jsxPragma: null, // for @typescript-eslint/parser
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
settings: {
|
|
20
|
+
react: {
|
|
21
|
+
version: 'detect',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
plugins: {
|
|
25
|
+
react: eslintPluginReact,
|
|
26
|
+
'react-hooks': eslintPluginReactHooks,
|
|
27
|
+
},
|
|
28
|
+
rules: {
|
|
29
|
+
...eslintPluginReact.configs['recommended']?.rules,
|
|
30
|
+
...eslintPluginReact.configs['jsx-runtime']?.rules,
|
|
31
|
+
...eslintPluginReactHooks.configs['recommended']?.rules,
|
|
32
|
+
// avoid unexpected form submits
|
|
33
|
+
'react/button-has-type': 'error',
|
|
34
|
+
'react/jsx-no-useless-fragment': [
|
|
35
|
+
'error',
|
|
36
|
+
{
|
|
37
|
+
// allow unnecessary fragment for single expression to bypass some typescript errors (e.g. do not allow string and only allow react element)
|
|
38
|
+
allowExpressions: true,
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
'react/jsx-sort-props': [
|
|
42
|
+
'error',
|
|
43
|
+
{
|
|
44
|
+
// any prop starts with `on`
|
|
45
|
+
callbacksLast: true,
|
|
46
|
+
ignoreCase: true,
|
|
47
|
+
noSortAlphabetically: false,
|
|
48
|
+
reservedFirst: true,
|
|
49
|
+
shorthandFirst: false,
|
|
50
|
+
shorthandLast: false,
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
// rely on typescript instead, and it does not work well with types that are imported from elsewhere
|
|
54
|
+
'react/prop-types': 'off',
|
|
55
|
+
// avoid unnecessary closing tags
|
|
56
|
+
'react/self-closing-comp': 'error',
|
|
57
|
+
'react-hooks/exhaustive-deps': [
|
|
58
|
+
'error',
|
|
59
|
+
{
|
|
60
|
+
// support package `use-deep-compare`
|
|
61
|
+
additionalHooks:
|
|
62
|
+
'(useDeepCompareCallback|useDeepCompareEffect|useDeepCompareMemo)',
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
files: testFileGlobs,
|
|
69
|
+
plugins: {
|
|
70
|
+
'testing-library': eslintPluginTestingLibrary,
|
|
71
|
+
},
|
|
72
|
+
rules: {
|
|
73
|
+
...eslintPluginTestingLibrary.configs['react']?.rules,
|
|
74
|
+
// avoid using unnecessary `await` as workaround for `not wrapped in act(...)` warnings
|
|
75
|
+
'testing-library/no-await-sync-events': [
|
|
76
|
+
'error',
|
|
77
|
+
{
|
|
78
|
+
eventModules: ['fire-event'],
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
// global flag /g holds state and might cause false-positives while querying for elements
|
|
82
|
+
'testing-library/no-global-regexp-flag-in-query': 'error',
|
|
83
|
+
// explicitly assert the element to prevent reader missed the test cases
|
|
84
|
+
'testing-library/prefer-explicit-assert': 'error',
|
|
85
|
+
// prefer @testing-library/user-event over fireEvent
|
|
86
|
+
'testing-library/prefer-user-event': 'error',
|
|
87
|
+
// as `wait` is deprecated
|
|
88
|
+
'testing-library/prefer-wait-for': 'error',
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
]
|
|
92
|
+
export default reactConfig
|
package/constants.mjs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const supportedFilesGlob = '**/*.{cjs,cts,js,mjs,mts,ts,tsx}'
|
|
2
|
+
export const testFileGlobs = [
|
|
3
|
+
'**/__fixtures__/**/*.{cjs,cts,js,mjs,mts,ts,tsx}',
|
|
4
|
+
'**/__mocks__/**/*.{cjs,cts,js,mjs,mts,ts,tsx}',
|
|
5
|
+
'**/__tests__/**/*.{cjs,cts,js,mjs,mts,ts,tsx}',
|
|
6
|
+
'**/*.{spec,test}.{cjs,cts,js,mjs,mts,ts,tsx}',
|
|
7
|
+
]
|
|
8
|
+
|
|
9
|
+
export const typeScriptFileGlobs = ['**/*.{cts,mts,ts,tsx}']
|
|
10
|
+
export const typeScriptTestFileGlobs = [
|
|
11
|
+
'**/__fixtures__/**/*.{cts,mts,ts,tsx}',
|
|
12
|
+
'**/__mocks__/**/*.{cts,mts,ts,tsx}',
|
|
13
|
+
'**/__tests__/**/*.{cts,mts,ts,tsx}',
|
|
14
|
+
'**/*.{spec,test}.{cts,mts,ts,tsx}',
|
|
15
|
+
]
|
package/index.mjs
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import baseConfig from './bases/base.mjs'
|
|
2
|
+
import browserConfig from './bases/browser.mjs'
|
|
3
|
+
import nodeConfig from './bases/node.mjs'
|
|
4
|
+
import prettierConfig from './bases/prettier.mjs'
|
|
5
|
+
import reactConfig from './bases/react.mjs'
|
|
6
|
+
|
|
7
|
+
export * from './utils/applyConfig.mjs'
|
|
8
|
+
|
|
9
|
+
/** @type {readonly import('eslint').Linter.FlatConfig[]} */
|
|
10
|
+
export const eslintBrowserConfig = [
|
|
11
|
+
...baseConfig,
|
|
12
|
+
...browserConfig,
|
|
13
|
+
...prettierConfig,
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
/** @type {readonly import('eslint').Linter.FlatConfig[]} */
|
|
17
|
+
export const eslintNodeConfig = [
|
|
18
|
+
...baseConfig,
|
|
19
|
+
...nodeConfig,
|
|
20
|
+
...prettierConfig,
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
/** @type {readonly import('eslint').Linter.FlatConfig[]} */
|
|
24
|
+
export const eslintReactConfig = [
|
|
25
|
+
...baseConfig,
|
|
26
|
+
...browserConfig,
|
|
27
|
+
...reactConfig,
|
|
28
|
+
...prettierConfig,
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
export { default as eslintIgnoresConfig } from './bases/ignores.mjs'
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "@foray1010/eslint-config",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "10.0.1",
|
|
5
5
|
"homepage": "https://github.com/foray1010/common-presets/tree/master/packages/eslint-config#readme",
|
|
6
6
|
"bugs": "https://github.com/foray1010/common-presets/issues",
|
|
7
7
|
"repository": {
|
|
@@ -10,54 +10,53 @@
|
|
|
10
10
|
"directory": "packages/eslint-config"
|
|
11
11
|
},
|
|
12
12
|
"license": "MIT",
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
"./react": "./react.cjs"
|
|
16
|
-
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"exports": "./index.mjs",
|
|
17
15
|
"files": [
|
|
18
16
|
"**/*.{cjs,js,json,mjs}",
|
|
19
|
-
"*.md"
|
|
20
|
-
"eslintignore"
|
|
17
|
+
"*.md"
|
|
21
18
|
],
|
|
22
19
|
"scripts": {
|
|
23
20
|
"type:check": "tsc"
|
|
24
21
|
},
|
|
25
22
|
"dependencies": {
|
|
26
|
-
"@
|
|
27
|
-
"@
|
|
28
|
-
"@
|
|
23
|
+
"@eslint-community/eslint-plugin-eslint-comments": "^3.2.1",
|
|
24
|
+
"@eslint/js": "^8.36.0",
|
|
25
|
+
"@foray1010/common-presets-utils": "^7.0.0",
|
|
26
|
+
"@typescript-eslint/eslint-plugin": "^5.56.0",
|
|
27
|
+
"@typescript-eslint/parser": "^5.56.0",
|
|
29
28
|
"confusing-browser-globals": "^1.0.10",
|
|
30
|
-
"eslint-config-prettier": "^8.
|
|
29
|
+
"eslint-config-prettier": "^8.8.0",
|
|
31
30
|
"eslint-import-resolver-typescript": "^3.5.2",
|
|
32
|
-
"eslint-plugin-compat": "^4.
|
|
31
|
+
"eslint-plugin-compat": "^4.1.2",
|
|
33
32
|
"eslint-plugin-deprecation": "^1.3.2",
|
|
34
|
-
"eslint-plugin-
|
|
35
|
-
"eslint-plugin-functional": "^4.4.1",
|
|
33
|
+
"eslint-plugin-functional": "^5.0.0",
|
|
36
34
|
"eslint-plugin-import": "^2.22.1",
|
|
37
35
|
"eslint-plugin-jest": "^27.1.3",
|
|
38
36
|
"eslint-plugin-jest-dom": "^4.0.0",
|
|
39
|
-
"eslint-plugin-jsdoc": "^40.
|
|
37
|
+
"eslint-plugin-jsdoc": "^40.1.0",
|
|
40
38
|
"eslint-plugin-n": "^15.3.0",
|
|
41
39
|
"eslint-plugin-prettier": "^4.0.0",
|
|
42
|
-
"eslint-plugin-react": "^7.
|
|
40
|
+
"eslint-plugin-react": "^7.32.2",
|
|
43
41
|
"eslint-plugin-react-hooks": "^4.2.0",
|
|
44
42
|
"eslint-plugin-simple-import-sort": "^10.0.0",
|
|
45
|
-
"eslint-plugin-testing-library": "^5.
|
|
46
|
-
"eslint-plugin-unicorn": "^
|
|
43
|
+
"eslint-plugin-testing-library": "^5.10.2",
|
|
44
|
+
"eslint-plugin-unicorn": "^46.0.0",
|
|
45
|
+
"globals": "^13.19.0"
|
|
47
46
|
},
|
|
48
47
|
"devDependencies": {
|
|
49
48
|
"@types/confusing-browser-globals": "1.0.0",
|
|
50
|
-
"@types/eslint": "8.21.
|
|
49
|
+
"@types/eslint": "8.21.3"
|
|
51
50
|
},
|
|
52
51
|
"peerDependencies": {
|
|
53
|
-
"eslint": "^8.
|
|
52
|
+
"eslint": "^8.36.0",
|
|
54
53
|
"prettier": "^2.0.0"
|
|
55
54
|
},
|
|
56
55
|
"engines": {
|
|
57
|
-
"node": "^
|
|
56
|
+
"node": "^16.14.0 || >=18.12.0"
|
|
58
57
|
},
|
|
59
58
|
"publishConfig": {
|
|
60
59
|
"access": "public"
|
|
61
60
|
},
|
|
62
|
-
"gitHead": "
|
|
61
|
+
"gitHead": "c722884bc466360097d9ab80e72f350a15ed7cad"
|
|
63
62
|
}
|
package/tsconfig.json
CHANGED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
|
|
3
|
+
import { supportedFilesGlob } from '../constants.mjs'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Extend the flat configs with default files and ignores
|
|
7
|
+
* @param {{
|
|
8
|
+
* readonly filePrefixes: string | string[],
|
|
9
|
+
* readonly ignores?: string | string[] | undefined
|
|
10
|
+
* }} options
|
|
11
|
+
* @param {readonly import('eslint').Linter.FlatConfig[]} flatConfigs
|
|
12
|
+
* @returns {readonly import('eslint').Linter.FlatConfig[]}
|
|
13
|
+
*/
|
|
14
|
+
export function applyConfig(options, flatConfigs) {
|
|
15
|
+
const filePrefixes = [options.filePrefixes].flat()
|
|
16
|
+
if (filePrefixes.length === 0) {
|
|
17
|
+
throw new TypeError('filePrefixes must not be empty')
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Do not allow string such as "eslint:recommended" because it cannot be overridden by files/ignores
|
|
21
|
+
for (const config of flatConfigs) {
|
|
22
|
+
if (typeof config === 'string') {
|
|
23
|
+
throw new TypeError(
|
|
24
|
+
`Cannot extend ${config} with files/ignores, use \`@eslint/js\` instead`,
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (Object.keys(config).includes('ignores')) {
|
|
29
|
+
throw new TypeError('Do not use `ignores` in config')
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return flatConfigs.map((config) => {
|
|
34
|
+
const files = generateCombinations(filePrefixes, config.files)
|
|
35
|
+
return {
|
|
36
|
+
...config,
|
|
37
|
+
...(files ? { files } : {}),
|
|
38
|
+
...(options.ignores ? { ignores: options.ignores } : {}),
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @param {string[]} prefixes
|
|
45
|
+
* @param {string | string[] | undefined} originalGlobs
|
|
46
|
+
* @returns {string | string[] | undefined}
|
|
47
|
+
*/
|
|
48
|
+
function generateCombinations(prefixes, originalGlobs) {
|
|
49
|
+
if (!originalGlobs || originalGlobs.length === 0) {
|
|
50
|
+
return prefixes.map((prefix) => path.join(prefix, supportedFilesGlob))
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const originalGlobList = [originalGlobs].flat()
|
|
54
|
+
|
|
55
|
+
return prefixes.flatMap((prefix) => {
|
|
56
|
+
return originalGlobList.flatMap((originalGlob) => {
|
|
57
|
+
const signRegexp = /^!/
|
|
58
|
+
const sign = originalGlob.match(signRegexp)?.[0] ?? ''
|
|
59
|
+
return sign + path.join(prefix, originalGlob.replace(signRegexp, ''))
|
|
60
|
+
})
|
|
61
|
+
})
|
|
62
|
+
}
|
package/eslintignore
DELETED