Skip to content

Commit

Permalink
Fix: estraverse/escope to work with unknowns (fixes #5476)
Browse files Browse the repository at this point in the history
  • Loading branch information
nzakas committed Mar 11, 2016
1 parent d727f17 commit 97b2466
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 28 deletions.
23 changes: 10 additions & 13 deletions lib/eslint.js
Expand Up @@ -11,8 +11,7 @@
//------------------------------------------------------------------------------

var lodash = require("lodash"),
espree = require("espree"),
estraverse = require("estraverse"),
Traverser = require("./util/traverser"),
escope = require("escope"),
Environments = require("./config/environments"),
blankScriptAST = require("../conf/blank-script.json"),
Expand Down Expand Up @@ -522,7 +521,7 @@ module.exports = (function() {
scopeMap = null,
scopeManager = null,
currentFilename = null,
controller = null,
traverser = null,
reportingConfig = [],
sourceCode = null;

Expand Down Expand Up @@ -640,7 +639,7 @@ module.exports = (function() {
currentScopes = null;
scopeMap = null;
scopeManager = null;
controller = null;
traverser = null;
reportingConfig = [];
sourceCode = null;
};
Expand Down Expand Up @@ -786,7 +785,7 @@ module.exports = (function() {

// save config so rules can access as necessary
currentConfig = config;
controller = new estraverse.Controller();
traverser = new Traverser();

ecmaFeatures = currentConfig.parserOptions.ecmaFeatures || {};
ecmaVersion = currentConfig.parserOptions.ecmaVersion || 5;
Expand All @@ -798,8 +797,7 @@ module.exports = (function() {
impliedStrict: ecmaFeatures.impliedStrict,
ecmaVersion: ecmaVersion,
sourceType: currentConfig.parserOptions.sourceType || "script",
childVisitorKeys: espree.VisitorKeys,
fallback: "none"
fallback: Traverser.getKeys
});
currentScopes = scopeManager.scopes;

Expand Down Expand Up @@ -839,15 +837,14 @@ module.exports = (function() {
* an event is fired. This allows any listeners to automatically be informed
* that this type of node has been found and react accordingly.
*/
controller.traverse(ast, {
traverser.traverse(ast, {
enter: function(node, parent) {
node.parent = parent;
eventGenerator.enterNode(node);
},
leave: function(node) {
eventGenerator.leaveNode(node);
},
keys: espree.VisitorKeys
}
});
}

Expand Down Expand Up @@ -976,22 +973,22 @@ module.exports = (function() {
* @returns {ASTNode[]} Array of objects representing ancestors.
*/
api.getAncestors = function() {
return controller.parents();
return traverser.parents();
};

/**
* Gets the scope for the current node.
* @returns {Object} An object representing the current node's scope.
*/
api.getScope = function() {
var parents = controller.parents(),
var parents = traverser.parents(),
scope = currentScopes[0];

// Don't do this for Program nodes - they have no parents
if (parents.length) {

// if current node introduces a scope, add it to the list
var current = controller.current();
var current = traverser.current();
if (currentConfig.parserOptions.ecmaVersion >= 6) {
if (["BlockStatement", "SwitchStatement", "CatchClause", "FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"].indexOf(current.type) >= 0) {
parents.push(current);
Expand Down
11 changes: 5 additions & 6 deletions lib/rules/no-unmodified-loop-condition.js
Expand Up @@ -12,8 +12,7 @@
//------------------------------------------------------------------------------

var Map = require("es6-map"),
espree = require("espree"),
estraverse = require("estraverse"),
Traverser = require("../util/traverser"),
astUtils = require("../ast-utils");

//------------------------------------------------------------------------------
Expand Down Expand Up @@ -116,18 +115,18 @@ var isInLoop = {
* @returns {boolean} `true` if the node is dynamic.
*/
function hasDynamicExpressions(root) {
var retv = false;
var retv = false,
traverser = new Traverser();

estraverse.traverse(root, {
traverser.traverse(root, {
enter: function(node) {
if (DYNAMIC_PATTERN.test(node.type)) {
retv = true;
this.break();
} else if (SKIP_PATTERN.test(node.type)) {
this.skip();
}
},
keys: espree.VisitorKeys
}
});

return retv;
Expand Down
13 changes: 6 additions & 7 deletions lib/util/source-code.js
Expand Up @@ -12,8 +12,7 @@

var lodash = require("lodash"),
createTokenStore = require("../token-store.js"),
espree = require("espree"),
estraverse = require("estraverse");
Traverser = require("./traverser");

//------------------------------------------------------------------------------
// Private
Expand Down Expand Up @@ -262,10 +261,11 @@ SourceCode.prototype = {
* @returns {ASTNode} The node if found or null if not found.
*/
getNodeByRangeIndex: function(index) {
var result = null;
var resultParent = null;
var result = null,
resultParent = null,
traverser = new Traverser();

estraverse.traverse(this.ast, {
traverser.traverse(this.ast, {
enter: function(node, parent) {
if (node.range[0] <= index && index < node.range[1]) {
result = node;
Expand All @@ -278,8 +278,7 @@ SourceCode.prototype = {
if (node === result) {
this.break();
}
},
keys: espree.VisitorKeys
}
});

return result ? lodash.assign({parent: resultParent}, result) : null;
Expand Down
58 changes: 58 additions & 0 deletions lib/util/traverser.js
@@ -0,0 +1,58 @@
/**
* @fileoverview Wrapper around estraverse
* @author Nicholas C. Zakas
* @copyright 2016 Nicholas C. Zakas. All rights reserved.
* See LICENSE in root directory for full license.
*/
"use strict";

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

var estraverse = require("estraverse");

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------

var KEY_BLACKLIST = [
"parent",
"leadingComments",
"trailingComments"
];

/**
* Wrapper around an estraverse controller that ensures the correct keys
* are visited.
* @constructor
*/
function Traverser() {

var controller = Object.create(new estraverse.Controller()),
originalTraverse = controller.traverse;

// intercept call to traverse() and add the fallback key to the visitor
controller.traverse = function(node, visitor) {
visitor.fallback = Traverser.getKeys;
return originalTraverse.call(this, node, visitor);
};

return controller;
}

/**
* Calculates the keys to use for traversal.
* @param {ASTNode} node The node to read keys from.
* @returns {string[]} An array of keys to visit on the node.
* @private
*/
Traverser.getKeys = function(node) {
return Object.keys(node).filter(function(key) {
return KEY_BLACKLIST.indexOf(key) === -1;
});
};

module.exports = Traverser;


4 changes: 2 additions & 2 deletions package.json
Expand Up @@ -41,9 +41,9 @@
"debug": "^2.1.1",
"doctrine": "^1.2.0",
"es6-map": "^0.1.3",
"escope": "^3.5.0",
"escope": "^3.6.0",
"espree": "^3.1.1",
"estraverse": "^4.1.1",
"estraverse": "^4.2.0",
"esutils": "^2.0.2",
"file-entry-cache": "^1.1.1",
"glob": "^6.0.4",
Expand Down

0 comments on commit 97b2466

Please sign in to comment.