@foray1010/eslint-config 9.1.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/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
@@ -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
- 'use strict'
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
- exports.testFileGlobs = testFileGlobs
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": "9.1.0",
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
- "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.42.1",
28
- "@typescript-eslint/parser": "^5.42.1",
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": "^39.3.25",
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
- "eslint-plugin-simple-import-sort": "^8.0.0",
45
- "eslint-plugin-testing-library": "^5.9.1",
46
- "eslint-plugin-unicorn": "^45.0.0"
42
+ "eslint-plugin-simple-import-sort": "^10.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.4.10"
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": "7b07434790f3f2c119d1106c379ab07bd715372e"
61
+ "gitHead": "ee22f073ee1702354310091b7c3a5ec18a930bec"
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,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
@@ -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
- }