UNPKG

2.12 kBJavaScriptView Raw
1/**
2 * @fileoverview Rule to flag references to undeclared variables.
3 * @author Mark Macdonald
4 */
5"use strict";
6
7//------------------------------------------------------------------------------
8// Helpers
9//------------------------------------------------------------------------------
10
11function isImplicitGlobal(variable) {
12 return variable.defs.every(function(def) {
13 return def.type === "ImplicitGlobalVariable";
14 });
15}
16
17/**
18 * Gets the declared variable, defined in `scope`, that `ref` refers to.
19 * @param {Scope} scope The scope in which to search.
20 * @param {Reference} ref The reference to find in the scope.
21 * @returns {Variable} The variable, or null if ref refers to an undeclared variable.
22 */
23function getDeclaredGlobalVariable(scope, ref) {
24 var declaredGlobal = null;
25 scope.variables.some(function(variable) {
26 if (variable.name === ref.identifier.name) {
27 // If it's an implicit global, it must have a `writeable` field (indicating it was declared)
28 if (!isImplicitGlobal(variable) || {}.hasOwnProperty.call(variable, "writeable")) {
29 declaredGlobal = variable;
30 return true;
31 }
32 }
33 return false;
34 });
35 return declaredGlobal;
36}
37
38//------------------------------------------------------------------------------
39// Rule Definition
40//------------------------------------------------------------------------------
41
42module.exports = function(context) {
43
44 return {
45
46 "Program": function(/*node*/) {
47
48 var globalScope = context.getScope();
49
50 globalScope.through.forEach(function(ref) {
51 var variable = getDeclaredGlobalVariable(globalScope, ref),
52 name = ref.identifier.name;
53 if (!variable) {
54 context.report(ref.identifier, "'{{name}}' is not defined.", { name: name });
55 } else if (ref.isWrite() && variable.writeable === false) {
56 context.report(ref.identifier, "'{{name}}' is read only.", { name: name });
57 }
58 });
59 }
60 };
61
62};