no-lonely-if.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. /**
  2. * @fileoverview Rule to disallow if as the only statmenet in an else block
  3. * @author Brandon Mills
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Rule Definition
  8. //------------------------------------------------------------------------------
  9. module.exports = {
  10. meta: {
  11. docs: {
  12. description: "disallow `if` statements as the only statement in `else` blocks",
  13. category: "Stylistic Issues",
  14. recommended: false,
  15. url: "https://eslint.org/docs/rules/no-lonely-if"
  16. },
  17. schema: [],
  18. fixable: "code"
  19. },
  20. create(context) {
  21. const sourceCode = context.getSourceCode();
  22. return {
  23. IfStatement(node) {
  24. const ancestors = context.getAncestors(),
  25. parent = ancestors.pop(),
  26. grandparent = ancestors.pop();
  27. if (parent && parent.type === "BlockStatement" &&
  28. parent.body.length === 1 && grandparent &&
  29. grandparent.type === "IfStatement" &&
  30. parent === grandparent.alternate) {
  31. context.report({
  32. node,
  33. message: "Unexpected if as the only statement in an else block.",
  34. fix(fixer) {
  35. const openingElseCurly = sourceCode.getFirstToken(parent);
  36. const closingElseCurly = sourceCode.getLastToken(parent);
  37. const elseKeyword = sourceCode.getTokenBefore(openingElseCurly);
  38. const tokenAfterElseBlock = sourceCode.getTokenAfter(closingElseCurly);
  39. const lastIfToken = sourceCode.getLastToken(node.consequent);
  40. const sourceText = sourceCode.getText();
  41. if (sourceText.slice(openingElseCurly.range[1],
  42. node.range[0]).trim() || sourceText.slice(node.range[1], closingElseCurly.range[0]).trim()) {
  43. // Don't fix if there are any non-whitespace characters interfering (e.g. comments)
  44. return null;
  45. }
  46. if (
  47. node.consequent.type !== "BlockStatement" && lastIfToken.value !== ";" && tokenAfterElseBlock &&
  48. (
  49. node.consequent.loc.end.line === tokenAfterElseBlock.loc.start.line ||
  50. /^[([/+`-]/.test(tokenAfterElseBlock.value) ||
  51. lastIfToken.value === "++" ||
  52. lastIfToken.value === "--"
  53. )
  54. ) {
  55. /*
  56. * If the `if` statement has no block, and is not followed by a semicolon, make sure that fixing
  57. * the issue would not change semantics due to ASI. If this would happen, don't do a fix.
  58. */
  59. return null;
  60. }
  61. return fixer.replaceTextRange(
  62. [openingElseCurly.range[0], closingElseCurly.range[1]],
  63. (elseKeyword.range[1] === openingElseCurly.range[0] ? " " : "") + sourceCode.getText(node)
  64. );
  65. }
  66. });
  67. }
  68. }
  69. };
  70. }
  71. };