@typescript-eslint/eslint-plugin 8.67.1-alpha.28 → 8.67.1-alpha.29

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/dist/index.d.ts CHANGED
@@ -1096,7 +1096,7 @@ declare const _default: {
1096
1096
  'strict-boolean-expressions': import("@typescript-eslint/utils/ts-eslint").RuleModule<import("./rules/strict-boolean-expressions").MessageId, import("./rules/strict-boolean-expressions").Options, import("../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
1097
1097
  name: string;
1098
1098
  };
1099
- 'strict-void-return': import("@typescript-eslint/utils/ts-eslint").RuleModule<"asyncFunc" | "nonVoidFunc" | "nonVoidReturn", [{
1099
+ 'strict-void-return': import("@typescript-eslint/utils/ts-eslint").RuleModule<"asyncFunc" | "nonVoidFunc" | "nonVoidReturn" | "suggestAddVoidOp" | "suggestWrapInAsyncIIFE", [{
1100
1100
  allowReturnAny?: boolean;
1101
1101
  }], import("../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
1102
1102
  name: string;
@@ -1119,7 +1119,7 @@ declare const _default: {
1119
1119
  'strict-boolean-expressions': TSESLint.RuleModule<import("./rules/strict-boolean-expressions").MessageId, import("./rules/strict-boolean-expressions").Options, import("../rules").ESLintPluginDocs, TSESLint.RuleListener> & {
1120
1120
  name: string;
1121
1121
  };
1122
- 'strict-void-return': TSESLint.RuleModule<"asyncFunc" | "nonVoidFunc" | "nonVoidReturn", [{
1122
+ 'strict-void-return': TSESLint.RuleModule<"asyncFunc" | "nonVoidFunc" | "nonVoidReturn" | "suggestAddVoidOp" | "suggestWrapInAsyncIIFE", [{
1123
1123
  allowReturnAny?: boolean;
1124
1124
  }], import("../rules").ESLintPluginDocs, TSESLint.RuleListener> & {
1125
1125
  name: string;
@@ -421,7 +421,7 @@ declare const rules: {
421
421
  'strict-boolean-expressions': import("@typescript-eslint/utils/ts-eslint").RuleModule<import("./strict-boolean-expressions").MessageId, import("./strict-boolean-expressions").Options, import("../../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
422
422
  name: string;
423
423
  };
424
- 'strict-void-return': import("@typescript-eslint/utils/ts-eslint").RuleModule<"asyncFunc" | "nonVoidFunc" | "nonVoidReturn", [{
424
+ 'strict-void-return': import("@typescript-eslint/utils/ts-eslint").RuleModule<"asyncFunc" | "nonVoidFunc" | "nonVoidReturn" | "suggestAddVoidOp" | "suggestWrapInAsyncIIFE", [{
425
425
  allowReturnAny?: boolean;
426
426
  }], import("../../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
427
427
  name: string;
@@ -139,15 +139,13 @@ exports.default = (0, util_1.createRule)({
139
139
  if (!canFix(arrowFunction)) {
140
140
  return null;
141
141
  }
142
- const arrowBody = arrowFunction.body;
143
- const arrowBodyText = context.sourceCode.getText(arrowBody);
144
- const newArrowBodyText = `{ ${arrowBodyText}; }`;
145
- if ((0, util_1.isParenthesized)(arrowBody, context.sourceCode)) {
146
- const bodyOpeningParen = (0, util_1.nullThrows)(context.sourceCode.getTokenBefore(arrowBody, util_1.isOpeningParenToken), util_1.NullThrowsReasons.MissingToken('opening parenthesis', 'arrow body'));
147
- const bodyClosingParen = (0, util_1.nullThrows)(context.sourceCode.getTokenAfter(arrowBody, util_1.isClosingParenToken), util_1.NullThrowsReasons.MissingToken('closing parenthesis', 'arrow body'));
148
- return fixer.replaceTextRange([bodyOpeningParen.range[0], bodyClosingParen.range[1]], newArrowBodyText);
149
- }
150
- return fixer.replaceText(arrowBody, newArrowBodyText);
142
+ const arrowToken = (0, util_1.nullThrows)(context.sourceCode.getTokenBefore(arrowFunction.body, {
143
+ filter: token => token.value === '=>',
144
+ }), util_1.NullThrowsReasons.MissingToken('arrow token', 'before arrow function body'));
145
+ return [
146
+ fixer.replaceTextRange([arrowToken.range[1], arrowFunction.body.range[0]], ' { '),
147
+ fixer.replaceTextRange([arrowFunction.body.range[1], arrowFunction.range[1]], '; }'),
148
+ ];
151
149
  },
152
150
  });
153
151
  }
@@ -1,10 +1,11 @@
1
+ import type { TSESLint } from '@typescript-eslint/utils';
1
2
  type Options = [
2
3
  {
3
4
  allowReturnAny?: boolean;
4
5
  }
5
6
  ];
6
- type MessageId = `asyncFunc` | `nonVoidFunc` | `nonVoidReturn`;
7
- declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<MessageId, Options, import("../../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
7
+ type MessageId = `asyncFunc` | `nonVoidFunc` | `nonVoidReturn` | `suggestAddVoidOp` | `suggestWrapInAsyncIIFE`;
8
+ declare const _default: TSESLint.RuleModule<MessageId, Options, import("../../rules").ESLintPluginDocs, TSESLint.RuleListener> & {
8
9
  name: string;
9
10
  };
10
11
  export default _default;
@@ -45,10 +45,13 @@ exports.default = util.createRule({
45
45
  description: 'Disallow passing a value-returning function in a position accepting a void function',
46
46
  requiresTypeChecking: true,
47
47
  },
48
+ hasSuggestions: true,
48
49
  messages: {
49
50
  asyncFunc: 'Async function used in a context where a void function is expected.',
50
51
  nonVoidFunc: 'Value-returning function used in a context where a void function is expected.',
51
52
  nonVoidReturn: 'Value returned in a context where a void return is expected.',
53
+ suggestAddVoidOp: 'Add a void operator to discard the return value.',
54
+ suggestWrapInAsyncIIFE: 'Wrap the function body in an async IIFE.',
52
55
  },
53
56
  schema: [
54
57
  {
@@ -324,20 +327,55 @@ exports.default = util.createRule({
324
327
  }
325
328
  if (funcNode.async) {
326
329
  // The provided function is an async function.
327
- // Async functions aren't allowed.
330
+ if (funcNode.body.type !== utils_1.AST_NODE_TYPES.BlockStatement) {
331
+ // This async function is an arrow function shorthand without braces.
332
+ return context.report({
333
+ loc: util.getFunctionHeadLoc(funcNode, sourceCode),
334
+ messageId: 'asyncFunc',
335
+ suggest: utils_1.ASTUtils.hasSideEffect(funcNode.body, sourceCode)
336
+ ? // This function has side effects, e.g. `async () => doSomething()`.
337
+ // Suggest removing the async keyword and adding a void operator.
338
+ [
339
+ {
340
+ messageId: 'suggestAddVoidOp',
341
+ fix: fixer => addVoidToArrowFix(fixer, funcNode),
342
+ },
343
+ ]
344
+ : [],
345
+ });
346
+ }
347
+ // This async function has a block body.
348
+ // Suggest wrapping its body in an async IIFE.
328
349
  return context.report({
329
350
  loc: util.getFunctionHeadLoc(funcNode, sourceCode),
330
- messageId: `asyncFunc`,
351
+ messageId: 'asyncFunc',
352
+ suggest: [
353
+ {
354
+ messageId: 'suggestWrapInAsyncIIFE',
355
+ fix: fixer => wrapInAsyncIIFEFix(fixer, funcNode),
356
+ },
357
+ ],
331
358
  });
332
359
  }
360
+ // This function is a regular or arrow sync function.
333
361
  if (funcNode.body.type !== utils_1.AST_NODE_TYPES.BlockStatement) {
334
- // The provided function is an arrow function shorthand without braces.
362
+ // This function is an arrow function shorthand without braces.
335
363
  return context.report({
336
364
  node: funcNode.body,
337
- messageId: `nonVoidReturn`,
365
+ messageId: 'nonVoidReturn',
366
+ suggest: utils_1.ASTUtils.hasSideEffect(funcNode.body, sourceCode)
367
+ ? // This function has side effects, e.g. `() => doSomething()`.
368
+ // Suggest adding a void operator.
369
+ [
370
+ {
371
+ messageId: 'suggestAddVoidOp',
372
+ fix: fixer => addVoidToArrowFix(fixer, funcNode),
373
+ },
374
+ ]
375
+ : [],
338
376
  });
339
377
  }
340
- // The function is a regular or arrow function with a block body.
378
+ // This function is a regular or arrow sync function with a block body.
341
379
  // Check return type annotation.
342
380
  if (funcNode.returnType != null) {
343
381
  // The provided function has an explicit return type annotation.
@@ -373,6 +411,59 @@ exports.default = util.createRule({
373
411
  }
374
412
  // No invalid returns found. The function is allowed.
375
413
  }
414
+ /**
415
+ * Removes the async keyword and replaces the return type with void.
416
+ */
417
+ function* makeSyncFuncFix(fixer, funcNode) {
418
+ if (funcNode.async) {
419
+ // Remove async keyword
420
+ const funcHeadNode = funcNode.parent.type === utils_1.AST_NODE_TYPES.Property ||
421
+ funcNode.parent.type === utils_1.AST_NODE_TYPES.MethodDefinition
422
+ ? funcNode.parent
423
+ : funcNode;
424
+ const asyncToken = util.nullThrows(sourceCode.getFirstToken(funcHeadNode, {
425
+ filter: token => token.value === 'async',
426
+ }), util.NullThrowsReasons.MissingToken('async keyword', funcNode.type));
427
+ yield fixer.remove(asyncToken);
428
+ }
429
+ // Replace return type with void
430
+ if (funcNode.returnType != null) {
431
+ yield fixer.replaceText(funcNode.returnType.typeAnnotation, 'void');
432
+ }
433
+ }
434
+ /**
435
+ * Makes the function sync and adds a void operator to the arrow shorthand body.
436
+ */
437
+ function* addVoidToArrowFix(fixer, funcNode) {
438
+ yield* makeSyncFuncFix(fixer, funcNode);
439
+ // Add void operator
440
+ yield util.getWrappingFixer({
441
+ node: funcNode.body,
442
+ sourceCode,
443
+ wrap: code => `void ${code}`,
444
+ })(fixer);
445
+ }
446
+ /**
447
+ * Makes the function sync and wraps the body in an inner async IIFE.
448
+ */
449
+ function* wrapInAsyncIIFEFix(fixer, funcNode) {
450
+ yield* makeSyncFuncFix(fixer, funcNode);
451
+ // Wrap body in async IIFE.
452
+ // This preserves the node kind (normal/arrow) for the _outer_ function
453
+ // and uses an arrow function for the _inner_ function,
454
+ // so that `this` will always refer to the same value as before.
455
+ if (funcNode.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression) {
456
+ const arrowToken = util.nullThrows(sourceCode.getTokenBefore(funcNode.body, {
457
+ filter: token => token.value === '=>',
458
+ }), util.NullThrowsReasons.MissingToken('arrow token', 'before arrow function body'));
459
+ yield fixer.insertTextAfter(arrowToken, ' void (async () =>');
460
+ yield fixer.insertTextAfter(funcNode, ')()');
461
+ }
462
+ else {
463
+ yield fixer.insertTextBefore(funcNode.body, '{ (async () => ');
464
+ yield fixer.insertTextAfter(funcNode.body, ')(); }');
465
+ }
466
+ }
376
467
  },
377
468
  });
378
469
  //# sourceMappingURL=strict-void-return.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typescript-eslint/eslint-plugin",
3
- "version": "8.67.1-alpha.28",
3
+ "version": "8.67.1-alpha.29",
4
4
  "description": "TypeScript plugin for ESLint",
5
5
  "files": [
6
6
  "dist",
@@ -47,10 +47,10 @@
47
47
  ],
48
48
  "dependencies": {
49
49
  "@eslint-community/regexpp": "^4.12.2",
50
- "@typescript-eslint/scope-manager": "8.67.1-alpha.28",
51
- "@typescript-eslint/type-utils": "8.67.1-alpha.28",
52
- "@typescript-eslint/utils": "8.67.1-alpha.28",
53
- "@typescript-eslint/visitor-keys": "8.67.1-alpha.28",
50
+ "@typescript-eslint/scope-manager": "8.67.1-alpha.29",
51
+ "@typescript-eslint/type-utils": "8.67.1-alpha.29",
52
+ "@typescript-eslint/utils": "8.67.1-alpha.29",
53
+ "@typescript-eslint/visitor-keys": "8.67.1-alpha.29",
54
54
  "ignore": "^7.0.5",
55
55
  "natural-compare": "^1.4.0",
56
56
  "ts-api-utils": "^2.5.0"
@@ -60,8 +60,8 @@
60
60
  "@types/mdast": "^4.0.4",
61
61
  "@types/natural-compare": "^1.4.3",
62
62
  "@types/react": "^18.3.21",
63
- "@typescript-eslint/rule-schema-to-typescript-types": "8.67.1-alpha.28",
64
- "@typescript-eslint/rule-tester": "8.67.1-alpha.28",
63
+ "@typescript-eslint/rule-schema-to-typescript-types": "8.67.1-alpha.29",
64
+ "@typescript-eslint/rule-tester": "8.67.1-alpha.29",
65
65
  "@typescript/native": "npm:typescript@^7.0.2",
66
66
  "@vitest/coverage-v8": "^4.0.18",
67
67
  "ajv": "^6.12.6",
@@ -81,7 +81,7 @@
81
81
  "vitest": "^4.0.18"
82
82
  },
83
83
  "peerDependencies": {
84
- "@typescript-eslint/parser": "^8.67.1-alpha.28",
84
+ "@typescript-eslint/parser": "^8.67.1-alpha.29",
85
85
  "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
86
86
  "typescript": ">=4.8.4 <6.1.0"
87
87
  },