1 | /**
|
2 | * @fileoverview Rule to check for "block scoped" variables by binding context
|
3 | * @author Matt DuVall <http://www.mattduvall.com>
|
4 | * @copyright 2015 Toru Nagashima. All rights reserved.
|
5 | * @copyright 2015 Mathieu M-Gosselin. All rights reserved.
|
6 | */
|
7 | ;
|
8 |
|
9 | //------------------------------------------------------------------------------
|
10 | // Rule Definition
|
11 | //------------------------------------------------------------------------------
|
12 |
|
13 | module.exports = function(context) {
|
14 | var stack = [];
|
15 |
|
16 | /**
|
17 | * Makes a block scope.
|
18 | * @param {ASTNode} node - A node of a scope.
|
19 | * @returns {void}
|
20 | */
|
21 | function enterScope(node) {
|
22 | stack.push(node.range);
|
23 | }
|
24 |
|
25 | /**
|
26 | * Pops the last block scope.
|
27 | * @returns {void}
|
28 | */
|
29 | function exitScope() {
|
30 | stack.pop();
|
31 | }
|
32 |
|
33 | /**
|
34 | * Reports a given reference.
|
35 | * @param {escope.Reference} reference - A reference to report.
|
36 | * @returns {void}
|
37 | */
|
38 | function report(reference) {
|
39 | var identifier = reference.identifier;
|
40 | context.report(
|
41 | identifier,
|
42 | "'{{name}}' used outside of binding context.",
|
43 | {name: identifier.name});
|
44 | }
|
45 |
|
46 | /**
|
47 | * Finds and reports references which are outside of valid scopes.
|
48 | * @param {ASTNode} node - A node to get variables.
|
49 | * @returns {void}
|
50 | */
|
51 | function checkForVariables(node) {
|
52 | if (node.kind !== "var") {
|
53 | return;
|
54 | }
|
55 |
|
56 | // Defines a predicate to check whether or not a given reference is outside of valid scope.
|
57 | var scopeRange = stack[stack.length - 1];
|
58 |
|
59 | /**
|
60 | * Check if a reference is out of scope
|
61 | * @param {ASTNode} reference node to examine
|
62 | * @returns {boolean} True is its outside the scope
|
63 | * @private
|
64 | */
|
65 | function isOutsideOfScope(reference) {
|
66 | var idRange = reference.identifier.range;
|
67 | return idRange[0] < scopeRange[0] || idRange[1] > scopeRange[1];
|
68 | }
|
69 |
|
70 | // Gets declared variables, and checks its references.
|
71 | var variables = context.getDeclaredVariables(node);
|
72 | for (var i = 0; i < variables.length; ++i) {
|
73 | // Reports.
|
74 | variables[i]
|
75 | .references
|
76 | .filter(isOutsideOfScope)
|
77 | .forEach(report);
|
78 | }
|
79 | }
|
80 |
|
81 | return {
|
82 | "Program": function(node) {
|
83 | stack = [node.range];
|
84 | },
|
85 |
|
86 | // Manages scopes.
|
87 | "BlockStatement": enterScope,
|
88 | "BlockStatement:exit": exitScope,
|
89 | "ForStatement": enterScope,
|
90 | "ForStatement:exit": exitScope,
|
91 | "ForInStatement": enterScope,
|
92 | "ForInStatement:exit": exitScope,
|
93 | "ForOfStatement": enterScope,
|
94 | "ForOfStatement:exit": exitScope,
|
95 | "SwitchStatement": enterScope,
|
96 | "SwitchStatement:exit": exitScope,
|
97 | "CatchClause": enterScope,
|
98 | "CatchClause:exit": exitScope,
|
99 |
|
100 | // Finds and reports references which are outside of valid scope.
|
101 | "VariableDeclaration": checkForVariables
|
102 | };
|
103 |
|
104 | };
|
105 |
|
106 | module.exports.schema = [];
|