@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.
@@ -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
@@ -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": "9.2.0",
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
- "exports": {
14
- ".": "./index.cjs",
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
- "@foray1010/common-presets-utils": "^6.0.0",
27
- "@typescript-eslint/eslint-plugin": "^5.51.0",
28
- "@typescript-eslint/parser": "^5.51.0",
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.3.0",
29
+ "eslint-config-prettier": "^8.8.0",
31
30
  "eslint-import-resolver-typescript": "^3.5.2",
32
- "eslint-plugin-compat": "^4.0.0",
31
+ "eslint-plugin-compat": "^4.1.2",
33
32
  "eslint-plugin-deprecation": "^1.3.2",
34
- "eslint-plugin-eslint-comments": "^3.2.0",
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.0.0",
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.31.10",
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.9.1",
46
- "eslint-plugin-unicorn": "^45.0.0"
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.1"
49
+ "@types/eslint": "8.21.3"
51
50
  },
52
51
  "peerDependencies": {
53
- "eslint": "^8.0.0",
52
+ "eslint": "^8.36.0",
54
53
  "prettier": "^2.0.0"
55
54
  },
56
55
  "engines": {
57
- "node": "^14.18.0 || ^16.13.0 || >=18.12.0"
56
+ "node": "^16.14.0 || >=18.12.0"
58
57
  },
59
58
  "publishConfig": {
60
59
  "access": "public"
61
60
  },
62
- "gitHead": "11a76b57489f7de8f08ec5cd47f8747c4c432f09"
61
+ "gitHead": "c722884bc466360097d9ab80e72f350a15ed7cad"
63
62
  }
package/tsconfig.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/tsconfig",
3
- "extends": "@foray1010/tsconfig",
3
+ "extends": "@foray1010/tsconfig/tsconfig.base.json",
4
4
  "compilerOptions": {
5
5
  "allowJs": true,
6
6
  "checkJs": true
@@ -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
@@ -1,6 +0,0 @@
1
- !.*
2
- .yarn/
3
- build/
4
- coverage/
5
- dist/
6
- node_modules/
package/index.cjs DELETED
@@ -1,6 +0,0 @@
1
- 'use strict'
2
-
3
- /** @type {import('eslint').Linter.Config} */
4
- module.exports = {
5
- extends: ['./presets/base.cjs', './presets/node.cjs'],
6
- }