@wkovacs64/eslint-config 5.0.1 → 7.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/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2019 Justin R. Hall
3
+ Copyright (c) 2024 Justin R. Hall
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a
6
6
  copy of this software and associated documentation files (the
package/README.md CHANGED
@@ -1,30 +1,64 @@
1
1
  # @wkovacs64/eslint-config
2
2
 
3
- This is my base personal ESLint configuration.
3
+ This is my personal [ESLint][eslint] configuration.
4
+
5
+ [![npm Version][npm-image]][npm-url] [![Build Status][ci-image]][ci-url]
6
+ [![changesets][changesets-image]][changesets-url]
4
7
 
5
8
  ### Install
6
9
 
7
10
  ```
8
- npx install-peerdeps --dev --yarn @wkovacs64/eslint-config
11
+ npm install --save-dev @wkovacs64/eslint-config
9
12
  ```
10
13
 
11
- > Drop the `--yarn` when using `npm`.
14
+ > Be sure to install the appropriately versioned `eslint` peer dependency as
15
+ > well.
12
16
 
13
17
  ### Usage
14
18
 
15
- Extend in your `.eslintrc.js`:
19
+ Follow the ESLint documentation on [shared configurations][eslint-sharing]. See
20
+ the documentation on [ignoring files][eslint-ignores] if you need to ignore
21
+ anything the config doesn't already ignore by default.
22
+
23
+ ### Examples
24
+
25
+ #### `eslint.config.js`
16
26
 
17
27
  ```js
18
- module.exports = {
19
- extends: ['@wkovacs64/eslint-config'],
20
- };
28
+ import baseConfig from '@wkovacs64/eslint-config';
29
+
30
+ /** @type {import("eslint").Linter.FlatConfig[]} */
31
+ const config = [
32
+ ...baseConfig,
33
+ // overrides here
34
+ ];
35
+
36
+ export default config;
21
37
  ```
22
38
 
23
- ### Other Configurations
39
+ #### `package.json`
40
+
41
+ ```
42
+ {
43
+ "scripts": {
44
+ ...
45
+ "lint": "eslint --cache --cache-location ./node_modules/.cache/eslint .",
46
+ ...
47
+ }
48
+ }
49
+ ```
24
50
 
25
- - React:
26
- [@wkovacs64/eslint-config-react](https://github.com/wKovacs64/eslint-config-react)
27
- - TypeScript:
28
- [@wkovacs64/eslint-config-ts](https://github.com/wKovacs64/eslint-config-ts)
29
- - TypeScript and React:
30
- [@wkovacs64/eslint-config-ts-react](https://github.com/wKovacs64/eslint-config-ts-react)
51
+ [npm-image]:
52
+ https://img.shields.io/npm/v/@wkovacs64/eslint-config.svg?style=flat-square
53
+ [npm-url]: https://www.npmjs.com/package/@wkovacs64/eslint-config
54
+ [ci-image]:
55
+ https://img.shields.io/github/actions/workflow/status/wKovacs64/eslint-config/ci.yml?logo=github&style=flat-square
56
+ [ci-url]: https://github.com/wKovacs64/eslint-config/actions?query=workflow%3Aci
57
+ [changesets-image]:
58
+ https://img.shields.io/badge/maintained%20with-changesets-blue?style=flat-square
59
+ [changesets-url]: https://github.com/changesets/changesets
60
+ [eslint]: https://eslint.org/
61
+ [eslint-sharing]:
62
+ https://eslint.org/docs/latest/use/configure/configuration-files#using-a-shareable-configuration-package
63
+ [eslint-ignores]:
64
+ https://eslint.org/docs/latest/use/configure/migration-guide#ignoring-files
package/index.js CHANGED
@@ -1,51 +1,365 @@
1
- module.exports = {
2
- extends: ['airbnb-base', 'prettier'],
3
- env: {
4
- jest: true,
1
+ // @ts-check
2
+ //
3
+ // Forked from https://github.com/epicweb-dev/config
4
+ //
5
+ import globals from 'globals';
6
+ import eslint from '@eslint/js';
7
+ import tseslint from 'typescript-eslint';
8
+ import playwright from 'eslint-plugin-playwright';
9
+
10
+ const ERROR = 'error';
11
+ const WARN = 'warn';
12
+ const OFF = 'off';
13
+
14
+ const has = (pkg) =>
15
+ import(pkg).then(
16
+ () => true,
17
+ () => false,
18
+ );
19
+
20
+ const hasTypeScript = await has('typescript');
21
+ const hasReact = await has('react');
22
+ const hasTestingLibrary = await has('@testing-library/dom');
23
+ const hasJestDom = await has('@testing-library/jest-dom');
24
+ const hasVitest = await has('vitest');
25
+ const hasPlaywright = await has('playwright');
26
+
27
+ const vitestFiles = ['**/__tests__/**/*', '**/*.test.*'];
28
+ const testFiles = ['**/tests/**', '**/#tests/**', ...vitestFiles];
29
+ const playwrightFiles = ['**/playwright/tests/**'];
30
+
31
+ export const config = [
32
+ {
33
+ ignores: [
34
+ '**/.cache/**',
35
+ '**/node_modules/**',
36
+ '**/build/**',
37
+ '**/public/build/**',
38
+ '**/playwright-report/**',
39
+ '**/playwright-results/**',
40
+ '**/playwright/report/**',
41
+ '**/playwright/results/**',
42
+ '**/server-build/**',
43
+ '**/dist/**',
44
+ '**/coverage/**',
45
+ ],
5
46
  },
6
- parser: 'babel-eslint',
7
- plugins: ['jest'],
8
- rules: {
9
- 'import/prefer-default-export': 'off',
10
- 'jest/consistent-test-it': 'error',
11
- 'jest/expect-expect': 'off',
12
- 'jest/lowercase-name': 'off',
13
- 'jest/no-alias-methods': 'error',
14
- 'jest/no-disabled-tests': 'error',
15
- 'jest/no-focused-tests': 'error',
16
- 'jest/no-hooks': 'off',
17
- 'jest/no-identical-title': 'error',
18
- 'jest/no-jasmine-globals': 'error',
19
- 'jest/no-jest-import': 'error',
20
- 'jest/no-large-snapshots': 'off',
21
- 'jest/no-test-callback': 'error',
22
- 'jest/no-test-prefixes': 'error',
23
- 'jest/no-test-return-statement': 'off',
24
- 'jest/no-truthy-falsy': 'off',
25
- 'jest/prefer-expect-assertions': 'off',
26
- 'jest/prefer-spy-on': 'warn',
27
- 'jest/prefer-strict-equal': 'off',
28
- 'jest/prefer-to-be-null': 'warn',
29
- 'jest/prefer-to-be-undefined': 'warn',
30
- 'jest/prefer-to-contain': 'warn',
31
- 'jest/prefer-to-have-length': 'warn',
32
- 'jest/prefer-inline-snapshots': 'off',
33
- 'jest/require-tothrow-message': 'off',
34
- 'jest/valid-describe': 'error',
35
- 'jest/valid-expect-in-promise': 'error',
36
- 'jest/valid-expect': 'error',
37
- 'jest/prefer-todo': 'warn',
38
- 'no-nested-ternary': 'off',
39
- 'no-unused-expressions': ['error', { allowTaggedTemplates: true }],
40
- 'valid-jsdoc': [
41
- 'error',
42
- {
43
- prefer: {
44
- arg: 'param',
45
- argument: 'param',
46
- return: 'returns',
47
- },
47
+
48
+ // all files
49
+ eslint.configs.recommended,
50
+ {
51
+ plugins: {
52
+ import: (await import('eslint-plugin-import-x')).default,
53
+ },
54
+ languageOptions: {
55
+ globals: {
56
+ ...globals.browser,
57
+ ...globals.node,
48
58
  },
49
- ],
59
+ },
60
+ rules: {
61
+ 'import/no-duplicates': [WARN, { 'prefer-inline': true }],
62
+ 'import/order': [
63
+ WARN,
64
+ {
65
+ pathGroups: [
66
+ { pattern: '#*/**', group: 'internal' },
67
+ { pattern: '~/**', group: 'internal' },
68
+ ],
69
+ groups: [
70
+ 'builtin',
71
+ 'external',
72
+ 'internal',
73
+ 'parent',
74
+ 'sibling',
75
+ 'index',
76
+ ],
77
+ },
78
+ ],
79
+ },
80
+ },
81
+
82
+ // JSX/TSX files
83
+ hasReact
84
+ ? {
85
+ files: ['**/*.tsx', '**/*.jsx'].filter(Boolean),
86
+ plugins: {
87
+ react: (await import('eslint-plugin-react')).default,
88
+ 'jsx-a11y': (await import('eslint-plugin-jsx-a11y')).default,
89
+ },
90
+ languageOptions: {
91
+ parserOptions: {
92
+ ecmaFeatures: {
93
+ jsx: true,
94
+ },
95
+ },
96
+ },
97
+ rules: {
98
+ 'react/function-component-definition': [
99
+ 'error',
100
+ {
101
+ namedComponents: 'function-declaration',
102
+ unnamedComponents: 'arrow-function',
103
+ },
104
+ ],
105
+ 'react/jsx-key': WARN,
106
+ 'jsx-a11y/label-has-associated-control': [
107
+ ERROR,
108
+ {
109
+ assert: 'either',
110
+ },
111
+ ],
112
+ },
113
+ settings: {
114
+ react: {
115
+ version: 'detect',
116
+ },
117
+ },
118
+ }
119
+ : null,
120
+
121
+ // react-hook rules are applicable in ts/js/tsx/jsx, but only with React as a
122
+ // dep
123
+ hasReact
124
+ ? {
125
+ files: ['**/*.ts?(x)', '**/*.js?(x)'],
126
+ plugins: {
127
+ 'react-hooks': (await import('eslint-plugin-react-hooks')).default,
128
+ },
129
+ rules: {
130
+ 'react-hooks/rules-of-hooks': ERROR,
131
+ 'react-hooks/exhaustive-deps': ERROR,
132
+ },
133
+ }
134
+ : null,
135
+
136
+ // JS and JSX files
137
+ {
138
+ files: ['**/*.js?(x)'],
139
+ rules: {
140
+ // most of these rules are useful for JS but not TS because TS handles these better
141
+ // if it weren't for https://github.com/import-js/eslint-plugin-import/issues/2132
142
+ // we could enable this :(
143
+ // 'import/no-unresolved': ERROR,
144
+ 'no-unused-vars': [
145
+ WARN,
146
+ {
147
+ args: 'after-used',
148
+ argsIgnorePattern: '^_',
149
+ ignoreRestSiblings: true,
150
+ varsIgnorePattern: '^ignored',
151
+ },
152
+ ],
153
+ },
50
154
  },
51
- };
155
+
156
+ // TS and TSX files
157
+ ...(hasTypeScript
158
+ ? [
159
+ // TODO: figure out how to switch to type-checked configs
160
+ ...tseslint.configs.recommended,
161
+ ...tseslint.configs.stylistic,
162
+ ]
163
+ : []),
164
+ hasTypeScript
165
+ ? {
166
+ files: ['**/*.ts?(x)'],
167
+ languageOptions: {
168
+ parserOptions: {
169
+ parser: tseslint.parser,
170
+ projectService: true,
171
+ },
172
+ },
173
+ plugins: {
174
+ '@typescript-eslint': tseslint.plugin,
175
+ },
176
+ rules: {
177
+ '@typescript-eslint/ban-ts-comment': OFF,
178
+ '@typescript-eslint/consistent-type-assertions': [
179
+ ERROR,
180
+ {
181
+ assertionStyle: 'as',
182
+ objectLiteralTypeAssertions: 'allow-as-parameter',
183
+ },
184
+ ],
185
+ '@typescript-eslint/consistent-type-definitions': OFF,
186
+ 'import/consistent-type-specifier-style': [WARN, 'prefer-inline'],
187
+ '@typescript-eslint/consistent-type-imports': [
188
+ ERROR,
189
+ {
190
+ prefer: 'type-imports',
191
+ disallowTypeAnnotations: true,
192
+ fixStyle: 'inline-type-imports',
193
+ },
194
+ ],
195
+ '@typescript-eslint/explicit-module-boundary-types': OFF,
196
+ '@typescript-eslint/naming-convention': [
197
+ ERROR,
198
+ {
199
+ selector: 'typeLike',
200
+ format: ['PascalCase'],
201
+ custom: { regex: '^I[A-Z]', match: false },
202
+ },
203
+ ],
204
+ '@typescript-eslint/no-confusing-void-expression': [
205
+ ERROR,
206
+ {
207
+ ignoreArrowShorthand: true,
208
+ },
209
+ ],
210
+ '@typescript-eslint/no-explicit-any': OFF,
211
+ '@typescript-eslint/no-floating-promises': [
212
+ ERROR,
213
+ {
214
+ ignoreIIFE: true,
215
+ },
216
+ ],
217
+ '@typescript-eslint/no-import-type-side-effects': ERROR,
218
+ 'no-invalid-this': OFF,
219
+ '@typescript-eslint/no-invalid-this': ERROR,
220
+ 'no-redeclare': OFF,
221
+ '@typescript-eslint/no-non-null-assertion': OFF,
222
+ '@typescript-eslint/no-redeclare': ERROR,
223
+ 'no-shadow': OFF,
224
+ '@typescript-eslint/no-shadow': ERROR,
225
+ '@typescript-eslint/no-unnecessary-type-constraint': 'warn',
226
+ '@typescript-eslint/no-unused-vars': [
227
+ ERROR,
228
+ {
229
+ vars: 'all',
230
+ args: 'after-used',
231
+ argsIgnorePattern: '^_',
232
+ ignoreRestSiblings: true,
233
+ },
234
+ ],
235
+ 'no-use-before-define': OFF,
236
+ '@typescript-eslint/no-use-before-define': [
237
+ ERROR,
238
+ {
239
+ functions: false,
240
+ classes: true,
241
+ variables: true,
242
+ },
243
+ ],
244
+ '@typescript-eslint/prefer-nullish-coalescing': OFF,
245
+ '@typescript-eslint/restrict-template-expressions': [
246
+ ERROR,
247
+ {
248
+ allowBoolean: true,
249
+ allowNullish: true,
250
+ },
251
+ ],
252
+ '@typescript-eslint/require-await': OFF,
253
+ '@typescript-eslint/unified-signatures': 'warn',
254
+ },
255
+ }
256
+ : null,
257
+
258
+ // This assumes test files are those which are in the test directory or have
259
+ // *.test.* in the filename. If a file doesn't match this assumption, then it
260
+ // will not be allowed to import test files.
261
+ {
262
+ files: ['**/*.ts?(x)', '**/*.js?(x)'],
263
+ ignores: testFiles,
264
+ rules: {
265
+ 'no-restricted-imports': [
266
+ ERROR,
267
+ {
268
+ patterns: [
269
+ {
270
+ group: testFiles,
271
+ message: 'Do not import test files in source files',
272
+ },
273
+ ],
274
+ },
275
+ ],
276
+ },
277
+ },
278
+
279
+ hasTestingLibrary
280
+ ? {
281
+ files: testFiles,
282
+ ignores: [...playwrightFiles],
283
+ plugins: {
284
+ 'testing-library': (await import('eslint-plugin-testing-library'))
285
+ .default,
286
+ },
287
+ rules: {
288
+ // 'testing-library/await-async-events': ERROR,
289
+ // 'testing-library/await-async-queries': ERROR,
290
+ // 'testing-library/await-async-utils': ERROR,
291
+ // 'testing-library/consistent-data-testid': OFF,
292
+ // 'testing-library/no-await-sync-events': ERROR,
293
+ // 'testing-library/no-await-sync-queries': ERROR,
294
+ // 'testing-library/no-container': ERROR,
295
+ // 'testing-library/no-debugging-utils': OFF,
296
+ // 'testing-library/no-dom-import': [ERROR, 'react'],
297
+ // 'testing-library/no-global-regexp-flag-in-query': ERROR,
298
+ // 'testing-library/no-manual-cleanup': ERROR,
299
+ // 'testing-library/no-node-access': ERROR,
300
+ // 'testing-library/no-promise-in-fire-event': ERROR,
301
+ // 'testing-library/no-render-in-lifecycle': ERROR,
302
+ 'testing-library/no-unnecessary-act': ERROR,
303
+ // 'testing-library/no-wait-for-multiple-assertions': ERROR,
304
+ 'testing-library/no-wait-for-side-effects': ERROR,
305
+ // 'testing-library/no-wait-for-snapshot': ERROR,
306
+ // 'testing-library/prefer-explicit-assert': ERROR,
307
+ 'testing-library/prefer-find-by': ERROR,
308
+ // 'testing-library/prefer-presence-queries': ERROR,
309
+ // 'testing-library/prefer-query-by-disappearance': ERROR,
310
+ // 'testing-library/prefer-query-matchers': OFF,
311
+ // 'testing-library/prefer-screen-queries': ERROR,
312
+ // 'testing-library/prefer-user-event': ERROR,
313
+ // 'testing-library/render-result-naming-convention': ERROR,
314
+ },
315
+ }
316
+ : null,
317
+
318
+ hasJestDom
319
+ ? {
320
+ files: testFiles,
321
+ ignores: [...playwrightFiles],
322
+ plugins: {
323
+ 'jest-dom': (await import('eslint-plugin-jest-dom')).default,
324
+ },
325
+ rules: {
326
+ 'jest-dom/prefer-checked': ERROR,
327
+ 'jest-dom/prefer-empty': ERROR,
328
+ 'jest-dom/prefer-enabled-disabled': ERROR,
329
+ 'jest-dom/prefer-focus': ERROR,
330
+ 'jest-dom/prefer-in-document': ERROR,
331
+ 'jest-dom/prefer-required': ERROR,
332
+ 'jest-dom/prefer-to-have-attribute': ERROR,
333
+ 'jest-dom/prefer-to-have-class': ERROR,
334
+ 'jest-dom/prefer-to-have-style': ERROR,
335
+ 'jest-dom/prefer-to-have-text-content': ERROR,
336
+ 'jest-dom/prefer-to-have-value': ERROR,
337
+ },
338
+ }
339
+ : null,
340
+
341
+ hasVitest
342
+ ? {
343
+ files: testFiles,
344
+ ignores: [...playwrightFiles],
345
+ plugins: {
346
+ vitest: (await import('eslint-plugin-vitest')).default,
347
+ },
348
+ rules: {
349
+ // you don't want the editor to autofix this, but we do want to be
350
+ // made aware of it
351
+ 'vitest/no-focused-tests': [WARN, { fixable: false }],
352
+ },
353
+ }
354
+ : null,
355
+
356
+ hasPlaywright
357
+ ? {
358
+ files: playwrightFiles,
359
+ ...playwright.configs['flat/recommended'],
360
+ }
361
+ : null,
362
+ ].filter(Boolean);
363
+
364
+ // this is for backward compatibility
365
+ export default config;
package/package.json CHANGED
@@ -1,10 +1,13 @@
1
1
  {
2
2
  "name": "@wkovacs64/eslint-config",
3
- "version": "5.0.1",
4
- "description": "@wKovacs64 ESLint config (base)",
3
+ "version": "7.0.0",
4
+ "description": "@wKovacs64 ESLint config",
5
5
  "keywords": [
6
6
  "eslint",
7
7
  "eslintconfig",
8
+ "eslintplugin",
9
+ "eslint-config",
10
+ "eslint-plugin",
8
11
  "wkovacs64"
9
12
  ],
10
13
  "author": {
@@ -12,10 +15,17 @@
12
15
  "email": "justin.r.hall@gmail.com"
13
16
  },
14
17
  "license": "MIT",
18
+ "type": "module",
15
19
  "main": "index.js",
20
+ "exports": {
21
+ ".": {
22
+ "import": "./index.js"
23
+ }
24
+ },
16
25
  "files": [
17
26
  "index.js"
18
27
  ],
28
+ "homepage": "https://github.com/wKovacs64/eslint-config#readme",
19
29
  "repository": {
20
30
  "type": "git",
21
31
  "url": "https://github.com/wKovacs64/eslint-config.git"
@@ -24,41 +34,52 @@
24
34
  "url": "https://github.com/wKovacs64/eslint-config/issues"
25
35
  },
26
36
  "scripts": {
27
- "cm": "git-cz",
28
- "format": "prettier --write \"**/*.{js,ts,tsx,json,md,yml}\"",
37
+ "changeset": "changeset",
38
+ "changeset:version": "changeset version && npm install --package-lock-only",
39
+ "changeset:publish": "changeset publish",
40
+ "format": "prettier --cache --write .",
41
+ "format:check": "prettier --cache --check .",
29
42
  "lint": "eslint .",
30
- "validate": "yarn lint"
31
- },
32
- "config": {
33
- "commitizen": {
34
- "path": "./node_modules/cz-conventional-changelog"
35
- }
43
+ "typecheck": "tsc"
36
44
  },
37
45
  "private": false,
46
+ "prettier": "@wkovacs64/prettier-config",
38
47
  "publishConfig": {
39
48
  "access": "public"
40
49
  },
50
+ "engines": {
51
+ "node": "^18.18.0 || >=20.0.0"
52
+ },
53
+ "peerDependencies": {
54
+ "eslint": "^9.4.0"
55
+ },
41
56
  "dependencies": {
42
- "babel-eslint": "^10.0.1",
43
- "eslint-config-airbnb-base": "^13.1.0",
44
- "eslint-config-prettier": "^6.0.0"
57
+ "@eslint/js": "^9.4.0",
58
+ "eslint-plugin-import-x": "^0.5.1",
59
+ "eslint-plugin-jest-dom": "^5.4.0",
60
+ "eslint-plugin-jsx-a11y": "^6.8.0",
61
+ "eslint-plugin-playwright": "^1.6.2",
62
+ "eslint-plugin-react": "^7.34.2",
63
+ "eslint-plugin-react-hooks": "^4.6.2",
64
+ "eslint-plugin-testing-library": "^6.2.2",
65
+ "eslint-plugin-vitest": "^0.5.4",
66
+ "globals": "^15.3.0",
67
+ "typescript-eslint": "^8.0.0-alpha.20"
45
68
  },
46
69
  "devDependencies": {
47
- "@commitlint/cli": "8.0.0",
48
- "@commitlint/config-conventional": "8.0.0",
49
- "commitizen": "3.1.1",
50
- "cz-conventional-changelog": "2.1.0",
51
- "eslint": "5.16.0",
52
- "eslint-plugin-import": "2.18.0",
53
- "eslint-plugin-jest": "22.7.1",
54
- "husky": "2.7.0",
55
- "lint-staged": "8.2.1",
56
- "prettier": "1.18.2",
57
- "semantic-release": "15.13.18"
70
+ "@changesets/changelog-github": "0.5.0",
71
+ "@changesets/cli": "2.27.5",
72
+ "@types/eslint__js": "8.42.3",
73
+ "@types/node": "20.13.0",
74
+ "@types/react": "18.3.3",
75
+ "@types/react-dom": "18.3.0",
76
+ "@wkovacs64/prettier-config": "4.0.0",
77
+ "eslint": "9.4.0",
78
+ "prettier": "3.3.0",
79
+ "typescript": "5.4.5"
58
80
  },
59
- "peerDependencies": {
60
- "eslint": "^5.13.0",
61
- "eslint-plugin-import": "^2.16.0",
62
- "eslint-plugin-jest": "^22.2.2"
81
+ "// TODO": "remove eslint override once our dependencies include v9 in their peerDependencies",
82
+ "overrides": {
83
+ "eslint": "9.4.0"
63
84
  }
64
85
  }
package/CHANGELOG.md DELETED
@@ -1,5 +0,0 @@
1
- # Change Log
2
-
3
- The changelog is automatically updated using
4
- [semantic-release](https://github.com/semantic-release/semantic-release). You
5
- can see it on the [releases page](../../releases).