@foray1010/eslint-config 9.2.0 → 10.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/CHANGELOG.md +23 -0
- package/README.md +85 -41
- package/bases/base.mjs +379 -0
- package/bases/browser.mjs +47 -0
- package/bases/files.mjs +8 -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/{presets/utils/testUtil.cjs → constants.mjs} +3 -4
- package/index.mjs +32 -0
- package/package.json +21 -22
- package/tsconfig.json +1 -1
- package/utils/applyConfig.mjs +61 -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/react.cjs +0 -9
package/bases/node.mjs
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// @ts-expect-error
|
|
2
|
+
import { isESM } from '@foray1010/common-presets-utils'
|
|
3
|
+
import eslintPluginN from 'eslint-plugin-n'
|
|
4
|
+
|
|
5
|
+
/** @type {import('eslint').Linter.FlatConfig} */
|
|
6
|
+
const cjsConfig = {
|
|
7
|
+
languageOptions: {
|
|
8
|
+
globals: {
|
|
9
|
+
// @ts-expect-error
|
|
10
|
+
__dirname: 'readonly',
|
|
11
|
+
// @ts-expect-error
|
|
12
|
+
__filename: 'readonly',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** @type {import('eslint').Linter.FlatConfig[]} */
|
|
18
|
+
const nodeConfig = [
|
|
19
|
+
{
|
|
20
|
+
plugins: {
|
|
21
|
+
n: eslintPluginN,
|
|
22
|
+
},
|
|
23
|
+
languageOptions: {
|
|
24
|
+
globals: {
|
|
25
|
+
// hack to mute no-undef error, and show n/prefer-global/buffer error instead
|
|
26
|
+
// @ts-expect-error
|
|
27
|
+
Buffer: 'writable',
|
|
28
|
+
// hack to mute no-undef error, and show n/prefer-global/process error instead
|
|
29
|
+
// @ts-expect-error
|
|
30
|
+
process: 'writable',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
rules: {
|
|
34
|
+
// disallow deprecated node APIs
|
|
35
|
+
'n/no-deprecated-api': 'error',
|
|
36
|
+
// disallow the assignment to `exports`
|
|
37
|
+
'n/no-exports-assign': 'error',
|
|
38
|
+
// disallow `bin` files that npm ignores
|
|
39
|
+
'n/no-unpublished-bin': 'error',
|
|
40
|
+
// disallow unsupported Node.js built-in APIs on the specified version
|
|
41
|
+
'n/no-unsupported-features/node-builtins': 'error',
|
|
42
|
+
// prefer `import { Buffer } from 'node:buffer'` as it is not isomorphic
|
|
43
|
+
'n/prefer-global/buffer': ['error', 'never'],
|
|
44
|
+
// prefer global `console` to be isomorphic
|
|
45
|
+
'n/prefer-global/console': ['error', 'always'],
|
|
46
|
+
// prefer `import process from 'node:process'` as it is not isomorphic
|
|
47
|
+
'n/prefer-global/process': ['error', 'never'],
|
|
48
|
+
// prefer global `TextDecoder` to be isomorphic
|
|
49
|
+
'n/prefer-global/text-decoder': ['error', 'always'],
|
|
50
|
+
// prefer global `TextEncoder` to be isomorphic
|
|
51
|
+
'n/prefer-global/text-encoder': ['error', 'always'],
|
|
52
|
+
// prefer global `URL` to be isomorphic
|
|
53
|
+
'n/prefer-global/url': ['error', 'always'],
|
|
54
|
+
// prefer global `URLSearchParams` to be isomorphic
|
|
55
|
+
'n/prefer-global/url-search-params': ['error', 'always'],
|
|
56
|
+
// make `process.exit()` expressions the same code path as `throw`
|
|
57
|
+
'n/process-exit-as-throw': 'error',
|
|
58
|
+
// enforce shebang on the entry bin file
|
|
59
|
+
'n/shebang': 'error',
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
...(isESM()
|
|
63
|
+
? []
|
|
64
|
+
: [
|
|
65
|
+
{
|
|
66
|
+
files: ['**/*.js'],
|
|
67
|
+
...cjsConfig,
|
|
68
|
+
},
|
|
69
|
+
]),
|
|
70
|
+
{
|
|
71
|
+
files: ['**/*.{cjs,cts}'],
|
|
72
|
+
...cjsConfig,
|
|
73
|
+
},
|
|
74
|
+
]
|
|
75
|
+
export default nodeConfig
|
|
@@ -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
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const testFileGlobs = [
|
|
1
|
+
export const testFileGlobs = [
|
|
4
2
|
'**/__fixtures__/**',
|
|
5
3
|
'**/__mocks__/**',
|
|
6
4
|
'**/__tests__/**',
|
|
7
5
|
'**/*.{spec,test}.{cjs,cts,js,mjs,mts,ts,tsx}',
|
|
8
6
|
]
|
|
9
|
-
|
|
7
|
+
|
|
8
|
+
export const typeScriptFileGlobs = ['**/*.{cts,mts,ts,tsx}']
|
package/index.mjs
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
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 eslintFilesConfig } from './bases/files.mjs'
|
|
32
|
+
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.0",
|
|
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": "ee22f073ee1702354310091b7c3a5ec18a930bec"
|
|
63
62
|
}
|
package/tsconfig.json
CHANGED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Extend the flat configs with default files and ignores
|
|
5
|
+
* @param {{
|
|
6
|
+
* readonly filePrefixes?: string[] | undefined,
|
|
7
|
+
* readonly ignorePrefixes?: string[] | undefined
|
|
8
|
+
* }} options
|
|
9
|
+
* @param {readonly import('eslint').Linter.FlatConfig[]} flatConfigs
|
|
10
|
+
* @returns {readonly import('eslint').Linter.FlatConfig[]}
|
|
11
|
+
*/
|
|
12
|
+
export function applyConfig(options, flatConfigs) {
|
|
13
|
+
// Do not allow string such as "eslint:recommended" because it cannot be overridden by files/ignores
|
|
14
|
+
for (const config of flatConfigs) {
|
|
15
|
+
if (typeof config === 'string') {
|
|
16
|
+
throw new TypeError(
|
|
17
|
+
`Cannot extend ${config} with files/ignores, use \`@eslint/js\` instead`,
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const keys = Object.keys(config)
|
|
22
|
+
if (
|
|
23
|
+
keys.length === 1 &&
|
|
24
|
+
(keys.includes('files') || keys.includes('ignores'))
|
|
25
|
+
) {
|
|
26
|
+
throw new TypeError('Do not use `files` or `ignores` only')
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return flatConfigs.map((config) => {
|
|
31
|
+
const files = generateCombinations(options.filePrefixes, config.files)
|
|
32
|
+
const ignores = generateCombinations(options.ignorePrefixes, config.ignores)
|
|
33
|
+
return {
|
|
34
|
+
...config,
|
|
35
|
+
...(files ? { files } : {}),
|
|
36
|
+
...(ignores ? { ignores } : {}),
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @param {string[] | undefined} prefixes
|
|
43
|
+
* @param {string | string[] | undefined} originalGlobs
|
|
44
|
+
* @returns {string | string[] | undefined}
|
|
45
|
+
*/
|
|
46
|
+
function generateCombinations(prefixes, originalGlobs) {
|
|
47
|
+
if (!prefixes || prefixes.length === 0) return originalGlobs
|
|
48
|
+
if (!originalGlobs || originalGlobs.length === 0) {
|
|
49
|
+
return prefixes.map((prefix) => path.join(prefix, '**'))
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const originalGlobList = [originalGlobs].flat()
|
|
53
|
+
|
|
54
|
+
return prefixes.flatMap((prefix) => {
|
|
55
|
+
return originalGlobList.flatMap((originalGlob) => {
|
|
56
|
+
const signRegexp = /^!/
|
|
57
|
+
const sign = originalGlob.match(signRegexp)?.[0] ?? ''
|
|
58
|
+
return sign + path.join(prefix, originalGlob.replace(signRegexp, ''))
|
|
59
|
+
})
|
|
60
|
+
})
|
|
61
|
+
}
|
package/eslintignore
DELETED