@perfective/eslint-config 0.32.0 → 0.34.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License
2
2
 
3
- Copyright (c) 2020-2025 Andrey Mikheychik (https://github.com/amikheychik)
3
+ Copyright (c) 2020-2026 Andrey Mikheychik (https://github.com/amikheychik)
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.adoc CHANGED
@@ -78,7 +78,7 @@ import { perfectiveEslintConfig } from '@perfective/eslint-config';
78
78
 
79
79
  // Optional dependencies.
80
80
  import { cypressConfig } from '@perfective/eslint-config/cypress';
81
- import { jestConfig } from '@perfective/eslint-config/jest';
81
+ import { jestConfig, jestTypescriptConfig } from '@perfective/eslint-config/jest';
82
82
  import { jestDomConfig } from '@perfective/eslint-config/jest-dom';
83
83
  import { rxjsConfig } from '@perfective/eslint-config/rxjs';
84
84
  import { testingLibraryConfig } from '@perfective/eslint-config/testing-library';
@@ -86,6 +86,7 @@ import { testingLibraryConfig } from '@perfective/eslint-config/testing-library'
86
86
  const eslintConfig = perfectiveEslintConfig([
87
87
  cypressConfig,
88
88
  jestConfig,
89
+ jestTypescriptConfig,
89
90
  jestDomConfig,
90
91
  rxjsConfig,
91
92
  testingLibraryConfig,
@@ -188,6 +189,12 @@ a nominal type for glob patterns.
188
189
  ** `jestFiles: Glob[]`
189
190
  — the link:https://jestjs.io/docs/configuration#testmatch-arraystring[default] glob patterns
190
191
  Jest uses to find test files.
192
+ ** `jestJavascriptFiles: Glob[]`
193
+ — the link:https://jestjs.io/docs/configuration#testmatch-arraystring[default] glob patterns
194
+ Jest uses to find JavaScript test files.
195
+ ** `jestTypescriptFiles: Glob[]`
196
+ — the link:https://jestjs.io/docs/configuration#testmatch-arraystring[default] glob patterns
197
+ Jest uses to find TypeScript test files.
191
198
  ** `cypressFiles: Glob`
192
199
  — the link:https://docs.cypress.io/app/references/configuration#e2e[default] glob pattern
193
200
  Cypress uses to load test files.
@@ -231,6 +238,11 @@ Overrides some rules for `perfectiveEslintConfig` for compatibility with Cypress
231
238
 
232
239
  * `jestConfig(files: Glob[] = jestFiles): Linter.Config`
233
240
  — creates a flat config for `eslint-plugin-jest` for a given list of files globs.
241
+ This config excludes the rules that require `@typescript-eslint` plugin.
242
+ +
243
+ * `jestTypescriptConfig(files: Glob[] = jestTypescriptFiles): Linter.Config`
244
+ — creates a flat config for `eslint-plugin-jest` for a given list of TypeScript file globs.
245
+ This config includes only the rules that require `@typescript-eslint` plugin.
234
246
 
235
247
  === `@perfective/eslint-config/jest-dom`
236
248
 
@@ -257,6 +269,9 @@ Allows to splice `internal` scope packages imports between the global and relati
257
269
 
258
270
  === `@perfective/eslint-config/typescript-eslint`
259
271
 
272
+ * `typescriptEslintDependentConfig(plugin: ESLint.Plugin, rules: Linter.RulesRecord, files: Glob[] = typescriptFiles): Linter.Config`
273
+ — a function to create a flat config for a given `plugin` that requires TypeScript ESLint plugin.
274
+ +
260
275
  * `interface TypescriptEslintNamingConvention`
261
276
  — configuration options for the
262
277
  `link:https://typescript-eslint.io/rules/naming-convention/[@typescript-eslint/naming-convention]` rule.
@@ -270,7 +285,7 @@ Allows to splice `internal` scope packages imports between the global and relati
270
285
  — values for the `@typescript-eslint/naming-convention` rule `format` option.
271
286
  ** `type TypescriptEslintNamingConventionUnderscore`
272
287
  — values for the `@typescript-eslint/naming-convention` rule `leadingUnderscore` and `trailingUnderscore` options.
273
- ** `function typescriptEslintNamingConvention(extensions: TypescriptEslintNamingConvention[] = []): TypescriptEslintNamingConvention[]`
288
+ ** `typescriptEslintNamingConvention(extensions: TypescriptEslintNamingConvention[] = []): TypescriptEslintNamingConvention[]`
274
289
  — creates configuration with the given extensions for the `@typescript-eslint/naming-convention` rule.
275
290
 
276
291
  === `@perfective/eslint-config/unicorn`
@@ -280,5 +295,5 @@ Allows to splice `internal` scope packages imports between the global and relati
280
295
  `link:https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prevent-abbreviations.md[unicorn/prevent-abbreviation]` rule.
281
296
  ** `type UnicornPreventAbbreviationReplacements`
282
297
  — nominal type for the `replacements` option of the `unicorn/prevent-abbreviation` rule.
283
- ** `function unicornPreventAbbreviations( replacements: UnicornPreventAbbreviationReplacements = {}, options: Partial<Pick<UnicornPreventAbbreviations, 'checkProperties'>> = {}): UnicornPreventAbbreviations`
298
+ ** `unicornPreventAbbreviations(replacements: UnicornPreventAbbreviationReplacements = {}, options: Partial<Pick<UnicornPreventAbbreviations, 'checkProperties'>> = {}): UnicornPreventAbbreviations`
284
299
  — creates configuration for the `unicorn/prevent-abbreviation` rule with the given replacements and options.
@@ -1,4 +1,4 @@
1
- import eslintPluginCypress from 'eslint-plugin-cypress/flat';
1
+ import eslintPluginCypress from 'eslint-plugin-cypress';
2
2
  import { cypressFiles } from "../../linter/glob.js";
3
3
  import { importNoExtraneousDependencies } from "../import/rules/no-extraneous-dependencies.js";
4
4
  export function cypressConfig(files = [cypressFiles]) {
@@ -165,6 +165,9 @@ export const eslintSuggestionsRules = {
165
165
  'prefer-rest-params': 'error',
166
166
  'prefer-spread': 'error',
167
167
  'prefer-template': 'warn',
168
+ 'preserve-caught-error': ['off', {
169
+ requireCatchParameter: true
170
+ }],
168
171
  'quote-props': 'off',
169
172
  'radix': 'error',
170
173
  'require-await': 'error',
@@ -1 +1,2 @@
1
1
  export { jestConfig } from './jest-config';
2
+ export { jestTypescriptConfig } from './jest-typescript-config';
@@ -1 +1,2 @@
1
- export { jestConfig } from "./jest-config.js";
1
+ export { jestConfig } from "./jest-config.js";
2
+ export { jestTypescriptConfig } from "./jest-typescript-config.js";
@@ -3,6 +3,8 @@ import { Glob } from '../../linter/glob';
3
3
  /**
4
4
  * Creates a flat config for `eslint-plugin-jest` for a given list of files globs.
5
5
  *
6
+ * This config excludes the rules that require `@typescript-eslint` plugin.
7
+ *
6
8
  * @since v0.31.0
7
9
  */
8
10
  export declare function jestConfig(files?: Glob[]): Linter.Config;
@@ -1,7 +1,6 @@
1
1
  import eslintPluginJest from 'eslint-plugin-jest';
2
2
  import { jestFiles } from "../../linter/glob.js";
3
- import { importNoExtraneousDependencies } from "../import/index.js";
4
- import { typescriptEslintJestRules } from "./typescript-eslint-jest-rules.js";
3
+ import { importNoExtraneousDependencies } from "../import/rules/no-extraneous-dependencies.js";
5
4
  export function jestConfig(files = jestFiles) {
6
5
  return {
7
6
  files,
@@ -11,7 +10,7 @@ export function jestConfig(files = jestFiles) {
11
10
  languageOptions: {
12
11
  globals: eslintPluginJest.environments.globals.globals
13
12
  },
14
- rules: Object.assign(Object.assign(Object.assign({}, perfectiveRules()), typescriptEslintJestRules), {
13
+ rules: Object.assign(Object.assign({}, perfectiveRules()), {
15
14
  'jest/consistent-test-it': ['warn', {
16
15
  fn: 'test',
17
16
  withinDescribe: 'it'
@@ -53,6 +52,7 @@ export function jestConfig(files = jestFiles) {
53
52
  'jest/no-standalone-expect': 'error',
54
53
  'jest/no-test-prefixes': 'warn',
55
54
  'jest/no-test-return-statement': 'error',
55
+ 'jest/no-unneeded-async-expect-function': 'warn',
56
56
  'jest/no-untyped-mock-factory': 'warn',
57
57
  'jest/padding-around-after-all-blocks': 'warn',
58
58
  'jest/padding-around-after-each-blocks': 'warn',
@@ -76,14 +76,18 @@ export function jestConfig(files = jestFiles) {
76
76
  'jest/prefer-lowercase-title': ['error', {
77
77
  allowedPrefixes: [],
78
78
  ignore: [],
79
+ ignoreTodos: false,
79
80
  ignoreTopLevelDescribe: true
80
81
  }],
81
82
  'jest/prefer-mock-promise-shorthand': 'warn',
83
+ 'jest/prefer-mock-return-shorthand': 'warn',
82
84
  'jest/prefer-snapshot-hint': ['error', 'always'],
83
85
  'jest/prefer-spy-on': 'warn',
84
86
  'jest/prefer-strict-equal': 'warn',
85
87
  'jest/prefer-to-be': 'warn',
86
88
  'jest/prefer-to-contain': 'warn',
89
+ 'jest/prefer-to-have-been-called': 'warn',
90
+ 'jest/prefer-to-have-been-called-times': 'warn',
87
91
  'jest/prefer-to-have-length': 'warn',
88
92
  'jest/prefer-todo': 'warn',
89
93
  'jest/require-hook': ['error', {
@@ -94,6 +98,7 @@ export function jestConfig(files = jestFiles) {
94
98
  'jest/valid-describe-callback': 'error',
95
99
  'jest/valid-expect-in-promise': 'error',
96
100
  'jest/valid-expect': 'error',
101
+ 'jest/valid-mock-module-path': 'error',
97
102
  'jest/valid-title': ['warn', {
98
103
  ignoreTypeOfDescribeName: true,
99
104
  ignoreTypeOfTestName: false,
@@ -104,14 +109,6 @@ export function jestConfig(files = jestFiles) {
104
109
  }
105
110
  function perfectiveRules() {
106
111
  return {
107
- '@typescript-eslint/ban-ts-comment': ['error', {
108
- 'ts-expect-error': 'allow-with-description',
109
- 'ts-ignore': true,
110
- 'ts-nocheck': true,
111
- 'ts-check': false
112
- }],
113
- '@typescript-eslint/init-declarations': 'off',
114
- '@typescript-eslint/unbound-method': 'off',
115
112
  'import/no-extraneous-dependencies': ['error', importNoExtraneousDependencies({
116
113
  devDependencies: jestFiles
117
114
  })],
@@ -124,6 +121,6 @@ function perfectiveRules() {
124
121
  }],
125
122
  'prefer-arrow/prefer-arrow-functions': 'off',
126
123
  'promise/always-return': 'off',
127
- '@smarttools/rxjs/no-topromise': 'off'
124
+ 'rxjs-x/no-topromise': 'off'
128
125
  };
129
126
  }
@@ -0,0 +1,10 @@
1
+ import { Linter } from 'eslint';
2
+ import { Glob } from '../../linter/glob';
3
+ /**
4
+ * Creates a flat config for `eslint-plugin-jest` for a given list of TypeScript file globs.
5
+ *
6
+ * This config includes only the rules that require `@typescript-eslint` plugin.
7
+ *
8
+ * @since v0.34.0
9
+ */
10
+ export declare function jestTypescriptConfig(files?: Glob[]): Linter.Config;
@@ -0,0 +1,24 @@
1
+ import eslintPluginJest from 'eslint-plugin-jest';
2
+ import { jestTypescriptFiles } from "../../linter/glob.js";
3
+ import { typescriptEslintDependentConfig } from "../typescript-eslint/typescript-eslint-config.js";
4
+ const jestTypescriptRules = {
5
+ 'jest/no-error-equal': 'error',
6
+ 'jest/no-unnecessary-assertion': 'error',
7
+ 'jest/unbound-method': ['error', {
8
+ ignoreStatic: false
9
+ }],
10
+ 'jest/valid-expect-with-promise': 'error'
11
+ };
12
+ const jestTypescriptEslintRulesOverrides = {
13
+ '@typescript-eslint/ban-ts-comment': ['error', {
14
+ 'ts-expect-error': 'allow-with-description',
15
+ 'ts-ignore': true,
16
+ 'ts-nocheck': true,
17
+ 'ts-check': false
18
+ }],
19
+ '@typescript-eslint/init-declarations': 'off',
20
+ '@typescript-eslint/unbound-method': 'off'
21
+ };
22
+ export function jestTypescriptConfig(files = jestTypescriptFiles) {
23
+ return typescriptEslintDependentConfig(eslintPluginJest, Object.assign(Object.assign({}, jestTypescriptRules), jestTypescriptEslintRulesOverrides), files);
24
+ }
@@ -1,13 +1,9 @@
1
- import eslintPluginJsdoc from 'eslint-plugin-jsdoc';
1
+ import { jsdoc } from 'eslint-plugin-jsdoc';
2
2
  import { javascriptFiles } from "../../linter/glob.js";
3
3
  import { javascriptLanguageOptions } from "../../linter/language-options.js";
4
4
  export function jsdocConfig() {
5
- return {
6
- plugins: {
7
- jsdoc: {
8
- rules: eslintPluginJsdoc.configs['flat/recommended'].plugins['jsdoc'].rules
9
- }
10
- },
5
+ return jsdoc({
6
+ config: 'flat/recommended',
11
7
  settings: {
12
8
  jsdoc: {
13
9
  tagNamePreference: {
@@ -30,7 +26,9 @@ export function jsdocConfig() {
30
26
  },
31
27
  rules: {
32
28
  'jsdoc/check-access': 'off',
33
- 'jsdoc/check-alignment': 'error',
29
+ 'jsdoc/check-alignment': ['error', {
30
+ innerIndent: 1
31
+ }],
34
32
  'jsdoc/check-examples': 'off',
35
33
  'jsdoc/check-indentation': 'off',
36
34
  'jsdoc/check-line-alignment': ['off', 'never'],
@@ -60,6 +58,11 @@ export function jsdocConfig() {
60
58
  'jsdoc/empty-tags': ['error', {
61
59
  tags: ['final', 'flags', 'sealed']
62
60
  }],
61
+ 'jsdoc/escape-inline-tags': ['error', {
62
+ allowedInlineTags: [],
63
+ enableFixer: false,
64
+ fixType: 'backticks'
65
+ }],
63
66
  'jsdoc/implements-on-classes': 'error',
64
67
  'jsdoc/imports-as-dependencies': 'error',
65
68
  'jsdoc/lines-before-block': 'off',
@@ -90,6 +93,9 @@ export function jsdocConfig() {
90
93
  'jsdoc/no-restricted-syntax': 'off',
91
94
  'jsdoc/no-types': 'error',
92
95
  'jsdoc/no-undefined-types': 'error',
96
+ 'jsdoc/prefer-import-tag': 'warn',
97
+ 'jsdoc/reject-any-type': 'error',
98
+ 'jsdoc/reject-function-type': 'error',
93
99
  'jsdoc/require-asterisk-prefix': ['error', 'always'],
94
100
  'jsdoc/require-description': ['error', {
95
101
  exemptedBy: ['inheritdoc', 'package', 'private', 'see', 'deprecated']
@@ -99,6 +105,8 @@ export function jsdocConfig() {
99
105
  'jsdoc/require-file-overview': 'off',
100
106
  'jsdoc/require-hyphen-before-param-description': ['warn', 'always'],
101
107
  'jsdoc/require-jsdoc': 'off',
108
+ 'jsdoc/require-next-description': 'error',
109
+ 'jsdoc/require-next-type': 'error',
102
110
  'jsdoc/require-param': 'off',
103
111
  'jsdoc/require-param-description': 'error',
104
112
  'jsdoc/require-param-name': 'error',
@@ -107,16 +115,24 @@ export function jsdocConfig() {
107
115
  'jsdoc/require-property-description': 'error',
108
116
  'jsdoc/require-property-name': 'error',
109
117
  'jsdoc/require-property-type': 'error',
118
+ 'jsdoc/require-rejects': 'error',
110
119
  'jsdoc/require-returns': 'off',
111
120
  'jsdoc/require-returns-check': 'error',
112
121
  'jsdoc/require-returns-description': 'error',
113
122
  'jsdoc/require-returns-type': 'off',
123
+ 'jsdoc/require-tags': 'off',
114
124
  'jsdoc/require-template': ['off', {
125
+ exemptedBy: [],
115
126
  requireSeparateTemplates: false
116
127
  }],
128
+ 'jsdoc/require-template-description': 'off',
117
129
  'jsdoc/require-throws': 'error',
130
+ 'jsdoc/require-throws-description': 'error',
131
+ 'jsdoc/require-throws-type': 'error',
118
132
  'jsdoc/require-yields': 'error',
119
133
  'jsdoc/require-yields-check': 'error',
134
+ 'jsdoc/require-yields-description': 'error',
135
+ 'jsdoc/require-yields-type': 'error',
120
136
  'jsdoc/sort-tags': ['warn', {
121
137
  tagSequence: [{
122
138
  tags: ['summary', 'typeSummary']
@@ -157,11 +173,46 @@ export function jsdocConfig() {
157
173
  startLines: 1,
158
174
  endLines: 0,
159
175
  applyToEndTag: false,
176
+ maxBlockLines: null,
160
177
  tags: {}
161
178
  }],
179
+ 'jsdoc/ts-method-signature-style': 'warn',
180
+ 'jsdoc/ts-no-empty-object-type': 'error',
181
+ 'jsdoc/ts-no-unnecessary-template-expression': 'warn',
182
+ 'jsdoc/ts-prefer-function-type': 'warn',
183
+ 'jsdoc/type-formatting': ['warn', {
184
+ arrayBrackets: 'square',
185
+ arrowFunctionPostReturnMarkerSpacing: '',
186
+ arrowFunctionPreReturnMarkerSpacing: '',
187
+ enableFixer: true,
188
+ functionOrClassParameterSpacing: '',
189
+ functionOrClassPostGenericSpacing: '',
190
+ functionOrClassPostReturnMarkerSpacing: '',
191
+ functionOrClassPreReturnMarkerSpacing: '',
192
+ functionOrClassTypeParameterSpacing: '',
193
+ genericAndTupleElementSpacing: '',
194
+ genericDot: false,
195
+ keyValuePostColonSpacing: '',
196
+ keyValuePostKeySpacing: '',
197
+ keyValuePostOptionalSpacing: '',
198
+ keyValuePostVariadicSpacing: '',
199
+ methodQuotes: 'double',
200
+ objectFieldIndent: '',
201
+ objectFieldQuote: null,
202
+ objectFieldSeparator: 'comma',
203
+ objectFieldSeparatorOptionalLinebreak: true,
204
+ objectFieldSeparatorTrailingPunctuation: false,
205
+ parameterDefaultValueSpacing: ' ',
206
+ postMethodNameSpacing: '',
207
+ postNewSpacing: ' ',
208
+ separatorForSingleObjectField: false,
209
+ stringQuotes: 'double',
210
+ typeBracketSpacing: '',
211
+ unionSpacing: ' '
212
+ }],
162
213
  'jsdoc/valid-types': 'error'
163
214
  }
164
- };
215
+ });
165
216
  }
166
217
  export function jsdocJavascriptConfig() {
167
218
  return {
@@ -48,12 +48,14 @@ export function rxjsConfig(files = typescriptFiles) {
48
48
  'rxjs-x/no-nested-subscribe': 'error',
49
49
  'rxjs-x/no-redundant-notify': 'error',
50
50
  'rxjs-x/no-sharereplay': 'off',
51
+ 'rxjs-x/no-sharereplay-before-takeuntil': 'error',
51
52
  'rxjs-x/no-subclass': 'error',
52
53
  'rxjs-x/no-subject-unsubscribe': 'error',
53
54
  'rxjs-x/no-subject-value': 'error',
54
55
  'rxjs-x/no-subscribe-handlers': 'off',
55
56
  'rxjs-x/no-topromise': 'error',
56
57
  'rxjs-x/no-unbound-methods': 'error',
58
+ 'rxjs-x/no-unnecessary-collection': 'error',
57
59
  'rxjs-x/no-unsafe-catch': 'error',
58
60
  'rxjs-x/no-unsafe-first': 'error',
59
61
  'rxjs-x/no-unsafe-subject-next': 'error',
@@ -94,7 +94,7 @@ export function stylisticConfig() {
94
94
  allowNamespace: false,
95
95
  ignore: []
96
96
  }],
97
- '@stylistic/jsx-props-no-multi-spaces': 'warn',
97
+ '@stylistic/jsx-props-no-multi-spaces': 'off',
98
98
  '@stylistic/jsx-quotes': ['warn', 'prefer-double'],
99
99
  '@stylistic/jsx-self-closing-comp': ['warn', {
100
100
  component: true,
@@ -161,6 +161,7 @@ export function stylisticConfig() {
161
161
  exceptAfterSingleLine: true,
162
162
  exceptAfterOverload: true
163
163
  }],
164
+ '@stylistic/exp-list-style': 'off',
164
165
  '@stylistic/max-len': ['error', {
165
166
  code: 120,
166
167
  tabWidth: 4,
@@ -197,8 +198,8 @@ export function stylisticConfig() {
197
198
  ignoreJSX: 'all',
198
199
  nestedBinaryExpressions: false,
199
200
  nestedConditionalExpressions: false,
200
- enforceForArrowConditionals: false,
201
- ternaryOperandBinaryExpressions: false
201
+ ternaryOperandBinaryExpressions: false,
202
+ ignoredNodes: ['ArrowFunctionExpression[body.type=ConditionalExpression]']
202
203
  }],
203
204
  '@stylistic/no-extra-semi': 'warn',
204
205
  '@stylistic/no-floating-decimal': 'warn',
@@ -227,6 +228,7 @@ export function stylisticConfig() {
227
228
  }],
228
229
  '@stylistic/object-curly-spacing': ['warn', 'always', {
229
230
  arraysInObjects: true,
231
+ emptyObjects: 'never',
230
232
  objectsInObjects: true
231
233
  }],
232
234
  '@stylistic/object-property-newline': ['warn', {
@@ -8,14 +8,14 @@ export function testingLibraryConfig(files = jestFiles) {
8
8
  },
9
9
  rules: {
10
10
  'testing-library/await-async-events': 'off',
11
- 'testing-library/await-async-queries': 'error',
12
- 'testing-library/await-async-utils': 'error',
11
+ 'testing-library/await-async-queries': 'warn',
12
+ 'testing-library/await-async-utils': 'warn',
13
13
  'testing-library/consistent-data-testid': ['error', {
14
14
  testIdPattern: '^[a-z0-9]+(-[a-z0-9]+)*$',
15
15
  testIdAttribute: 'data-testId'
16
16
  }],
17
17
  'testing-library/no-await-sync-events': 'error',
18
- 'testing-library/no-await-sync-queries': 'error',
18
+ 'testing-library/no-await-sync-queries': 'warn',
19
19
  'testing-library/no-container': 'error',
20
20
  'testing-library/no-debugging-utils': 'error',
21
21
  'testing-library/no-dom-import': 'warn',
@@ -26,7 +26,7 @@ export function testingLibraryConfig(files = jestFiles) {
26
26
  'testing-library/no-render-in-lifecycle': 'error',
27
27
  'testing-library/no-test-id-queries': 'error',
28
28
  'testing-library/no-unnecessary-act': 'off',
29
- 'testing-library/no-wait-for-multiple-assertions': 'error',
29
+ 'testing-library/no-wait-for-multiple-assertions': 'warn',
30
30
  'testing-library/no-wait-for-side-effects': 'error',
31
31
  'testing-library/no-wait-for-snapshot': 'error',
32
32
  'testing-library/prefer-explicit-assert': 'off',
@@ -40,6 +40,7 @@ export function testingLibraryConfig(files = jestFiles) {
40
40
  'testing-library/prefer-query-matchers': 'off',
41
41
  'testing-library/prefer-screen-queries': 'error',
42
42
  'testing-library/prefer-user-event': 'error',
43
+ 'testing-library/prefer-user-event-setup': 'error',
43
44
  'testing-library/render-result-naming-convention': 'error'
44
45
  }
45
46
  };
@@ -68,6 +68,8 @@ export const extensionRules = {
68
68
  }],
69
69
  'no-unused-expressions': 'off',
70
70
  '@typescript-eslint/no-unused-expressions': 'error',
71
+ 'no-unused-private-class-members': 'off',
72
+ '@typescript-eslint/no-unused-private-class-members': 'error',
71
73
  'no-unused-vars': 'off',
72
74
  '@typescript-eslint/no-unused-vars': ['error', {
73
75
  args: 'after-used',
@@ -1 +1,2 @@
1
1
  export { TypescriptEslintNamingConvention, typescriptEslintNamingConvention, TypescriptEslintNamingConventionFormat, TypescriptEslintNamingConventionGroupSelector, TypescriptEslintNamingConventionIndividualSelector, TypescriptEslintNamingConventionSelector, TypescriptEslintNamingConventionUnderscore, } from './rules/typescript-eslint-naming-convention';
2
+ export { typescriptEslintDependentConfig } from './typescript-eslint-config';
@@ -1 +1,2 @@
1
- export { typescriptEslintNamingConvention } from "./rules/typescript-eslint-naming-convention.js";
1
+ export { typescriptEslintNamingConvention } from "./rules/typescript-eslint-naming-convention.js";
2
+ export { typescriptEslintDependentConfig } from "./typescript-eslint-config.js";
@@ -144,10 +144,13 @@ export const supportedRules = {
144
144
  '@typescript-eslint/no-unsafe-declaration-merging': 'error',
145
145
  '@typescript-eslint/no-unsafe-enum-comparison': 'error',
146
146
  '@typescript-eslint/no-unsafe-function-type': 'warn',
147
- '@typescript-eslint/no-unsafe-member-access': 'error',
147
+ '@typescript-eslint/no-unsafe-member-access': ['error', {
148
+ allowOptionalChaining: false
149
+ }],
148
150
  '@typescript-eslint/no-unsafe-return': 'error',
149
151
  '@typescript-eslint/no-unsafe-type-assertion': 'off',
150
152
  '@typescript-eslint/no-unsafe-unary-minus': 'error',
153
+ '@typescript-eslint/no-useless-default-assignment': 'error',
151
154
  '@typescript-eslint/no-useless-empty-export': 'warn',
152
155
  '@typescript-eslint/no-useless-template-literal': 'off',
153
156
  '@typescript-eslint/no-var-requires': ['error', {
@@ -1,2 +1,16 @@
1
- import { Linter } from 'eslint';
1
+ import { ESLint, Linter } from 'eslint';
2
+ import { Glob } from '../../linter/glob';
2
3
  export declare function typescriptEslintConfig(): Linter.Config;
4
+ /**
5
+ * A function to create a flat config for a given `plugin` that requires TypeScript ESLint plugin.
6
+ *
7
+ * This function should be used by other plugin configurations to enable rules that require type information
8
+ * or to change the behavior of the `@typescript-eslint` plugin rules.
9
+ *
10
+ * @param plugin - An ESLint plugin with the rules.
11
+ * @param rules - Rules for the plugin or for the `@typescript-eslint` plugin.
12
+ * @param files - An optional list of globs to narrow down the applicable files.
13
+ *
14
+ * @since v0.34.0
15
+ */
16
+ export declare function typescriptEslintDependentConfig(plugin: ESLint.Plugin, rules: Linter.RulesRecord, files?: Glob[]): Linter.Config;
@@ -1,4 +1,4 @@
1
- import { plugin } from 'typescript-eslint';
1
+ import { plugin as typescriptEslintPlugin } from 'typescript-eslint';
2
2
  import { typescriptFiles } from "../../linter/glob.js";
3
3
  import { typescriptLanguageOptions } from "../../linter/language-options.js";
4
4
  import { extensionRules } from "./extension-rules.js";
@@ -8,8 +8,19 @@ export function typescriptEslintConfig() {
8
8
  files: typescriptFiles,
9
9
  languageOptions: typescriptLanguageOptions(),
10
10
  plugins: {
11
- '@typescript-eslint': plugin
11
+ '@typescript-eslint': typescriptEslintPlugin
12
12
  },
13
13
  rules: Object.assign(Object.assign({}, supportedRules), extensionRules)
14
14
  };
15
+ }
16
+ export function typescriptEslintDependentConfig(plugin, rules, files = typescriptFiles) {
17
+ return {
18
+ files,
19
+ languageOptions: typescriptLanguageOptions(),
20
+ plugins: {
21
+ '@typescript-eslint': typescriptEslintPlugin,
22
+ plugin
23
+ },
24
+ rules
25
+ };
15
26
  }
@@ -36,6 +36,7 @@ export function unicornConfig() {
36
36
  'unicorn/no-array-method-this-argument': 'warn',
37
37
  'unicorn/no-array-reduce': 'off',
38
38
  'unicorn/no-array-reverse': 'off',
39
+ 'unicorn/no-array-sort': 'off',
39
40
  'unicorn/no-await-expression-member': 'error',
40
41
  'unicorn/no-await-in-promise-methods': 'error',
41
42
  'unicorn/no-console-spaces': 'warn',
@@ -43,6 +44,7 @@ export function unicornConfig() {
43
44
  'unicorn/no-empty-file': 'error',
44
45
  'unicorn/no-for-loop': 'warn',
45
46
  'unicorn/no-hex-escape': 'warn',
47
+ 'unicorn/no-immediate-mutation': 'warn',
46
48
  'unicorn/no-instanceof-array': 'off',
47
49
  'unicorn/no-instanceof-builtins': 'warn',
48
50
  'unicorn/no-invalid-fetch-options': 'error',
@@ -79,6 +81,7 @@ export function unicornConfig() {
79
81
  'unicorn/no-unreadable-iife': 'error',
80
82
  'unicorn/no-unsafe-regex': 'off',
81
83
  'unicorn/no-unused-properties': 'off',
84
+ 'unicorn/no-useless-collection-argument': 'warn',
82
85
  'unicorn/no-useless-error-capture-stack-trace': 'warn',
83
86
  'unicorn/no-useless-fallback-in-spread': 'warn',
84
87
  'unicorn/no-useless-length-check': 'warn',
@@ -117,8 +120,10 @@ export function unicornConfig() {
117
120
  'unicorn/prefer-array-index-of': 'warn',
118
121
  'unicorn/prefer-array-some': 'error',
119
122
  'unicorn/prefer-at': 'off',
123
+ 'unicorn/prefer-bigint-literals': 'warn',
120
124
  'unicorn/prefer-blob-reading-methods': 'error',
121
125
  'unicorn/prefer-class-fields': 'warn',
126
+ 'unicorn/prefer-classlist-toggle': 'warn',
122
127
  'unicorn/prefer-code-point': 'error',
123
128
  'unicorn/prefer-date-now': 'warn',
124
129
  'unicorn/prefer-default-parameters': 'warn',
@@ -154,6 +159,7 @@ export function unicornConfig() {
154
159
  'unicorn/prefer-query-selector': 'warn',
155
160
  'unicorn/prefer-reflect-apply': 'warn',
156
161
  'unicorn/prefer-regexp-test': 'off',
162
+ 'unicorn/prefer-response-static-json': 'warn',
157
163
  'unicorn/prefer-set-has': 'warn',
158
164
  'unicorn/prefer-set-size': 'warn',
159
165
  'unicorn/prefer-single-call': ['warn', {
@@ -176,6 +182,7 @@ export function unicornConfig() {
176
182
  'unicorn/prevent-abbreviations': ['warn', unicornPreventAbbreviations()],
177
183
  'unicorn/relative-url-style': ['warn', 'always'],
178
184
  'unicorn/require-array-join-separator': 'warn',
185
+ 'unicorn/require-module-attributes': 'warn',
179
186
  'unicorn/require-module-specifiers': 'warn',
180
187
  'unicorn/require-number-to-fixed-digits-argument': 'warn',
181
188
  'unicorn/require-post-message-target-origin': 'error',
package/linter/glob.d.ts CHANGED
@@ -40,6 +40,22 @@ export declare const typescriptDeclarationFiles: Glob;
40
40
  * @since v0.31.0
41
41
  */
42
42
  export declare const configurationFiles: string[];
43
+ /**
44
+ * The default glob patterns Jest uses to find JavaScript test files.
45
+ *
46
+ * @see https://jestjs.io/docs/configuration#testmatch-arraystring
47
+ *
48
+ * @since v0.34.0
49
+ */
50
+ export declare const jestJavascriptFiles: Glob[];
51
+ /**
52
+ * The default glob patterns Jest uses to find TypeScript test files.
53
+ *
54
+ * @see https://jestjs.io/docs/configuration#testmatch-arraystring
55
+ *
56
+ * @since v0.34.0
57
+ */
58
+ export declare const jestTypescriptFiles: Glob[];
43
59
  /**
44
60
  * The default glob patterns Jest uses to find test files.
45
61
  *
package/linter/glob.js CHANGED
@@ -4,5 +4,7 @@ export const tsxFiles = '**/*.tsx';
4
4
  export const typescriptFiles = ['**/*.{ts,cts,mts}', tsxFiles];
5
5
  export const typescriptDeclarationFiles = '**/*.d.{ts,cts,mts}';
6
6
  export const configurationFiles = ['**/.*.js', '**/*.config.js', '**/gulpfile.js'];
7
- export const jestFiles = ['**/__tests__/**/*.[jt]s?(x)', '**/?(*.)+(spec|test).[jt]s?(x)'];
7
+ export const jestJavascriptFiles = ['**/__tests__/**/*.js?(x)', '**/?(*.)+(spec|test).js?(x)'];
8
+ export const jestTypescriptFiles = ['**/__tests__/**/*.ts?(x)', '**/?(*.)+(spec|test).ts?(x)'];
9
+ export const jestFiles = [...jestJavascriptFiles, ...jestTypescriptFiles];
8
10
  export const cypressFiles = 'cypress/e2e/**/*.cy.{js,jsx,ts,tsx}';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@perfective/eslint-config",
3
- "version": "0.32.0",
3
+ "version": "0.34.0",
4
4
  "description": "ESLint shareable rules configuration",
5
5
  "keywords": ["code quality", "code standard", "code style", "eslint", "eslint config", "lint", "perfective", "tslint", "tslint config", "typescript"],
6
6
  "author": "Andrey Mikheychik <a.mikheychik@gmail.com>",
@@ -13,24 +13,24 @@
13
13
  "license": "MIT",
14
14
  "peerDependencies": {
15
15
  "@eslint-community/eslint-plugin-eslint-comments": "^4.5.0",
16
- "@stylistic/eslint-plugin": "^5.2.3",
17
- "eslint": "^9.34.0",
16
+ "@stylistic/eslint-plugin": "^5.6.1",
17
+ "eslint": "^9.39.2",
18
18
  "eslint-import-resolver-typescript": "^3.10.1",
19
- "eslint-plugin-array-func": "^5.0.2",
20
- "eslint-plugin-cypress": "^5.1.1",
19
+ "eslint-plugin-array-func": "^5.1.0",
20
+ "eslint-plugin-cypress": "^5.2.1",
21
21
  "eslint-plugin-import": "^2.32.0",
22
- "eslint-plugin-jest": "^29.0.1",
22
+ "eslint-plugin-jest": "^29.12.1",
23
23
  "eslint-plugin-jest-dom": "^5.5.0",
24
- "eslint-plugin-jsdoc": "^54.1.1",
25
- "eslint-plugin-n": "^17.21.3",
24
+ "eslint-plugin-jsdoc": "^61.7.1",
25
+ "eslint-plugin-n": "^17.23.1",
26
26
  "eslint-plugin-prefer-arrow": "^1.2.3",
27
27
  "eslint-plugin-promise": "^7.2.1",
28
- "eslint-plugin-rxjs-x": "~0.7.7",
28
+ "eslint-plugin-rxjs-x": "~0.8.4",
29
29
  "eslint-plugin-security": "^3.0.1",
30
30
  "eslint-plugin-simple-import-sort": "^12.1.1",
31
- "eslint-plugin-testing-library": "^7.6.6",
32
- "eslint-plugin-unicorn": "^60.0.0",
33
- "typescript-eslint": "^8.40.0"
31
+ "eslint-plugin-testing-library": "^7.15.4",
32
+ "eslint-plugin-unicorn": "^62.0.0",
33
+ "typescript-eslint": "^8.52.0"
34
34
  },
35
35
  "peerDependenciesMeta": {
36
36
  "eslint-plugin-cypress": {
@@ -1,2 +0,0 @@
1
- import { Linter } from 'eslint';
2
- export declare const typescriptEslintJestRules: Linter.RulesRecord;
@@ -1,5 +0,0 @@
1
- export const typescriptEslintJestRules = {
2
- 'jest/unbound-method': ['error', {
3
- ignoreStatic: false
4
- }]
5
- };