Blame view

node_modules/eslint/lib/rules/no-lone-blocks.js 2.94 KB
c39994410   Ryan Glover   wip converting to...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
  /**
   * @fileoverview Rule to flag blocks with no reason to exist
   * @author Brandon Mills
   * @copyright 2015 Roberto Vidal. All rights reserved.
   * @copyright 2014 Brandon Mills. All rights reserved.
   */
  
  "use strict";
  
  //------------------------------------------------------------------------------
  // Rule Definition
  //------------------------------------------------------------------------------
  
  module.exports = function(context) {
  
      // A stack of lone blocks to be checked for block-level bindings
      var loneBlocks = [],
          ruleDef;
  
      /**
       * Reports a node as invalid.
       * @param {ASTNode} node - The node to be reported.
       * @returns {void}
      */
      function report(node) {
          var parent = context.getAncestors().pop();
          context.report(node, parent.type === "Program" ?
              "Block is redundant." :
              "Nested block is redundant."
          );
      }
  
      /**
       * Checks for any ocurrence of BlockStatement > BlockStatement or Program > BlockStatement
       * @returns {boolean} True if the current node is a lone block.
      */
      function isLoneBlock() {
          var parent = context.getAncestors().pop();
          return parent.type === "BlockStatement" || parent.type === "Program";
      }
  
      /**
       * Checks the enclosing block of the current node for block-level bindings,
       * and "marks it" as valid if any.
       * @returns {void}
      */
      function markLoneBlock() {
          if (loneBlocks.length === 0) {
              return;
          }
  
          var block = context.getAncestors().pop();
  
          if (loneBlocks[loneBlocks.length - 1] === block) {
              loneBlocks.pop();
          }
      }
  
      // Default rule definition: report all lone blocks
      ruleDef = {
          BlockStatement: function(node) {
              if (isLoneBlock(node)) {
                  report(node);
              }
          }
      };
  
      // ES6: report blocks without block-level bindings
      if (context.ecmaFeatures.blockBindings || context.ecmaFeatures.classes) {
          ruleDef = {
              "BlockStatement": function(node) {
                  if (isLoneBlock(node)) {
                      loneBlocks.push(node);
                  }
              },
              "BlockStatement:exit": function(node) {
                  if (loneBlocks.length > 0 && loneBlocks[loneBlocks.length - 1] === node) {
                      loneBlocks.pop();
                      report(node);
                  }
              }
          };
      }
  
      if (context.ecmaFeatures.blockBindings) {
          ruleDef.VariableDeclaration = function(node) {
              if (node.kind === "let" || node.kind === "const") {
                  markLoneBlock(node);
              }
          };
  
          ruleDef.FunctionDeclaration = function(node) {
              if (context.getScope().isStrict) {
                  markLoneBlock(node);
              }
          };
      }
  
      if (context.ecmaFeatures.classes) {
          ruleDef.ClassDeclaration = markLoneBlock;
      }
  
      return ruleDef;
  };
  
  module.exports.schema = [];