eslint-config-typed 4.0.9 → 4.2.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.
Files changed (99) hide show
  1. package/dist/configs/plugins.d.mts +1 -1
  2. package/dist/configs/plugins.d.mts.map +1 -1
  3. package/dist/configs/plugins.mjs +2 -0
  4. package/dist/configs/plugins.mjs.map +1 -1
  5. package/dist/configs/typescript.d.mts.map +1 -1
  6. package/dist/configs/typescript.mjs +2 -0
  7. package/dist/configs/typescript.mjs.map +1 -1
  8. package/dist/entry-point.mjs +2 -0
  9. package/dist/entry-point.mjs.map +1 -1
  10. package/dist/index.mjs +2 -0
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/plugins/immer-coding-style/index.d.mts +2 -0
  13. package/dist/plugins/immer-coding-style/index.d.mts.map +1 -0
  14. package/dist/plugins/immer-coding-style/index.mjs +2 -0
  15. package/dist/plugins/immer-coding-style/index.mjs.map +1 -0
  16. package/dist/plugins/immer-coding-style/plugin.d.mts +3 -0
  17. package/dist/plugins/immer-coding-style/plugin.d.mts.map +1 -0
  18. package/dist/plugins/immer-coding-style/plugin.mjs +8 -0
  19. package/dist/plugins/immer-coding-style/plugin.mjs.map +1 -0
  20. package/dist/plugins/immer-coding-style/rules/index.d.mts +2 -0
  21. package/dist/plugins/immer-coding-style/rules/index.d.mts.map +1 -0
  22. package/dist/plugins/immer-coding-style/rules/index.mjs +2 -0
  23. package/dist/plugins/immer-coding-style/rules/index.mjs.map +1 -0
  24. package/dist/plugins/immer-coding-style/rules/prefer-curried-produce.d.mts +5 -0
  25. package/dist/plugins/immer-coding-style/rules/prefer-curried-produce.d.mts.map +1 -0
  26. package/dist/plugins/immer-coding-style/rules/prefer-curried-produce.mjs +158 -0
  27. package/dist/plugins/immer-coding-style/rules/prefer-curried-produce.mjs.map +1 -0
  28. package/dist/plugins/immer-coding-style/rules/rules.d.mts +4 -0
  29. package/dist/plugins/immer-coding-style/rules/rules.d.mts.map +1 -0
  30. package/dist/plugins/immer-coding-style/rules/rules.mjs +8 -0
  31. package/dist/plugins/immer-coding-style/rules/rules.mjs.map +1 -0
  32. package/dist/plugins/index.d.mts +1 -0
  33. package/dist/plugins/index.d.mts.map +1 -1
  34. package/dist/plugins/index.mjs +1 -0
  35. package/dist/plugins/index.mjs.map +1 -1
  36. package/dist/rules/eslint-immer-coding-style-rules.d.mts +4 -0
  37. package/dist/rules/eslint-immer-coding-style-rules.d.mts.map +1 -0
  38. package/dist/rules/eslint-immer-coding-style-rules.mjs +6 -0
  39. package/dist/rules/eslint-immer-coding-style-rules.mjs.map +1 -0
  40. package/dist/rules/eslint-jest-rules.d.mts +3 -0
  41. package/dist/rules/eslint-jest-rules.d.mts.map +1 -1
  42. package/dist/rules/eslint-jest-rules.mjs +3 -0
  43. package/dist/rules/eslint-jest-rules.mjs.map +1 -1
  44. package/dist/rules/eslint-testing-library-rules.d.mts +1 -0
  45. package/dist/rules/eslint-testing-library-rules.d.mts.map +1 -1
  46. package/dist/rules/eslint-testing-library-rules.mjs +1 -0
  47. package/dist/rules/eslint-testing-library-rules.mjs.map +1 -1
  48. package/dist/rules/eslint-vitest-rules.d.mts +1 -0
  49. package/dist/rules/eslint-vitest-rules.d.mts.map +1 -1
  50. package/dist/rules/eslint-vitest-rules.mjs +1 -0
  51. package/dist/rules/eslint-vitest-rules.mjs.map +1 -1
  52. package/dist/rules/index.d.mts +1 -0
  53. package/dist/rules/index.d.mts.map +1 -1
  54. package/dist/rules/index.mjs +1 -0
  55. package/dist/rules/index.mjs.map +1 -1
  56. package/dist/rules/typescript-eslint-rules.d.mts +1 -0
  57. package/dist/rules/typescript-eslint-rules.d.mts.map +1 -1
  58. package/dist/rules/typescript-eslint-rules.mjs +1 -0
  59. package/dist/rules/typescript-eslint-rules.mjs.map +1 -1
  60. package/dist/types/define-known-rules.d.mts +2 -2
  61. package/dist/types/define-known-rules.d.mts.map +1 -1
  62. package/dist/types/define-known-rules.mjs.map +1 -1
  63. package/dist/types/rules/eslint-immer-coding-style-rules.d.mts +20 -0
  64. package/dist/types/rules/eslint-immer-coding-style-rules.d.mts.map +1 -0
  65. package/dist/types/rules/eslint-immer-coding-style-rules.mjs +2 -0
  66. package/dist/types/rules/eslint-immer-coding-style-rules.mjs.map +1 -0
  67. package/dist/types/rules/eslint-jest-rules.d.mts +116 -65
  68. package/dist/types/rules/eslint-jest-rules.d.mts.map +1 -1
  69. package/dist/types/rules/eslint-testing-library-rules.d.mts +16 -0
  70. package/dist/types/rules/eslint-testing-library-rules.d.mts.map +1 -1
  71. package/dist/types/rules/eslint-vitest-rules.d.mts +17 -0
  72. package/dist/types/rules/eslint-vitest-rules.d.mts.map +1 -1
  73. package/dist/types/rules/index.d.mts +1 -0
  74. package/dist/types/rules/index.d.mts.map +1 -1
  75. package/dist/types/rules/typescript-eslint-rules.d.mts +19 -0
  76. package/dist/types/rules/typescript-eslint-rules.d.mts.map +1 -1
  77. package/package.json +24 -23
  78. package/src/configs/plugins.mts +3 -0
  79. package/src/configs/typescript.mts +2 -0
  80. package/src/plugins/immer-coding-style/index.mts +1 -0
  81. package/src/plugins/immer-coding-style/plugin.mts +6 -0
  82. package/src/plugins/immer-coding-style/rules/index.mts +1 -0
  83. package/src/plugins/immer-coding-style/rules/prefer-curried-produce.mts +293 -0
  84. package/src/plugins/immer-coding-style/rules/prefer-curried-produce.test.mts +124 -0
  85. package/src/plugins/immer-coding-style/rules/rules.mts +6 -0
  86. package/src/plugins/index.mts +1 -0
  87. package/src/rules/eslint-immer-coding-style-rules.mts +5 -0
  88. package/src/rules/eslint-jest-rules.mts +3 -0
  89. package/src/rules/eslint-testing-library-rules.mts +1 -0
  90. package/src/rules/eslint-vitest-rules.mts +1 -0
  91. package/src/rules/index.mts +1 -0
  92. package/src/rules/typescript-eslint-rules.mts +1 -0
  93. package/src/types/define-known-rules.mts +2 -0
  94. package/src/types/rules/eslint-immer-coding-style-rules.mts +21 -0
  95. package/src/types/rules/eslint-jest-rules.mts +119 -65
  96. package/src/types/rules/eslint-testing-library-rules.mts +17 -0
  97. package/src/types/rules/eslint-vitest-rules.mts +18 -0
  98. package/src/types/rules/index.mts +1 -0
  99. package/src/types/rules/typescript-eslint-rules.mts +20 -0
@@ -0,0 +1,293 @@
1
+ import {
2
+ AST_NODE_TYPES,
3
+ type TSESLint,
4
+ type TSESTree,
5
+ } from '@typescript-eslint/utils';
6
+ import { castDeepMutable, hasKey, isRecord } from 'ts-data-forge';
7
+
8
+ type MessageIds = 'useCurriedProduce';
9
+
10
+ type CallExpressionWithLegacyTypeParameters = TSESTree.CallExpression &
11
+ Readonly<{
12
+ typeParameters?: TSESTree.TSTypeParameterInstantiation;
13
+ }>;
14
+
15
+ export const preferCurriedProduceRule: TSESLint.RuleModule<MessageIds> = {
16
+ meta: {
17
+ type: 'suggestion',
18
+ docs: {
19
+ description:
20
+ 'Prefer the curried overload of immer produce for shorter updater definitions.',
21
+ },
22
+ fixable: 'code',
23
+ schema: [],
24
+ messages: {
25
+ useCurriedProduce:
26
+ 'Use the curried overload of `produce`: `produce(recipe)` instead of `(state) => produce(state, recipe)`.',
27
+ },
28
+ },
29
+ create: (context) => {
30
+ const sourceCode = context.sourceCode;
31
+
32
+ return {
33
+ ArrowFunctionExpression: (
34
+ node: DeepReadonly<TSESTree.ArrowFunctionExpression>,
35
+ ) => {
36
+ if (node.params.length !== 1) {
37
+ return;
38
+ }
39
+
40
+ const param = node.params[0];
41
+
42
+ if (
43
+ param === undefined ||
44
+ param.type !== AST_NODE_TYPES.Identifier ||
45
+ param.name.length === 0
46
+ ) {
47
+ return;
48
+ }
49
+
50
+ const { name: parameterName } = param;
51
+
52
+ const callExpression = node.body;
53
+
54
+ if (!isProduceCall(callExpression)) {
55
+ return;
56
+ }
57
+
58
+ const [baseArgument, ...restArguments] = callExpression.arguments;
59
+
60
+ if (
61
+ baseArgument === undefined ||
62
+ restArguments.length === 0 ||
63
+ !isSameIdentifier(baseArgument, parameterName)
64
+ ) {
65
+ return;
66
+ }
67
+
68
+ if (hasOtherReferences(context, parameterName, baseArgument)) {
69
+ return;
70
+ }
71
+
72
+ report(context, {
73
+ arrowFunction: node,
74
+ callExpression,
75
+ remainingArguments: restArguments,
76
+ sourceCode,
77
+ });
78
+ },
79
+ };
80
+ },
81
+ defaultOptions: [],
82
+ };
83
+
84
+ type ReportContext = Readonly<{
85
+ arrowFunction: DeepReadonly<TSESTree.ArrowFunctionExpression>;
86
+ callExpression: DeepReadonly<TSESTree.CallExpression>;
87
+ remainingArguments: readonly DeepReadonly<TSESTree.CallExpressionArgument>[];
88
+ sourceCode: Readonly<{
89
+ getText: TSESLint.SourceCode['getText'];
90
+ }>;
91
+ }>;
92
+
93
+ const report = (
94
+ context: DeepReadonly<TSESLint.RuleContext<MessageIds, readonly []>>,
95
+ {
96
+ arrowFunction,
97
+ callExpression,
98
+ remainingArguments,
99
+ sourceCode,
100
+ }: ReportContext,
101
+ ): void => {
102
+ const calleeText = sourceCode.getText(castDeepMutable(callExpression.callee));
103
+
104
+ const typeParametersText = getTypeParametersText({
105
+ arrowFunction,
106
+ callExpression,
107
+ sourceCode,
108
+ });
109
+
110
+ const remainingArgumentsText = remainingArguments
111
+ .map((argument) =>
112
+ normalizeMultilineText(sourceCode.getText(castDeepMutable(argument))),
113
+ )
114
+ .join(', ');
115
+
116
+ const replacement = `${calleeText}${typeParametersText}(${remainingArgumentsText})`;
117
+
118
+ context.report({
119
+ node: castDeepMutable(arrowFunction),
120
+ messageId: 'useCurriedProduce',
121
+ fix: (fixer) =>
122
+ fixer.replaceText(castDeepMutable(arrowFunction), replacement),
123
+ });
124
+ };
125
+
126
+ const isProduceCall = (
127
+ node: DeepReadonly<TSESTree.Node>,
128
+ ): node is TSESTree.CallExpression => {
129
+ if (node.type !== AST_NODE_TYPES.CallExpression) {
130
+ return false;
131
+ }
132
+
133
+ return (
134
+ node.callee.type === AST_NODE_TYPES.Identifier &&
135
+ node.callee.name === 'produce'
136
+ );
137
+ };
138
+
139
+ const isSameIdentifier = (
140
+ node: DeepReadonly<TSESTree.CallExpressionArgument>,
141
+ expectedName: string,
142
+ ): node is TSESTree.Identifier =>
143
+ node.type === AST_NODE_TYPES.Identifier && node.name === expectedName;
144
+
145
+ const hasOtherReferences = (
146
+ context: DeepReadonly<TSESLint.RuleContext<MessageIds, readonly []>>,
147
+ parameterName: string,
148
+ baseIdentifier: DeepReadonly<TSESTree.Identifier>,
149
+ ): boolean => {
150
+ const scope = context.sourceCode.getScope(castDeepMutable(baseIdentifier));
151
+
152
+ const variable = scope.variables.find(
153
+ (variableItem) => variableItem.name === parameterName,
154
+ );
155
+
156
+ if (variable === undefined) {
157
+ return true;
158
+ }
159
+
160
+ return variable.references.some(
161
+ (reference) => reference.identifier !== baseIdentifier,
162
+ );
163
+ };
164
+
165
+ const getTypeArguments = (
166
+ node: DeepReadonly<TSESTree.CallExpression>,
167
+ ): TSESTree.TSTypeParameterInstantiation | undefined => {
168
+ const mutableNode = castDeepMutable(node);
169
+
170
+ if (isRecord(mutableNode) && hasKey(mutableNode, 'typeArguments')) {
171
+ return (
172
+ mutableNode as TSESTree.CallExpression & {
173
+ typeArguments?: TSESTree.TSTypeParameterInstantiation;
174
+ }
175
+ ).typeArguments;
176
+ }
177
+
178
+ if (isRecord(mutableNode) && hasKey(mutableNode, 'typeParameters')) {
179
+ return (mutableNode as CallExpressionWithLegacyTypeParameters)
180
+ .typeParameters;
181
+ }
182
+
183
+ return undefined;
184
+ };
185
+
186
+ const getTypeParametersText = ({
187
+ arrowFunction,
188
+ callExpression,
189
+ sourceCode,
190
+ }: Readonly<{
191
+ arrowFunction: DeepReadonly<TSESTree.ArrowFunctionExpression>;
192
+ callExpression: DeepReadonly<TSESTree.CallExpression>;
193
+ sourceCode: Readonly<{
194
+ getText: TSESLint.SourceCode['getText'];
195
+ }>;
196
+ }>): string => {
197
+ const typeArguments = getTypeArguments(callExpression);
198
+
199
+ if (typeArguments !== undefined) {
200
+ return sourceCode.getText(castDeepMutable(typeArguments));
201
+ }
202
+
203
+ const parameterType = getArrowFunctionParameterType({
204
+ arrowFunction,
205
+ sourceCode,
206
+ });
207
+
208
+ if (parameterType !== undefined) {
209
+ return `<${parameterType}>`;
210
+ }
211
+
212
+ const returnType = getArrowFunctionReturnType({
213
+ arrowFunction,
214
+ sourceCode,
215
+ });
216
+
217
+ if (returnType !== undefined) {
218
+ return `<${returnType}>`;
219
+ }
220
+
221
+ return '';
222
+ };
223
+
224
+ const getArrowFunctionParameterType = ({
225
+ arrowFunction,
226
+ sourceCode,
227
+ }: Readonly<{
228
+ arrowFunction: DeepReadonly<TSESTree.ArrowFunctionExpression>;
229
+ sourceCode: Readonly<{
230
+ getText: TSESLint.SourceCode['getText'];
231
+ }>;
232
+ }>): string | undefined => {
233
+ const [parameter] = arrowFunction.params;
234
+
235
+ if (parameter?.type !== AST_NODE_TYPES.Identifier) {
236
+ return undefined;
237
+ }
238
+
239
+ const typeAnnotation = parameter.typeAnnotation?.typeAnnotation;
240
+
241
+ if (typeAnnotation === undefined) {
242
+ return undefined;
243
+ }
244
+
245
+ return sourceCode.getText(castDeepMutable(typeAnnotation));
246
+ };
247
+
248
+ const getArrowFunctionReturnType = ({
249
+ arrowFunction,
250
+ sourceCode,
251
+ }: Readonly<{
252
+ arrowFunction: DeepReadonly<TSESTree.ArrowFunctionExpression>;
253
+ sourceCode: Readonly<{
254
+ getText: TSESLint.SourceCode['getText'];
255
+ }>;
256
+ }>): string | undefined => {
257
+ const typeAnnotation = arrowFunction.returnType?.typeAnnotation;
258
+
259
+ if (typeAnnotation === undefined) {
260
+ return undefined;
261
+ }
262
+
263
+ return sourceCode.getText(castDeepMutable(typeAnnotation));
264
+ };
265
+
266
+ const normalizeMultilineText = (text: string): string => {
267
+ const lines = text.split('\n');
268
+
269
+ if (lines.length <= 1) {
270
+ return text;
271
+ }
272
+
273
+ const indents = lines
274
+ .slice(1)
275
+ .filter((line) => line.trim().length > 0)
276
+ .map((line) => /^[\t ]*/u.exec(line)?.[0].length ?? 0);
277
+
278
+ if (indents.length === 0) {
279
+ return text;
280
+ }
281
+
282
+ const minIndent = Math.min(...indents);
283
+
284
+ if (minIndent === 0) {
285
+ return text;
286
+ }
287
+
288
+ const normalized = lines.map((line, index) =>
289
+ index === 0 ? line : line.slice(minIndent),
290
+ );
291
+
292
+ return normalized.join('\n');
293
+ };
@@ -0,0 +1,124 @@
1
+ import parser from '@typescript-eslint/parser';
2
+ import { RuleTester } from '@typescript-eslint/rule-tester';
3
+ import dedent from 'dedent';
4
+ import { preferCurriedProduceRule } from './prefer-curried-produce.mjs';
5
+
6
+ const ruleName = 'prefer-curried-produce';
7
+
8
+ const tester = new RuleTester({
9
+ languageOptions: {
10
+ parser,
11
+ parserOptions: {
12
+ ecmaVersion: 2020,
13
+ sourceType: 'module',
14
+ },
15
+ },
16
+ });
17
+
18
+ describe('prefer-curried-produce', () => {
19
+ tester.run(ruleName, preferCurriedProduceRule, {
20
+ valid: [
21
+ {
22
+ name: 'Already curried',
23
+ code: dedent`
24
+ import { produce } from 'immer';
25
+
26
+ const update = produce((draft) => {
27
+ draft.count += 1;
28
+ });
29
+ `,
30
+ },
31
+ {
32
+ name: 'Already curried with type arg',
33
+ code: dedent`
34
+ import { produce } from 'immer';
35
+
36
+ const update = produce<State>((draft) => {
37
+ draft.count += 1;
38
+ });
39
+ `,
40
+ },
41
+ {
42
+ name: 'Multiple parameters are ignored',
43
+ code: dedent`
44
+ import { produce } from 'immer';
45
+
46
+ const update = (state, action) =>
47
+ produce(state, (draft) => {
48
+ draft.count += action.delta;
49
+ });
50
+ `,
51
+ },
52
+ {
53
+ name: 'Base state differs from parameter',
54
+ code: dedent`
55
+ import { produce } from 'immer';
56
+
57
+ const update = (state) =>
58
+ produce(other, (draft) => {
59
+ draft.count += state.delta;
60
+ });
61
+ `,
62
+ },
63
+ {
64
+ name: 'Parameter referenced inside recipe is ignored',
65
+ code: dedent`
66
+ import { produce } from 'immer';
67
+
68
+ const update = (state) =>
69
+ produce(state, (draft) => {
70
+ draft.count += state.delta;
71
+ });
72
+ `,
73
+ },
74
+ ],
75
+ invalid: [
76
+ {
77
+ name: 'Transforms simple updater',
78
+ code: dedent`
79
+ import { produce } from 'immer';
80
+
81
+ const update = (state) =>
82
+ produce(state, (draft) => {
83
+ draft.count += 1;
84
+ });
85
+ `,
86
+ output: dedent`
87
+ import { produce } from 'immer';
88
+
89
+ const update = produce((draft) => {
90
+ draft.count += 1;
91
+ });
92
+ `,
93
+ errors: [
94
+ {
95
+ messageId: 'useCurriedProduce',
96
+ },
97
+ ],
98
+ },
99
+ {
100
+ name: 'Transforms simple updater with type annotations',
101
+ code: dedent`
102
+ import { produce } from 'immer';
103
+
104
+ const update = (state: State): State =>
105
+ produce(state, (draft) => {
106
+ draft.count += 1;
107
+ });
108
+ `,
109
+ output: dedent`
110
+ import { produce } from 'immer';
111
+
112
+ const update = produce<State>((draft) => {
113
+ draft.count += 1;
114
+ });
115
+ `,
116
+ errors: [
117
+ {
118
+ messageId: 'useCurriedProduce',
119
+ },
120
+ ],
121
+ },
122
+ ],
123
+ });
124
+ });
@@ -0,0 +1,6 @@
1
+ import { type ESLintPlugin } from '../../../types/index.mjs';
2
+ import { preferCurriedProduceRule } from './prefer-curried-produce.mjs';
3
+
4
+ export const immerCodingStyleRules = {
5
+ 'prefer-curried-produce': preferCurriedProduceRule,
6
+ } as const satisfies ESLintPlugin['rules'];
@@ -1,3 +1,4 @@
1
+ export * from './immer-coding-style/index.mjs';
1
2
  export * from './react-coding-style/index.mjs';
2
3
  export * from './strict-dependencies/index.mjs';
3
4
  export * from './total-functions/index.mjs';
@@ -0,0 +1,5 @@
1
+ import { type EslintImmerCodingStyleRules } from '../types/index.mjs';
2
+
3
+ export const eslintImmerCodingStyleRules = {
4
+ 'immer-coding-style/prefer-curried-produce': 'error',
5
+ } as const satisfies EslintImmerCodingStyleRules;
@@ -82,6 +82,9 @@ export const eslintJestRules = {
82
82
  'jest/unbound-method': withDefaultOption('error'),
83
83
  'jest/valid-expect-in-promise': 'error',
84
84
  'jest/prefer-ending-with-an-expect': withDefaultOption('error'),
85
+ 'jest/no-unneeded-async-expect-function': 'error',
86
+ 'jest/prefer-to-have-been-called': 'error',
87
+ 'jest/prefer-to-have-been-called-times': 'error',
85
88
 
86
89
  'jest/valid-mock-module-path': withDefaultOption('error'),
87
90
  } as const satisfies EslintJestRules;
@@ -30,6 +30,7 @@ export const eslintTestingLibraryRules = {
30
30
  'testing-library/prefer-screen-queries': 'error',
31
31
  'testing-library/render-result-naming-convention': 'error',
32
32
  'testing-library/no-test-id-queries': 'error',
33
+ 'testing-library/prefer-user-event-setup': 'error',
33
34
 
34
35
  'testing-library/consistent-data-testid': 'off',
35
36
  'testing-library/prefer-explicit-assert': 'off',
@@ -117,6 +117,7 @@ export const eslintVitestRules = {
117
117
  },
118
118
  ],
119
119
  'vitest/require-import-vi-mock': 'error',
120
+ 'vitest/no-unneeded-async-expect-function': 'error',
120
121
 
121
122
  // deprecated
122
123
  'vitest/no-done-callback': 0,
@@ -1,6 +1,7 @@
1
1
  export * from './eslint-array-func-rules.mjs';
2
2
  export * from './eslint-cypress-rules.mjs';
3
3
  export * from './eslint-functional-rules.mjs';
4
+ export * from './eslint-immer-coding-style-rules.mjs';
4
5
  export * from './eslint-import-rules.mjs';
5
6
  export * from './eslint-jest-rules.mjs';
6
7
  export * from './eslint-jsx-a11y-rules.mjs';
@@ -489,6 +489,7 @@ export const typescriptEslintRules = {
489
489
  '@typescript-eslint/no-unnecessary-type-conversion': 'error',
490
490
 
491
491
  '@typescript-eslint/no-unused-private-class-members': 'error',
492
+ '@typescript-eslint/no-useless-default-assignment': 'error',
492
493
 
493
494
  // For browser environment only
494
495
 
@@ -2,6 +2,7 @@ import {
2
2
  type EslintArrayFuncRules,
3
3
  type EslintCypressRules,
4
4
  type EslintFunctionalRules,
5
+ type EslintImmerCodingStyleRules,
5
6
  type EslintImportsRules,
6
7
  type EslintJestRules,
7
8
  type EslintJsxA11yRules,
@@ -60,6 +61,7 @@ type KnownRules = DeepReadonly<
60
61
  EslintUnicornRules &
61
62
  EslintVitestRules &
62
63
  EslintVitestCodingStyleRules &
64
+ EslintImmerCodingStyleRules &
63
65
  EslintReactCodingStyleRules &
64
66
  TypeScriptEslintRules
65
67
  >;
@@ -0,0 +1,21 @@
1
+ /* cSpell:disable */
2
+ import { type Linter } from 'eslint';
3
+
4
+ /**
5
+ * Prefer the curried overload of immer produce for shorter updater definitions.
6
+ *
7
+ * ```md
8
+ * | key | value |
9
+ * | :--------- | :--------- |
10
+ * | type | suggestion |
11
+ * | deprecated | false |
12
+ * | fixable | code |
13
+ * ```
14
+ */
15
+ namespace PreferCurriedProduce {
16
+ export type RuleEntry = Linter.StringSeverity;
17
+ }
18
+
19
+ export type EslintImmerCodingStyleRules = Readonly<{
20
+ 'immer-coding-style/prefer-curried-produce': PreferCurriedProduce.RuleEntry;
21
+ }>;