diff --git a/packages/eslint-scope/README.md b/packages/eslint-scope/README.md index f9e90ac0..810a1085 100644 --- a/packages/eslint-scope/README.md +++ b/packages/eslint-scope/README.md @@ -89,6 +89,11 @@ The `ScopeManager` class is at the core of eslint-scope and is returned when you #### Methods +- **`addGlobals(names)`** + Adds variables to the global scope and resolves references to them. + - `names` - An array of strings, the names of variables to add to the global scope. + - Returns: `undefined`. + - **`acquire(node, inner)`** Acquires the appropriate scope for a given node. - `node` - The AST node to acquire the scope from. diff --git a/packages/eslint-scope/lib/scope-manager.js b/packages/eslint-scope/lib/scope-manager.js index b012b646..a9f5c943 100644 --- a/packages/eslint-scope/lib/scope-manager.js +++ b/packages/eslint-scope/lib/scope-manager.js @@ -182,6 +182,16 @@ class ScopeManager { return null; } + /** + * Add global variables and resolve their references. + * @function ScopeManager#addGlobals + * @param {string[]} names Names of global variables to add. + * @returns {void} + */ + addGlobals(names) { + this.globalScope.__addVariables(names); + } + attach() { } // eslint-disable-line class-methods-use-this -- Desired as instance method detach() { } // eslint-disable-line class-methods-use-this -- Desired as instance method diff --git a/packages/eslint-scope/lib/scope.js b/packages/eslint-scope/lib/scope.js index 46eeb771..0b7f5890 100644 --- a/packages/eslint-scope/lib/scope.js +++ b/packages/eslint-scope/lib/scope.js @@ -122,18 +122,6 @@ function registerScope(scopeManager, scope) { } } -/** - * Should be statically - * @param {Object} def def - * @returns {boolean} should be statically - */ -function shouldBeStatically(def) { - return ( - (def.type === Variable.ClassName) || - (def.type === Variable.Variable && def.parent.kind !== "var") - ); -} - /** * @constructor Scope */ @@ -267,22 +255,7 @@ class Scope { } __shouldStaticallyClose(scopeManager) { - return (!this.dynamic || scopeManager.__isOptimistic()); - } - - __shouldStaticallyCloseForGlobal(ref) { - - // On global scope, let/const/class declarations should be resolved statically. - const name = ref.identifier.name; - - if (!this.set.has(name)) { - return false; - } - - const variable = this.set.get(name); - const defs = variable.defs; - - return defs.length > 0 && defs.every(shouldBeStatically); + return (!this.dynamic || scopeManager.__isOptimistic() || this.type === "global"); } __staticCloseRef(ref) { @@ -302,26 +275,13 @@ class Scope { } while (current); } - __globalCloseRef(ref) { - - // let/const/class declarations should be resolved statically. - // others should be resolved dynamically. - if (this.__shouldStaticallyCloseForGlobal(ref)) { - this.__staticCloseRef(ref); - } else { - this.__dynamicCloseRef(ref); - } - } - __close(scopeManager) { let closeRef; if (this.__shouldStaticallyClose(scopeManager)) { closeRef = this.__staticCloseRef; - } else if (this.type !== "global") { - closeRef = this.__dynamicCloseRef; } else { - closeRef = this.__globalCloseRef; + closeRef = this.__dynamicCloseRef; } // Try Resolving all references in this scope. @@ -560,9 +520,11 @@ class GlobalScope extends Scope { } - this.implicit.left = this.__left; + super.__close(scopeManager); - return super.__close(scopeManager); + this.implicit.left = [...this.through]; + + return null; } __defineImplicit(node, def) { @@ -576,6 +538,51 @@ class GlobalScope extends Scope { ); } } + + __addVariables(names) { + for (const name of names) { + this.__defineGeneric( + name, + this.set, + this.variables, + null, + null + ); + } + + const namesSet = new Set(names); + + this.through = this.through.filter(reference => { + const name = reference.identifier.name; + + if (namesSet.has(name)) { + const variable = this.set.get(name); + + reference.resolved = variable; + variable.references.push(reference); + + return false; + } + + return true; + }); + + this.implicit.variables = this.implicit.variables.filter(variable => { + const name = variable.name; + + if (namesSet.has(name)) { + this.implicit.set.delete(name); + + return false; + } + + return true; + }); + + this.implicit.left = this.implicit.left.filter( + reference => !namesSet.has(reference.identifier.name) + ); + } } /** diff --git a/packages/eslint-scope/tests/add-globals.test.js b/packages/eslint-scope/tests/add-globals.test.js new file mode 100644 index 00000000..63fa41bc --- /dev/null +++ b/packages/eslint-scope/tests/add-globals.test.js @@ -0,0 +1,351 @@ +/** + * @fileoverview Tests for ScopeManager#addGlobals method. + * @author Milos Djermanovic + */ + +import { expect } from "chai"; +import espree from "./util/espree.js"; +import { analyze } from "../lib/index.js"; + +describe("ScopeManager#addGlobals", () => { + it("adds variables to the global scope and resolves references from the global scope", () => { + const ast = espree(` + foo = bar + bar; + `); + + const scopeManager = analyze(ast); + + expect(scopeManager.scopes).to.have.length(1); + + const globalScope = scopeManager.scopes[0]; + + expect(globalScope.type).to.be.equal("global"); + + expect(globalScope.variables).to.have.length(0); + expect(globalScope.set.size).to.be.equal(0); + expect(globalScope.references).to.have.length(3); + expect(globalScope.references[0].identifier.name).to.be.equal("foo"); + expect(globalScope.references[0].from).to.be.equal(globalScope); + expect(globalScope.references[0].resolved).to.be.null; + expect(globalScope.references[1].identifier.name).to.be.equal("bar"); + expect(globalScope.references[1].from).to.be.equal(globalScope); + expect(globalScope.references[1].resolved).to.be.null; + expect(globalScope.references[2].identifier.name).to.be.equal("bar"); + expect(globalScope.references[2].from).to.be.equal(globalScope); + expect(globalScope.references[2].resolved).to.be.null; + expect(globalScope.references[1]).to.not.be.equal(globalScope.references[2]); + expect(globalScope.through).to.have.length(3); + expect(globalScope.through[0]).to.be.equal(globalScope.references[0]); + expect(globalScope.through[1]).to.be.equal(globalScope.references[1]); + expect(globalScope.through[2]).to.be.equal(globalScope.references[2]); + expect(globalScope.implicit.variables).to.have.length(1); + expect(globalScope.implicit.variables[0].name).to.be.equal("foo"); + expect(globalScope.implicit.variables[0].references).to.have.length(0); + expect(globalScope.implicit.variables[0].defs).to.have.length(1); + expect(globalScope.implicit.variables[0].identifiers).to.have.length(1); + expect(globalScope.implicit.set.size).to.be.equal(1); + expect(globalScope.implicit.set.get("foo")).to.be.equal(globalScope.implicit.variables[0]); + expect(globalScope.implicit.left).to.have.length(3); + expect(globalScope.implicit.left[0]).to.be.equal(globalScope.references[0]); + expect(globalScope.implicit.left[1]).to.be.equal(globalScope.references[1]); + expect(globalScope.implicit.left[2]).to.be.equal(globalScope.references[2]); + + scopeManager.addGlobals(["foo", "bar"]); + + expect(globalScope.variables).to.have.length(2); + expect(globalScope.variables[0].name).to.be.equal("foo"); + expect(globalScope.variables[0].scope).to.be.equal(globalScope); + expect(globalScope.variables[0].defs).to.have.length(0); + expect(globalScope.variables[0].identifiers).to.have.length(0); + expect(globalScope.variables[1].name).to.be.equal("bar"); + expect(globalScope.variables[1].scope).to.be.equal(globalScope); + expect(globalScope.variables[1].defs).to.have.length(0); + expect(globalScope.variables[1].identifiers).to.have.length(0); + expect(globalScope.set.size).to.be.equal(2); + expect(globalScope.set.get("foo")).to.be.equal(globalScope.variables[0]); + expect(globalScope.set.get("bar")).to.be.equal(globalScope.variables[1]); + expect(globalScope.references).to.have.length(3); + expect(globalScope.references[0].identifier.name).to.be.equal("foo"); + expect(globalScope.references[0].from).to.be.equal(globalScope); + expect(globalScope.references[0].resolved).to.be.equal(globalScope.variables[0]); + expect(globalScope.variables[0].references).to.have.length(1); + expect(globalScope.variables[0].references[0]).to.be.equal(globalScope.references[0]); + expect(globalScope.references[1].identifier.name).to.be.equal("bar"); + expect(globalScope.references[1].from).to.be.equal(globalScope); + expect(globalScope.references[1].resolved).to.be.equal(globalScope.variables[1]); + expect(globalScope.references[2].identifier.name).to.be.equal("bar"); + expect(globalScope.references[2].from).to.be.equal(globalScope); + expect(globalScope.references[2].resolved).to.be.equal(globalScope.variables[1]); + expect(globalScope.variables[1].references).to.have.length(2); + expect(globalScope.variables[1].references[0]).to.be.equal(globalScope.references[1]); + expect(globalScope.variables[1].references[1]).to.be.equal(globalScope.references[2]); + expect(globalScope.through).to.have.length(0); + expect(globalScope.implicit.variables).to.have.length(0); + expect(globalScope.implicit.set.size).to.be.equal(0); + expect(globalScope.implicit.left).to.have.length(0); + }); + + it("adds variables to the global scope and resolves references from inner scopes", () => { + const ast = espree(` + () => foo = bar + bar; + `); + + const scopeManager = analyze(ast); + + expect(scopeManager.scopes).to.have.length(2); + + const globalScope = scopeManager.scopes[0]; + + expect(globalScope.type).to.be.equal("global"); + + const functionScope = scopeManager.scopes[1]; + + expect(functionScope.type).to.be.equal("function"); + + expect(functionScope.variables).to.have.length(0); + expect(functionScope.set.size).to.be.equal(0); + expect(functionScope.references).to.have.length(3); + expect(functionScope.references[0].identifier.name).to.be.equal("foo"); + expect(functionScope.references[0].from).to.be.equal(functionScope); + expect(functionScope.references[0].resolved).to.be.null; + expect(functionScope.references[1].identifier.name).to.be.equal("bar"); + expect(functionScope.references[1].from).to.be.equal(functionScope); + expect(functionScope.references[1].resolved).to.be.null; + expect(functionScope.references[2].identifier.name).to.be.equal("bar"); + expect(functionScope.references[2].from).to.be.equal(functionScope); + expect(functionScope.references[2].resolved).to.be.null; + expect(functionScope.references[1]).to.not.be.equal(functionScope.references[2]); + expect(functionScope.through).to.have.length(3); + expect(functionScope.through[0]).to.be.equal(functionScope.references[0]); + expect(functionScope.through[1]).to.be.equal(functionScope.references[1]); + expect(functionScope.through[2]).to.be.equal(functionScope.references[2]); + expect(globalScope.variables).to.have.length(0); + expect(globalScope.set.size).to.be.equal(0); + expect(globalScope.references).to.have.length(0); + expect(globalScope.through).to.have.length(3); + expect(globalScope.through[0]).to.be.equal(functionScope.references[0]); + expect(globalScope.through[1]).to.be.equal(functionScope.references[1]); + expect(globalScope.through[2]).to.be.equal(functionScope.references[2]); + expect(globalScope.implicit.variables).to.have.length(1); + expect(globalScope.implicit.variables[0].name).to.be.equal("foo"); + expect(globalScope.implicit.variables[0].references).to.have.length(0); + expect(globalScope.implicit.variables[0].defs).to.have.length(1); + expect(globalScope.implicit.variables[0].identifiers).to.have.length(1); + expect(globalScope.implicit.set.size).to.be.equal(1); + expect(globalScope.implicit.set.get("foo")).to.be.equal(globalScope.implicit.variables[0]); + expect(globalScope.implicit.left).to.have.length(3); + expect(globalScope.implicit.left[0]).to.be.equal(functionScope.references[0]); + expect(globalScope.implicit.left[1]).to.be.equal(functionScope.references[1]); + expect(globalScope.implicit.left[2]).to.be.equal(functionScope.references[2]); + + scopeManager.addGlobals(["foo", "bar"]); + + expect(globalScope.variables).to.have.length(2); + expect(globalScope.variables[0].name).to.be.equal("foo"); + expect(globalScope.variables[0].scope).to.be.equal(globalScope); + expect(globalScope.variables[0].defs).to.have.length(0); + expect(globalScope.variables[0].identifiers).to.have.length(0); + expect(globalScope.variables[1].name).to.be.equal("bar"); + expect(globalScope.variables[1].scope).to.be.equal(globalScope); + expect(globalScope.variables[1].defs).to.have.length(0); + expect(globalScope.variables[1].identifiers).to.have.length(0); + expect(globalScope.set.size).to.be.equal(2); + expect(globalScope.set.get("foo")).to.be.equal(globalScope.variables[0]); + expect(globalScope.set.get("bar")).to.be.equal(globalScope.variables[1]); + expect(functionScope.variables).to.have.length(0); + expect(functionScope.set.size).to.be.equal(0); + expect(functionScope.references).to.have.length(3); + expect(functionScope.references[0].identifier.name).to.be.equal("foo"); + expect(functionScope.references[0].from).to.be.equal(functionScope); + expect(functionScope.references[0].resolved).to.be.equal(globalScope.variables[0]); + expect(globalScope.variables[0].references).to.have.length(1); + expect(globalScope.variables[0].references[0]).to.be.equal(functionScope.references[0]); + expect(functionScope.references[1].identifier.name).to.be.equal("bar"); + expect(functionScope.references[1].from).to.be.equal(functionScope); + expect(functionScope.references[1].resolved).to.be.equal(globalScope.variables[1]); + expect(functionScope.references[2].identifier.name).to.be.equal("bar"); + expect(functionScope.references[2].from).to.be.equal(functionScope); + expect(functionScope.references[2].resolved).to.be.equal(globalScope.variables[1]); + expect(functionScope.references[1]).to.not.be.equal(functionScope.references[2]); + expect(globalScope.variables[1].references).to.have.length(2); + expect(globalScope.variables[1].references[0]).to.be.equal(functionScope.references[1]); + expect(globalScope.variables[1].references[1]).to.be.equal(functionScope.references[2]); + expect(functionScope.through).to.have.length(3); + expect(functionScope.through[0]).to.be.equal(functionScope.references[0]); + expect(functionScope.through[1]).to.be.equal(functionScope.references[1]); + expect(functionScope.through[2]).to.be.equal(functionScope.references[2]); + expect(globalScope.references).to.have.length(0); + expect(globalScope.through).to.have.length(0); + expect(globalScope.implicit.variables).to.have.length(0); + expect(globalScope.implicit.set.size).to.be.equal(0); + expect(globalScope.implicit.left).to.have.length(0); + }); + + it("adds variables to the global scope and doesn't affect unrelated references", () => { + const ast = espree(` + foo = bar + bar; + `); + + const scopeManager = analyze(ast); + + expect(scopeManager.scopes).to.have.length(1); + + const globalScope = scopeManager.scopes[0]; + + expect(globalScope.type).to.be.equal("global"); + + expect(globalScope.variables).to.have.length(0); + expect(globalScope.set.size).to.be.equal(0); + expect(globalScope.references).to.have.length(3); + expect(globalScope.references[0].identifier.name).to.be.equal("foo"); + expect(globalScope.references[0].from).to.be.equal(globalScope); + expect(globalScope.references[0].resolved).to.be.null; + expect(globalScope.references[1].identifier.name).to.be.equal("bar"); + expect(globalScope.references[1].from).to.be.equal(globalScope); + expect(globalScope.references[1].resolved).to.be.null; + expect(globalScope.references[2].identifier.name).to.be.equal("bar"); + expect(globalScope.references[2].from).to.be.equal(globalScope); + expect(globalScope.references[2].resolved).to.be.null; + expect(globalScope.references[1]).to.not.be.equal(globalScope.references[2]); + expect(globalScope.through).to.have.length(3); + expect(globalScope.through[0]).to.be.equal(globalScope.references[0]); + expect(globalScope.through[1]).to.be.equal(globalScope.references[1]); + expect(globalScope.through[2]).to.be.equal(globalScope.references[2]); + expect(globalScope.implicit.variables).to.have.length(1); + expect(globalScope.implicit.variables[0].name).to.be.equal("foo"); + expect(globalScope.implicit.variables[0].references).to.have.length(0); + expect(globalScope.implicit.variables[0].defs).to.have.length(1); + expect(globalScope.implicit.variables[0].identifiers).to.have.length(1); + expect(globalScope.implicit.set.size).to.be.equal(1); + expect(globalScope.implicit.set.get("foo")).to.be.equal(globalScope.implicit.variables[0]); + expect(globalScope.implicit.left).to.have.length(3); + expect(globalScope.implicit.left[0]).to.be.equal(globalScope.references[0]); + expect(globalScope.implicit.left[1]).to.be.equal(globalScope.references[1]); + expect(globalScope.implicit.left[2]).to.be.equal(globalScope.references[2]); + + scopeManager.addGlobals(["baz", "qux"]); + + expect(globalScope.variables).to.have.length(2); + expect(globalScope.variables[0].name).to.be.equal("baz"); + expect(globalScope.variables[0].scope).to.be.equal(globalScope); + expect(globalScope.variables[0].defs).to.have.length(0); + expect(globalScope.variables[0].identifiers).to.have.length(0); + expect(globalScope.variables[0].references).to.have.length(0); + expect(globalScope.variables[1].name).to.be.equal("qux"); + expect(globalScope.variables[1].scope).to.be.equal(globalScope); + expect(globalScope.variables[1].defs).to.have.length(0); + expect(globalScope.variables[1].identifiers).to.have.length(0); + expect(globalScope.variables[1].references).to.have.length(0); + expect(globalScope.set.size).to.be.equal(2); + expect(globalScope.set.get("baz")).to.be.equal(globalScope.variables[0]); + expect(globalScope.set.get("qux")).to.be.equal(globalScope.variables[1]); + expect(globalScope.references).to.have.length(3); + expect(globalScope.references[0].identifier.name).to.be.equal("foo"); + expect(globalScope.references[0].from).to.be.equal(globalScope); + expect(globalScope.references[0].resolved).to.be.null; + expect(globalScope.references[1].identifier.name).to.be.equal("bar"); + expect(globalScope.references[1].from).to.be.equal(globalScope); + expect(globalScope.references[1].resolved).to.be.null; + expect(globalScope.references[2].identifier.name).to.be.equal("bar"); + expect(globalScope.references[2].from).to.be.equal(globalScope); + expect(globalScope.references[2].resolved).to.be.null; + expect(globalScope.references[1]).to.not.be.equal(globalScope.references[2]); + expect(globalScope.through).to.have.length(3); + expect(globalScope.through[0]).to.be.equal(globalScope.references[0]); + expect(globalScope.through[1]).to.be.equal(globalScope.references[1]); + expect(globalScope.through[2]).to.be.equal(globalScope.references[2]); + expect(globalScope.implicit.variables).to.have.length(1); + expect(globalScope.implicit.variables[0].name).to.be.equal("foo"); + expect(globalScope.implicit.variables[0].references).to.have.length(0); + expect(globalScope.implicit.variables[0].defs).to.have.length(1); + expect(globalScope.implicit.variables[0].identifiers).to.have.length(1); + expect(globalScope.implicit.set.size).to.be.equal(1); + expect(globalScope.implicit.set.get("foo")).to.be.equal(globalScope.implicit.variables[0]); + expect(globalScope.implicit.left).to.have.length(3); + expect(globalScope.implicit.left[0]).to.be.equal(globalScope.references[0]); + expect(globalScope.implicit.left[1]).to.be.equal(globalScope.references[1]); + expect(globalScope.implicit.left[2]).to.be.equal(globalScope.references[2]); + }); + + it("doesn't affect already declared global variables", () => { + const ast = espree(` + let foo = bar + bar; + var bar; + `); + + const scopeManager = analyze(ast); + + expect(scopeManager.scopes).to.have.length(1); + + const globalScope = scopeManager.scopes[0]; + + expect(globalScope.type).to.be.equal("global"); + + expect(globalScope.variables).to.have.length(2); + expect(globalScope.variables[0].name).to.be.equal("foo"); + expect(globalScope.variables[0].scope).to.be.equal(globalScope); + expect(globalScope.variables[0].defs).to.have.length(1); + expect(globalScope.variables[0].identifiers).to.have.length(1); + expect(globalScope.variables[1].name).to.be.equal("bar"); + expect(globalScope.variables[1].scope).to.be.equal(globalScope); + expect(globalScope.variables[1].defs).to.have.length(1); + expect(globalScope.variables[1].identifiers).to.have.length(1); + expect(globalScope.set.size).to.be.equal(2); + expect(globalScope.set.get("foo")).to.be.equal(globalScope.variables[0]); + expect(globalScope.set.get("bar")).to.be.equal(globalScope.variables[1]); + expect(globalScope.references).to.have.length(3); + expect(globalScope.references[0].identifier.name).to.be.equal("foo"); + expect(globalScope.references[0].from).to.be.equal(globalScope); + expect(globalScope.references[0].resolved).to.be.equal(globalScope.variables[0]); + expect(globalScope.variables[0].references).to.have.length(1); + expect(globalScope.variables[0].references[0]).to.be.equal(globalScope.references[0]); + expect(globalScope.references[1].identifier.name).to.be.equal("bar"); + expect(globalScope.references[1].from).to.be.equal(globalScope); + expect(globalScope.references[1].resolved).to.be.equal(globalScope.variables[1]); + expect(globalScope.references[2].identifier.name).to.be.equal("bar"); + expect(globalScope.references[2].from).to.be.equal(globalScope); + expect(globalScope.references[2].resolved).to.be.equal(globalScope.variables[1]); + expect(globalScope.variables[1].references).to.have.length(2); + expect(globalScope.variables[1].references[0]).to.be.equal(globalScope.references[1]); + expect(globalScope.variables[1].references[1]).to.be.equal(globalScope.references[2]); + expect(globalScope.through).to.have.length(0); + expect(globalScope.implicit.variables).to.have.length(0); + expect(globalScope.implicit.set.size).to.be.equal(0); + expect(globalScope.implicit.left).to.have.length(0); + + scopeManager.addGlobals(["foo", "bar"]); + + expect(globalScope.variables).to.have.length(2); + expect(globalScope.variables[0].name).to.be.equal("foo"); + expect(globalScope.variables[0].scope).to.be.equal(globalScope); + expect(globalScope.variables[0].defs).to.have.length(1); + expect(globalScope.variables[0].identifiers).to.have.length(1); + expect(globalScope.variables[1].name).to.be.equal("bar"); + expect(globalScope.variables[1].scope).to.be.equal(globalScope); + expect(globalScope.variables[1].defs).to.have.length(1); + expect(globalScope.variables[1].identifiers).to.have.length(1); + expect(globalScope.set.size).to.be.equal(2); + expect(globalScope.set.get("foo")).to.be.equal(globalScope.variables[0]); + expect(globalScope.set.get("bar")).to.be.equal(globalScope.variables[1]); + expect(globalScope.references).to.have.length(3); + expect(globalScope.references[0].identifier.name).to.be.equal("foo"); + expect(globalScope.references[0].from).to.be.equal(globalScope); + expect(globalScope.references[0].resolved).to.be.equal(globalScope.variables[0]); + expect(globalScope.variables[0].references).to.have.length(1); + expect(globalScope.variables[0].references[0]).to.be.equal(globalScope.references[0]); + expect(globalScope.references[1].identifier.name).to.be.equal("bar"); + expect(globalScope.references[1].from).to.be.equal(globalScope); + expect(globalScope.references[1].resolved).to.be.equal(globalScope.variables[1]); + expect(globalScope.references[2].identifier.name).to.be.equal("bar"); + expect(globalScope.references[2].from).to.be.equal(globalScope); + expect(globalScope.references[2].resolved).to.be.equal(globalScope.variables[1]); + expect(globalScope.variables[1].references).to.have.length(2); + expect(globalScope.variables[1].references[0]).to.be.equal(globalScope.references[1]); + expect(globalScope.variables[1].references[1]).to.be.equal(globalScope.references[2]); + expect(globalScope.through).to.have.length(0); + expect(globalScope.implicit.variables).to.have.length(0); + expect(globalScope.implicit.set.size).to.be.equal(0); + expect(globalScope.implicit.left).to.have.length(0); + }); + +}); diff --git a/packages/eslint-scope/tests/implicit-global-reference.test.js b/packages/eslint-scope/tests/implicit-global-reference.test.js index 4c869ff1..7809d0b8 100644 --- a/packages/eslint-scope/tests/implicit-global-reference.test.js +++ b/packages/eslint-scope/tests/implicit-global-reference.test.js @@ -44,6 +44,8 @@ describe("implicit global reference", () => { ); expect(scopes[0].implicit.variables.map(variable => variable.name)).to.be.eql([]); + expect(scopes[0].implicit.left.map(reference => reference.identifier.name)).to.be.eql([]); + expect(scopes[0].through.map(reference => reference.identifier.name)).to.be.eql([]); }); it("assignments global scope without definition", () => { @@ -66,6 +68,18 @@ describe("implicit global reference", () => { "x" ] ); + expect(scopes[0].implicit.left.map(reference => reference.identifier.name)).to.be.eql( + [ + "x", + "x" + ] + ); + expect(scopes[0].through.map(reference => reference.identifier.name)).to.be.eql( + [ + "x", + "x" + ] + ); }); it("assignments global scope without definition eval", () => { @@ -120,6 +134,16 @@ describe("implicit global reference", () => { "x" ] ); + expect(scopes[0].implicit.left.map(reference => reference.identifier.name)).to.be.eql( + [ + "x" + ] + ); + expect(scopes[0].through.map(reference => reference.identifier.name)).to.be.eql( + [ + "x" + ] + ); }); it("assignment doesn't leak", () => { @@ -151,6 +175,8 @@ describe("implicit global reference", () => { ); expect(scopes[0].implicit.variables.map(variable => variable.name)).to.be.eql([]); + expect(scopes[0].implicit.left.map(reference => reference.identifier.name)).to.be.eql([]); + expect(scopes[0].through.map(reference => reference.identifier.name)).to.be.eql([]); }); it("for-in-statement leaks", () => { @@ -177,6 +203,18 @@ describe("implicit global reference", () => { "x" ] ); + expect(scopes[0].implicit.left.map(reference => reference.identifier.name)).to.be.eql( + [ + "x", + "y" + ] + ); + expect(scopes[0].through.map(reference => reference.identifier.name)).to.be.eql( + [ + "x", + "y" + ] + ); }); it("for-in-statement doesn't leaks", () => { @@ -208,5 +246,15 @@ describe("implicit global reference", () => { ); expect(scopes[0].implicit.variables.map(variable => variable.name)).to.be.eql([]); + expect(scopes[0].implicit.left.map(reference => reference.identifier.name)).to.be.eql( + [ + "y" + ] + ); + expect(scopes[0].through.map(reference => reference.identifier.name)).to.be.eql( + [ + "y" + ] + ); }); }); diff --git a/packages/eslint-scope/tests/label.test.js b/packages/eslint-scope/tests/label.test.js index 3d0ff196..47869852 100644 --- a/packages/eslint-scope/tests/label.test.js +++ b/packages/eslint-scope/tests/label.test.js @@ -66,9 +66,10 @@ describe("label", () => { expect(globalScope.type).to.be.equal("global"); expect(globalScope.variables).to.have.length(1); expect(globalScope.variables[0].name).to.be.equal("foo"); - expect(globalScope.through.length).to.be.equal(3); - expect(globalScope.through[2].identifier.name).to.be.equal("foo"); - expect(globalScope.through[2].isRead()).to.be.true; + expect(globalScope.through.length).to.be.equal(1); + expect(globalScope.through[0].identifier.name).to.be.equal("console"); + expect(globalScope.variables[0].references.length).to.be.equal(2); + expect(globalScope.variables[0].references[1].isRead()).to.be.true; }); }); diff --git a/packages/eslint-scope/tests/references.test.js b/packages/eslint-scope/tests/references.test.js index a4776442..cbee1022 100644 --- a/packages/eslint-scope/tests/references.test.js +++ b/packages/eslint-scope/tests/references.test.js @@ -155,7 +155,7 @@ describe("References:", () => { }); describe("When there is a `var` declaration on global,", () => { - it("the reference on global should NOT be resolved.", () => { + it("the reference on global should be resolved.", () => { const ast = espree("var a = 0;"); const scopeManager = analyze(ast, { ecmaVersion: 6 }); @@ -171,13 +171,13 @@ describe("References:", () => { expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); - expect(reference.resolved).to.be.null; + expect(reference.resolved).to.equal(scope.variables[0]); expect(reference.writeExpr).to.not.be.undefined; expect(reference.isWrite()).to.be.true; expect(reference.isRead()).to.be.false; }); - it("the reference in functions should NOT be resolved.", () => { + it("the reference in functions should be resolved.", () => { const ast = espree(` var a = 0; function foo() { @@ -198,7 +198,7 @@ describe("References:", () => { expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); - expect(reference.resolved).to.be.null; + expect(reference.resolved).to.equal(scopeManager.scopes[0].variables[0]); expect(reference.writeExpr).to.be.undefined; expect(reference.isWrite()).to.be.false; expect(reference.isRead()).to.be.true; @@ -206,7 +206,7 @@ describe("References:", () => { }); describe("When there is a `function` declaration on global,", () => { - it("the reference on global should NOT be resolved.", () => { + it("the reference on global should be resolved.", () => { const ast = espree(` function a() {} a(); @@ -225,13 +225,13 @@ describe("References:", () => { expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); - expect(reference.resolved).to.be.null; + expect(reference.resolved).to.equal(scope.variables[0]); expect(reference.writeExpr).to.be.undefined; expect(reference.isWrite()).to.be.false; expect(reference.isRead()).to.be.true; }); - it("the reference in functions should NOT be resolved.", () => { + it("the reference in functions should be resolved.", () => { const ast = espree(` function a() {} function foo() { @@ -252,7 +252,7 @@ describe("References:", () => { expect(reference.from).to.equal(scope); expect(reference.identifier.name).to.equal("a"); - expect(reference.resolved).to.be.null; + expect(reference.resolved).to.equal(scopeManager.scopes[0].variables[0]); expect(reference.writeExpr).to.be.undefined; expect(reference.isWrite()).to.be.false; expect(reference.isRead()).to.be.true;