prefer-optional-catch-binding.js 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. 'use strict';
  2. const {isOpeningParenToken, isClosingParenToken} = require('eslint-utils');
  3. const assertToken = require('./utils/assert-token.js');
  4. const MESSAGE_ID_WITH_NAME = 'with-name';
  5. const MESSAGE_ID_WITHOUT_NAME = 'without-name';
  6. const messages = {
  7. [MESSAGE_ID_WITH_NAME]: 'Remove unused catch binding `{{name}}`.',
  8. [MESSAGE_ID_WITHOUT_NAME]: 'Remove unused catch binding.',
  9. };
  10. const selector = [
  11. 'CatchClause',
  12. ' > ',
  13. '.param',
  14. ].join('');
  15. /** @param {import('eslint').Rule.RuleContext} context */
  16. const create = context => ({
  17. [selector]: node => {
  18. const variables = context.getDeclaredVariables(node.parent);
  19. if (variables.some(variable => variable.references.length > 0)) {
  20. return;
  21. }
  22. const {type, name, parent} = node;
  23. return {
  24. node,
  25. messageId: type === 'Identifier' ? MESSAGE_ID_WITH_NAME : MESSAGE_ID_WITHOUT_NAME,
  26. data: {name},
  27. * fix(fixer) {
  28. const sourceCode = context.getSourceCode();
  29. const tokenBefore = sourceCode.getTokenBefore(node);
  30. assertToken(tokenBefore, {
  31. test: isOpeningParenToken,
  32. expected: '(',
  33. ruleId: 'prefer-optional-catch-binding',
  34. });
  35. const tokenAfter = sourceCode.getTokenAfter(node);
  36. assertToken(tokenAfter, {
  37. test: isClosingParenToken,
  38. expected: ')',
  39. ruleId: 'prefer-optional-catch-binding',
  40. });
  41. yield fixer.remove(tokenBefore);
  42. yield fixer.remove(node);
  43. yield fixer.remove(tokenAfter);
  44. const [, endOfClosingParenthesis] = tokenAfter.range;
  45. const [startOfCatchClauseBody] = parent.body.range;
  46. const text = sourceCode.text.slice(endOfClosingParenthesis, startOfCatchClauseBody);
  47. const leadingSpacesLength = text.length - text.trimStart().length;
  48. if (leadingSpacesLength !== 0) {
  49. yield fixer.removeRange([endOfClosingParenthesis, endOfClosingParenthesis + leadingSpacesLength]);
  50. }
  51. },
  52. };
  53. },
  54. });
  55. /** @type {import('eslint').Rule.RuleModule} */
  56. module.exports = {
  57. create,
  58. meta: {
  59. type: 'suggestion',
  60. docs: {
  61. description: 'Prefer omitting the `catch` binding parameter.',
  62. },
  63. fixable: 'code',
  64. messages,
  65. },
  66. };