From 62e147be60c1eb84a40c1918913755acbc2d3a3d Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Sat, 4 Dec 2021 02:15:34 +0100 Subject: [PATCH] test: add tests with year-based `ecmaVersion` (#83) Fixes #82 --- tests/es6-block-scope.js | 268 ++++++++++++++------------- tests/es6-import.js | 122 +++++++------ tests/es6-iteration-scope.js | 343 ++++++++++++++++++----------------- tests/es6-switch.js | 69 +++---- tests/implied-strict.js | 31 ++-- tests/util/ecma-version.js | 28 +++ 6 files changed, 461 insertions(+), 400 deletions(-) create mode 100644 tests/util/ecma-version.js diff --git a/tests/es6-block-scope.js b/tests/es6-block-scope.js index 8ddf5bc..7f18f07 100644 --- a/tests/es6-block-scope.js +++ b/tests/es6-block-scope.js @@ -25,162 +25,172 @@ import { expect } from "chai"; import espree from "./util/espree.js"; +import { getSupportedEcmaVersions } from "./util/ecma-version.js"; import { analyze } from "../lib/index.js"; describe("ES6 block scope", () => { it("let is materialized in ES6 block scope#1", () => { - const ast = espree(` - { - let i = 20; - i; - } - `); + getSupportedEcmaVersions({ min: 6 }).forEach(ecmaVersion => { + const ast = espree(` + { + let i = 20; + i; + } + `); - const scopeManager = analyze(ast, { ecmaVersion: 6 }); + const scopeManager = analyze(ast, { ecmaVersion }); - expect(scopeManager.scopes).to.have.length(2); // Program and BlockStatement scope. + expect(scopeManager.scopes).to.have.length(2); // Program and BlockStatement scope. - let scope = scopeManager.scopes[0]; + let scope = scopeManager.scopes[0]; - expect(scope.type).to.be.equal("global"); - expect(scope.variables).to.have.length(0); // No variable in Program scope. + expect(scope.type).to.be.equal("global"); + expect(scope.variables).to.have.length(0); // No variable in Program scope. - scope = scopeManager.scopes[1]; - expect(scope.type).to.be.equal("block"); - expect(scope.variables).to.have.length(1); // `i` in block scope. - expect(scope.variables[0].name).to.be.equal("i"); - expect(scope.references).to.have.length(2); - expect(scope.references[0].identifier.name).to.be.equal("i"); - expect(scope.references[1].identifier.name).to.be.equal("i"); + scope = scopeManager.scopes[1]; + expect(scope.type).to.be.equal("block"); + expect(scope.variables).to.have.length(1); // `i` in block scope. + expect(scope.variables[0].name).to.be.equal("i"); + expect(scope.references).to.have.length(2); + expect(scope.references[0].identifier.name).to.be.equal("i"); + expect(scope.references[1].identifier.name).to.be.equal("i"); + }); }); it("function delaration is materialized in ES6 block scope", () => { - const ast = espree(` - { - function test() { + getSupportedEcmaVersions({ min: 6 }).forEach(ecmaVersion => { + const ast = espree(` + { + function test() { + } + test(); } - test(); - } - `); + `); - const scopeManager = analyze(ast, { ecmaVersion: 6 }); + const scopeManager = analyze(ast, { ecmaVersion }); - expect(scopeManager.scopes).to.have.length(3); + expect(scopeManager.scopes).to.have.length(3); - let scope = scopeManager.scopes[0]; + let scope = scopeManager.scopes[0]; - expect(scope.type).to.be.equal("global"); - expect(scope.variables).to.have.length(0); + expect(scope.type).to.be.equal("global"); + expect(scope.variables).to.have.length(0); - scope = scopeManager.scopes[1]; - expect(scope.type).to.be.equal("block"); - expect(scope.variables).to.have.length(1); - expect(scope.variables[0].name).to.be.equal("test"); - expect(scope.references).to.have.length(1); - expect(scope.references[0].identifier.name).to.be.equal("test"); + scope = scopeManager.scopes[1]; + expect(scope.type).to.be.equal("block"); + expect(scope.variables).to.have.length(1); + expect(scope.variables[0].name).to.be.equal("test"); + expect(scope.references).to.have.length(1); + expect(scope.references[0].identifier.name).to.be.equal("test"); - scope = scopeManager.scopes[2]; - expect(scope.type).to.be.equal("function"); - expect(scope.variables).to.have.length(1); - expect(scope.variables[0].name).to.be.equal("arguments"); - expect(scope.references).to.have.length(0); + scope = scopeManager.scopes[2]; + expect(scope.type).to.be.equal("function"); + expect(scope.variables).to.have.length(1); + expect(scope.variables[0].name).to.be.equal("arguments"); + expect(scope.references).to.have.length(0); + }); }); it("let is not hoistable#1", () => { - const ast = espree(` - var i = 42; (1) - { - i; // (2) ReferenceError at runtime. - let i = 20; // (2) - i; // (2) - } - `); - - const scopeManager = analyze(ast, { ecmaVersion: 6 }); - - expect(scopeManager.scopes).to.have.length(2); - - const globalScope = scopeManager.scopes[0]; - - expect(globalScope.type).to.be.equal("global"); - expect(globalScope.variables).to.have.length(1); - expect(globalScope.variables[0].name).to.be.equal("i"); - expect(globalScope.references).to.have.length(1); - - const scope = scopeManager.scopes[1]; - - expect(scope.type).to.be.equal("block"); - expect(scope.variables).to.have.length(1); - expect(scope.variables[0].name).to.be.equal("i"); - expect(scope.references).to.have.length(3); - expect(scope.references[0].resolved).to.be.equal(scope.variables[0]); - expect(scope.references[1].resolved).to.be.equal(scope.variables[0]); - expect(scope.references[2].resolved).to.be.equal(scope.variables[0]); + getSupportedEcmaVersions({ min: 6 }).forEach(ecmaVersion => { + const ast = espree(` + var i = 42; (1) + { + i; // (2) ReferenceError at runtime. + let i = 20; // (2) + i; // (2) + } + `); + + const scopeManager = analyze(ast, { ecmaVersion }); + + expect(scopeManager.scopes).to.have.length(2); + + const globalScope = scopeManager.scopes[0]; + + expect(globalScope.type).to.be.equal("global"); + expect(globalScope.variables).to.have.length(1); + expect(globalScope.variables[0].name).to.be.equal("i"); + expect(globalScope.references).to.have.length(1); + + const scope = scopeManager.scopes[1]; + + expect(scope.type).to.be.equal("block"); + expect(scope.variables).to.have.length(1); + expect(scope.variables[0].name).to.be.equal("i"); + expect(scope.references).to.have.length(3); + expect(scope.references[0].resolved).to.be.equal(scope.variables[0]); + expect(scope.references[1].resolved).to.be.equal(scope.variables[0]); + expect(scope.references[2].resolved).to.be.equal(scope.variables[0]); + }); + }); it("let is not hoistable#2", () => { - const ast = espree(` - (function () { - var i = 42; // (1) - i; // (1) - { - i; // (3) + getSupportedEcmaVersions({ min: 6 }).forEach(ecmaVersion => { + const ast = espree(` + (function () { + var i = 42; // (1) + i; // (1) { - i; // (2) - let i = 20; // (2) - i; // (2) + i; // (3) + { + i; // (2) + let i = 20; // (2) + i; // (2) + } + let i = 30; // (3) + i; // (3) } - let i = 30; // (3) - i; // (3) - } - i; // (1) - }()); - `); - - const scopeManager = analyze(ast, { ecmaVersion: 6 }); - - expect(scopeManager.scopes).to.have.length(4); - - const globalScope = scopeManager.scopes[0]; - - expect(globalScope.type).to.be.equal("global"); - expect(globalScope.variables).to.have.length(0); - expect(globalScope.references).to.have.length(0); - - let scope = scopeManager.scopes[1]; - - expect(scope.type).to.be.equal("function"); - expect(scope.variables).to.have.length(2); - expect(scope.variables[0].name).to.be.equal("arguments"); - expect(scope.variables[1].name).to.be.equal("i"); - const v1 = scope.variables[1]; - - expect(scope.references).to.have.length(3); - expect(scope.references[0].resolved).to.be.equal(v1); - expect(scope.references[1].resolved).to.be.equal(v1); - expect(scope.references[2].resolved).to.be.equal(v1); - - scope = scopeManager.scopes[2]; - expect(scope.type).to.be.equal("block"); - expect(scope.variables).to.have.length(1); - expect(scope.variables[0].name).to.be.equal("i"); - const v3 = scope.variables[0]; - - expect(scope.references).to.have.length(3); - expect(scope.references[0].resolved).to.be.equal(v3); - expect(scope.references[1].resolved).to.be.equal(v3); - expect(scope.references[2].resolved).to.be.equal(v3); - - scope = scopeManager.scopes[3]; - expect(scope.type).to.be.equal("block"); - expect(scope.variables).to.have.length(1); - expect(scope.variables[0].name).to.be.equal("i"); - const v2 = scope.variables[0]; - - expect(scope.references).to.have.length(3); - expect(scope.references[0].resolved).to.be.equal(v2); - expect(scope.references[1].resolved).to.be.equal(v2); - expect(scope.references[2].resolved).to.be.equal(v2); + i; // (1) + }()); + `); + + const scopeManager = analyze(ast, { ecmaVersion }); + + expect(scopeManager.scopes).to.have.length(4); + + const globalScope = scopeManager.scopes[0]; + + expect(globalScope.type).to.be.equal("global"); + expect(globalScope.variables).to.have.length(0); + expect(globalScope.references).to.have.length(0); + + let scope = scopeManager.scopes[1]; + + expect(scope.type).to.be.equal("function"); + expect(scope.variables).to.have.length(2); + expect(scope.variables[0].name).to.be.equal("arguments"); + expect(scope.variables[1].name).to.be.equal("i"); + const v1 = scope.variables[1]; + + expect(scope.references).to.have.length(3); + expect(scope.references[0].resolved).to.be.equal(v1); + expect(scope.references[1].resolved).to.be.equal(v1); + expect(scope.references[2].resolved).to.be.equal(v1); + + scope = scopeManager.scopes[2]; + expect(scope.type).to.be.equal("block"); + expect(scope.variables).to.have.length(1); + expect(scope.variables[0].name).to.be.equal("i"); + const v3 = scope.variables[0]; + + expect(scope.references).to.have.length(3); + expect(scope.references[0].resolved).to.be.equal(v3); + expect(scope.references[1].resolved).to.be.equal(v3); + expect(scope.references[2].resolved).to.be.equal(v3); + + scope = scopeManager.scopes[3]; + expect(scope.type).to.be.equal("block"); + expect(scope.variables).to.have.length(1); + expect(scope.variables[0].name).to.be.equal("i"); + const v2 = scope.variables[0]; + + expect(scope.references).to.have.length(3); + expect(scope.references[0].resolved).to.be.equal(v2); + expect(scope.references[1].resolved).to.be.equal(v2); + expect(scope.references[2].resolved).to.be.equal(v2); + }); }); }); diff --git a/tests/es6-import.js b/tests/es6-import.js index 0cd8e9d..7c66588 100644 --- a/tests/es6-import.js +++ b/tests/es6-import.js @@ -25,97 +25,107 @@ import { expect } from "chai"; import espree from "./util/espree.js"; +import { getSupportedEcmaVersions } from "./util/ecma-version.js"; import { analyze } from "../lib/index.js"; describe("import declaration", () => { // http://people.mozilla.org/~jorendorff/es6-draft.html#sec-static-and-runtme-semantics-module-records it("should import names from source", () => { - const ast = espree("import v from \"mod\";"); + getSupportedEcmaVersions({ min: 6 }).forEach(ecmaVersion => { + const ast = espree("import v from \"mod\";"); - const scopeManager = analyze(ast, { ecmaVersion: 6, sourceType: "module" }); + const scopeManager = analyze(ast, { ecmaVersion, sourceType: "module" }); - expect(scopeManager.scopes).to.have.length(2); - const globalScope = scopeManager.scopes[0]; + expect(scopeManager.scopes).to.have.length(2); + const globalScope = scopeManager.scopes[0]; - expect(globalScope.type).to.be.equal("global"); - expect(globalScope.variables).to.have.length(0); - expect(globalScope.references).to.have.length(0); + expect(globalScope.type).to.be.equal("global"); + expect(globalScope.variables).to.have.length(0); + expect(globalScope.references).to.have.length(0); - const scope = scopeManager.scopes[1]; + const scope = scopeManager.scopes[1]; + + expect(scope.type).to.be.equal("module"); + expect(scope.isStrict).to.be.true; + expect(scope.variables).to.have.length(1); + expect(scope.variables[0].name).to.be.equal("v"); + expect(scope.variables[0].defs[0].type).to.be.equal("ImportBinding"); + expect(scope.references).to.have.length(0); + }); - expect(scope.type).to.be.equal("module"); - expect(scope.isStrict).to.be.true; - expect(scope.variables).to.have.length(1); - expect(scope.variables[0].name).to.be.equal("v"); - expect(scope.variables[0].defs[0].type).to.be.equal("ImportBinding"); - expect(scope.references).to.have.length(0); }); it("should import namespaces", () => { - const ast = espree("import * as ns from \"mod\";"); + getSupportedEcmaVersions({ min: 6 }).forEach(ecmaVersion => { + const ast = espree("import * as ns from \"mod\";"); - const scopeManager = analyze(ast, { ecmaVersion: 6, sourceType: "module" }); + const scopeManager = analyze(ast, { ecmaVersion, sourceType: "module" }); - expect(scopeManager.scopes).to.have.length(2); - const globalScope = scopeManager.scopes[0]; + expect(scopeManager.scopes).to.have.length(2); + const globalScope = scopeManager.scopes[0]; - expect(globalScope.type).to.be.equal("global"); - expect(globalScope.variables).to.have.length(0); - expect(globalScope.references).to.have.length(0); + expect(globalScope.type).to.be.equal("global"); + expect(globalScope.variables).to.have.length(0); + expect(globalScope.references).to.have.length(0); - const scope = scopeManager.scopes[1]; + const scope = scopeManager.scopes[1]; - expect(scope.type).to.be.equal("module"); - expect(scope.isStrict).to.be.true; - expect(scope.variables).to.have.length(1); - expect(scope.variables[0].name).to.be.equal("ns"); - expect(scope.variables[0].defs[0].type).to.be.equal("ImportBinding"); - expect(scope.references).to.have.length(0); + expect(scope.type).to.be.equal("module"); + expect(scope.isStrict).to.be.true; + expect(scope.variables).to.have.length(1); + expect(scope.variables[0].name).to.be.equal("ns"); + expect(scope.variables[0].defs[0].type).to.be.equal("ImportBinding"); + expect(scope.references).to.have.length(0); + }); }); it("should import insided names#1", () => { - const ast = espree("import {x} from \"mod\";"); + getSupportedEcmaVersions({ min: 6 }).forEach(ecmaVersion => { + const ast = espree("import {x} from \"mod\";"); - const scopeManager = analyze(ast, { ecmaVersion: 6, sourceType: "module" }); + const scopeManager = analyze(ast, { ecmaVersion, sourceType: "module" }); - expect(scopeManager.scopes).to.have.length(2); - const globalScope = scopeManager.scopes[0]; + expect(scopeManager.scopes).to.have.length(2); + const globalScope = scopeManager.scopes[0]; - expect(globalScope.type).to.be.equal("global"); - expect(globalScope.variables).to.have.length(0); - expect(globalScope.references).to.have.length(0); + expect(globalScope.type).to.be.equal("global"); + expect(globalScope.variables).to.have.length(0); + expect(globalScope.references).to.have.length(0); - const scope = scopeManager.scopes[1]; + const scope = scopeManager.scopes[1]; - expect(scope.type).to.be.equal("module"); - expect(scope.isStrict).to.be.true; - expect(scope.variables).to.have.length(1); - expect(scope.variables[0].name).to.be.equal("x"); - expect(scope.variables[0].defs[0].type).to.be.equal("ImportBinding"); - expect(scope.references).to.have.length(0); + expect(scope.type).to.be.equal("module"); + expect(scope.isStrict).to.be.true; + expect(scope.variables).to.have.length(1); + expect(scope.variables[0].name).to.be.equal("x"); + expect(scope.variables[0].defs[0].type).to.be.equal("ImportBinding"); + expect(scope.references).to.have.length(0); + }); }); it("should import insided names#2", () => { - const ast = espree("import {x as v} from \"mod\";"); + getSupportedEcmaVersions({ min: 6 }).forEach(ecmaVersion => { + const ast = espree("import {x as v} from \"mod\";"); - const scopeManager = analyze(ast, { ecmaVersion: 6, sourceType: "module" }); + const scopeManager = analyze(ast, { ecmaVersion, sourceType: "module" }); - expect(scopeManager.scopes).to.have.length(2); - const globalScope = scopeManager.scopes[0]; + expect(scopeManager.scopes).to.have.length(2); + const globalScope = scopeManager.scopes[0]; - expect(globalScope.type).to.be.equal("global"); - expect(globalScope.variables).to.have.length(0); - expect(globalScope.references).to.have.length(0); + expect(globalScope.type).to.be.equal("global"); + expect(globalScope.variables).to.have.length(0); + expect(globalScope.references).to.have.length(0); - const scope = scopeManager.scopes[1]; + const scope = scopeManager.scopes[1]; - expect(scope.type).to.be.equal("module"); - expect(scope.isStrict).to.be.true; - expect(scope.variables).to.have.length(1); - expect(scope.variables[0].name).to.be.equal("v"); - expect(scope.variables[0].defs[0].type).to.be.equal("ImportBinding"); - expect(scope.references).to.have.length(0); + expect(scope.type).to.be.equal("module"); + expect(scope.isStrict).to.be.true; + expect(scope.variables).to.have.length(1); + expect(scope.variables[0].name).to.be.equal("v"); + expect(scope.variables[0].defs[0].type).to.be.equal("ImportBinding"); + expect(scope.references).to.have.length(0); + }); }); // TODO: Should parse it. diff --git a/tests/es6-iteration-scope.js b/tests/es6-iteration-scope.js index 2ed630f..f8b0613 100644 --- a/tests/es6-iteration-scope.js +++ b/tests/es6-iteration-scope.js @@ -25,184 +25,191 @@ import { expect } from "chai"; import espree from "./util/espree.js"; +import { getSupportedEcmaVersions } from "./util/ecma-version.js"; import { analyze } from "../lib/index.js"; describe("ES6 iteration scope", () => { it("let materialize iteration scope for ForInStatement#1", () => { - const ast = espree(` - (function () { - let i = 20; - for (let i in i) { - console.log(i); - } - }()); - `); - - const scopeManager = analyze(ast, { ecmaVersion: 6 }); - - expect(scopeManager.scopes).to.have.length(4); - - let scope = scopeManager.scopes[0]; - - expect(scope.type).to.be.equal("global"); - expect(scope.variables).to.have.length(0); - - scope = scopeManager.scopes[1]; - expect(scope.type).to.be.equal("function"); - expect(scope.variables).to.have.length(2); - expect(scope.variables[0].name).to.be.equal("arguments"); - expect(scope.variables[1].name).to.be.equal("i"); - expect(scope.references).to.have.length(1); - expect(scope.references[0].identifier.name).to.be.equal("i"); - expect(scope.references[0].resolved).to.be.equal(scope.variables[1]); - - const iterScope = scope = scopeManager.scopes[2]; - - expect(scope.type).to.be.equal("for"); - expect(scope.variables).to.have.length(1); - expect(scope.variables[0].name).to.be.equal("i"); - expect(scope.references).to.have.length(2); - expect(scope.references[0].identifier.name).to.be.equal("i"); - expect(scope.references[0].resolved).to.be.equal(scope.variables[0]); - expect(scope.references[1].identifier.name).to.be.equal("i"); - expect(scope.references[1].resolved).to.be.equal(scope.variables[0]); - - scope = scopeManager.scopes[3]; - expect(scope.type).to.be.equal("block"); - expect(scope.variables).to.have.length(0); - expect(scope.references).to.have.length(2); - expect(scope.references[0].identifier.name).to.be.equal("console"); - expect(scope.references[0].resolved).to.be.equal(null); - expect(scope.references[1].identifier.name).to.be.equal("i"); - expect(scope.references[1].resolved).to.be.equal(iterScope.variables[0]); + getSupportedEcmaVersions({ min: 6 }).forEach(ecmaVersion => { + const ast = espree(` + (function () { + let i = 20; + for (let i in i) { + console.log(i); + } + }()); + `); + + const scopeManager = analyze(ast, { ecmaVersion }); + + expect(scopeManager.scopes).to.have.length(4); + + let scope = scopeManager.scopes[0]; + + expect(scope.type).to.be.equal("global"); + expect(scope.variables).to.have.length(0); + + scope = scopeManager.scopes[1]; + expect(scope.type).to.be.equal("function"); + expect(scope.variables).to.have.length(2); + expect(scope.variables[0].name).to.be.equal("arguments"); + expect(scope.variables[1].name).to.be.equal("i"); + expect(scope.references).to.have.length(1); + expect(scope.references[0].identifier.name).to.be.equal("i"); + expect(scope.references[0].resolved).to.be.equal(scope.variables[1]); + + const iterScope = scope = scopeManager.scopes[2]; + + expect(scope.type).to.be.equal("for"); + expect(scope.variables).to.have.length(1); + expect(scope.variables[0].name).to.be.equal("i"); + expect(scope.references).to.have.length(2); + expect(scope.references[0].identifier.name).to.be.equal("i"); + expect(scope.references[0].resolved).to.be.equal(scope.variables[0]); + expect(scope.references[1].identifier.name).to.be.equal("i"); + expect(scope.references[1].resolved).to.be.equal(scope.variables[0]); + + scope = scopeManager.scopes[3]; + expect(scope.type).to.be.equal("block"); + expect(scope.variables).to.have.length(0); + expect(scope.references).to.have.length(2); + expect(scope.references[0].identifier.name).to.be.equal("console"); + expect(scope.references[0].resolved).to.be.equal(null); + expect(scope.references[1].identifier.name).to.be.equal("i"); + expect(scope.references[1].resolved).to.be.equal(iterScope.variables[0]); + }); }); it("let materialize iteration scope for ForInStatement#2", () => { - const ast = espree(` - (function () { - let i = 20; - for (let { i, j, k } in i) { - console.log(i); - } - }()); - `); - - const scopeManager = analyze(ast, { ecmaVersion: 6 }); - - expect(scopeManager.scopes).to.have.length(4); - - let scope = scopeManager.scopes[0]; - - expect(scope.type).to.be.equal("global"); - expect(scope.variables).to.have.length(0); - - scope = scopeManager.scopes[1]; - expect(scope.type).to.be.equal("function"); - expect(scope.variables).to.have.length(2); - expect(scope.variables[0].name).to.be.equal("arguments"); - expect(scope.variables[1].name).to.be.equal("i"); - expect(scope.references).to.have.length(1); - expect(scope.references[0].identifier.name).to.be.equal("i"); - expect(scope.references[0].resolved).to.be.equal(scope.variables[1]); - - const iterScope = scope = scopeManager.scopes[2]; - - expect(scope.type).to.be.equal("for"); - expect(scope.variables).to.have.length(3); - expect(scope.variables[0].name).to.be.equal("i"); - expect(scope.variables[1].name).to.be.equal("j"); - expect(scope.variables[2].name).to.be.equal("k"); - expect(scope.references).to.have.length(4); - expect(scope.references[0].identifier.name).to.be.equal("i"); - expect(scope.references[0].resolved).to.be.equal(scope.variables[0]); - expect(scope.references[1].identifier.name).to.be.equal("j"); - expect(scope.references[1].resolved).to.be.equal(scope.variables[1]); - expect(scope.references[2].identifier.name).to.be.equal("k"); - expect(scope.references[2].resolved).to.be.equal(scope.variables[2]); - expect(scope.references[3].identifier.name).to.be.equal("i"); - expect(scope.references[3].resolved).to.be.equal(scope.variables[0]); - - scope = scopeManager.scopes[3]; - expect(scope.type).to.be.equal("block"); - expect(scope.variables).to.have.length(0); - expect(scope.references).to.have.length(2); - expect(scope.references[0].identifier.name).to.be.equal("console"); - expect(scope.references[0].resolved).to.be.equal(null); - expect(scope.references[1].identifier.name).to.be.equal("i"); - expect(scope.references[1].resolved).to.be.equal(iterScope.variables[0]); + getSupportedEcmaVersions({ min: 6 }).forEach(ecmaVersion => { + const ast = espree(` + (function () { + let i = 20; + for (let { i, j, k } in i) { + console.log(i); + } + }()); + `); + + const scopeManager = analyze(ast, { ecmaVersion }); + + expect(scopeManager.scopes).to.have.length(4); + + let scope = scopeManager.scopes[0]; + + expect(scope.type).to.be.equal("global"); + expect(scope.variables).to.have.length(0); + + scope = scopeManager.scopes[1]; + expect(scope.type).to.be.equal("function"); + expect(scope.variables).to.have.length(2); + expect(scope.variables[0].name).to.be.equal("arguments"); + expect(scope.variables[1].name).to.be.equal("i"); + expect(scope.references).to.have.length(1); + expect(scope.references[0].identifier.name).to.be.equal("i"); + expect(scope.references[0].resolved).to.be.equal(scope.variables[1]); + + const iterScope = scope = scopeManager.scopes[2]; + + expect(scope.type).to.be.equal("for"); + expect(scope.variables).to.have.length(3); + expect(scope.variables[0].name).to.be.equal("i"); + expect(scope.variables[1].name).to.be.equal("j"); + expect(scope.variables[2].name).to.be.equal("k"); + expect(scope.references).to.have.length(4); + expect(scope.references[0].identifier.name).to.be.equal("i"); + expect(scope.references[0].resolved).to.be.equal(scope.variables[0]); + expect(scope.references[1].identifier.name).to.be.equal("j"); + expect(scope.references[1].resolved).to.be.equal(scope.variables[1]); + expect(scope.references[2].identifier.name).to.be.equal("k"); + expect(scope.references[2].resolved).to.be.equal(scope.variables[2]); + expect(scope.references[3].identifier.name).to.be.equal("i"); + expect(scope.references[3].resolved).to.be.equal(scope.variables[0]); + + scope = scopeManager.scopes[3]; + expect(scope.type).to.be.equal("block"); + expect(scope.variables).to.have.length(0); + expect(scope.references).to.have.length(2); + expect(scope.references[0].identifier.name).to.be.equal("console"); + expect(scope.references[0].resolved).to.be.equal(null); + expect(scope.references[1].identifier.name).to.be.equal("i"); + expect(scope.references[1].resolved).to.be.equal(iterScope.variables[0]); + }); }); it("let materialize iteration scope for ForStatement#2", () => { - const ast = espree(` - (function () { - let i = 20; - let obj = {}; - for (let { i, j, k } = obj; i < okok; ++i) { - console.log(i, j, k); - } - }()); - `); - - const scopeManager = analyze(ast, { ecmaVersion: 6 }); - - expect(scopeManager.scopes).to.have.length(4); - - let scope = scopeManager.scopes[0]; - - expect(scope.type).to.be.equal("global"); - expect(scope.variables).to.have.length(0); - - const functionScope = scope = scopeManager.scopes[1]; - - expect(scope.type).to.be.equal("function"); - expect(scope.variables).to.have.length(3); - expect(scope.variables[0].name).to.be.equal("arguments"); - expect(scope.variables[1].name).to.be.equal("i"); - expect(scope.variables[2].name).to.be.equal("obj"); - expect(scope.references).to.have.length(2); - expect(scope.references[0].identifier.name).to.be.equal("i"); - expect(scope.references[0].resolved).to.be.equal(scope.variables[1]); - expect(scope.references[1].identifier.name).to.be.equal("obj"); - expect(scope.references[1].resolved).to.be.equal(scope.variables[2]); - - const iterScope = scope = scopeManager.scopes[2]; - - expect(scope.type).to.be.equal("for"); - expect(scope.variables).to.have.length(3); - expect(scope.variables[0].name).to.be.equal("i"); - expect(scope.variables[0].defs[0].type).to.be.equal("Variable"); - expect(scope.variables[1].name).to.be.equal("j"); - expect(scope.variables[1].defs[0].type).to.be.equal("Variable"); - expect(scope.variables[2].name).to.be.equal("k"); - expect(scope.variables[2].defs[0].type).to.be.equal("Variable"); - expect(scope.references).to.have.length(7); - expect(scope.references[0].identifier.name).to.be.equal("i"); - expect(scope.references[0].resolved).to.be.equal(scope.variables[0]); - expect(scope.references[1].identifier.name).to.be.equal("j"); - expect(scope.references[1].resolved).to.be.equal(scope.variables[1]); - expect(scope.references[2].identifier.name).to.be.equal("k"); - expect(scope.references[2].resolved).to.be.equal(scope.variables[2]); - expect(scope.references[3].identifier.name).to.be.equal("obj"); - expect(scope.references[3].resolved).to.be.equal(functionScope.variables[2]); - expect(scope.references[4].identifier.name).to.be.equal("i"); - expect(scope.references[4].resolved).to.be.equal(scope.variables[0]); - expect(scope.references[5].identifier.name).to.be.equal("okok"); - expect(scope.references[5].resolved).to.be.null; - expect(scope.references[6].identifier.name).to.be.equal("i"); - expect(scope.references[6].resolved).to.be.equal(scope.variables[0]); - - scope = scopeManager.scopes[3]; - expect(scope.type).to.be.equal("block"); - expect(scope.variables).to.have.length(0); - expect(scope.references).to.have.length(4); - expect(scope.references[0].identifier.name).to.be.equal("console"); - expect(scope.references[0].resolved).to.be.null; - expect(scope.references[1].identifier.name).to.be.equal("i"); - expect(scope.references[1].resolved).to.be.equal(iterScope.variables[0]); - expect(scope.references[2].identifier.name).to.be.equal("j"); - expect(scope.references[2].resolved).to.be.equal(iterScope.variables[1]); - expect(scope.references[3].identifier.name).to.be.equal("k"); - expect(scope.references[3].resolved).to.be.equal(iterScope.variables[2]); + getSupportedEcmaVersions({ min: 6 }).forEach(ecmaVersion => { + const ast = espree(` + (function () { + let i = 20; + let obj = {}; + for (let { i, j, k } = obj; i < okok; ++i) { + console.log(i, j, k); + } + }()); + `); + + const scopeManager = analyze(ast, { ecmaVersion }); + + expect(scopeManager.scopes).to.have.length(4); + + let scope = scopeManager.scopes[0]; + + expect(scope.type).to.be.equal("global"); + expect(scope.variables).to.have.length(0); + + const functionScope = scope = scopeManager.scopes[1]; + + expect(scope.type).to.be.equal("function"); + expect(scope.variables).to.have.length(3); + expect(scope.variables[0].name).to.be.equal("arguments"); + expect(scope.variables[1].name).to.be.equal("i"); + expect(scope.variables[2].name).to.be.equal("obj"); + expect(scope.references).to.have.length(2); + expect(scope.references[0].identifier.name).to.be.equal("i"); + expect(scope.references[0].resolved).to.be.equal(scope.variables[1]); + expect(scope.references[1].identifier.name).to.be.equal("obj"); + expect(scope.references[1].resolved).to.be.equal(scope.variables[2]); + + const iterScope = scope = scopeManager.scopes[2]; + + expect(scope.type).to.be.equal("for"); + expect(scope.variables).to.have.length(3); + expect(scope.variables[0].name).to.be.equal("i"); + expect(scope.variables[0].defs[0].type).to.be.equal("Variable"); + expect(scope.variables[1].name).to.be.equal("j"); + expect(scope.variables[1].defs[0].type).to.be.equal("Variable"); + expect(scope.variables[2].name).to.be.equal("k"); + expect(scope.variables[2].defs[0].type).to.be.equal("Variable"); + expect(scope.references).to.have.length(7); + expect(scope.references[0].identifier.name).to.be.equal("i"); + expect(scope.references[0].resolved).to.be.equal(scope.variables[0]); + expect(scope.references[1].identifier.name).to.be.equal("j"); + expect(scope.references[1].resolved).to.be.equal(scope.variables[1]); + expect(scope.references[2].identifier.name).to.be.equal("k"); + expect(scope.references[2].resolved).to.be.equal(scope.variables[2]); + expect(scope.references[3].identifier.name).to.be.equal("obj"); + expect(scope.references[3].resolved).to.be.equal(functionScope.variables[2]); + expect(scope.references[4].identifier.name).to.be.equal("i"); + expect(scope.references[4].resolved).to.be.equal(scope.variables[0]); + expect(scope.references[5].identifier.name).to.be.equal("okok"); + expect(scope.references[5].resolved).to.be.null; + expect(scope.references[6].identifier.name).to.be.equal("i"); + expect(scope.references[6].resolved).to.be.equal(scope.variables[0]); + + scope = scopeManager.scopes[3]; + expect(scope.type).to.be.equal("block"); + expect(scope.variables).to.have.length(0); + expect(scope.references).to.have.length(4); + expect(scope.references[0].identifier.name).to.be.equal("console"); + expect(scope.references[0].resolved).to.be.null; + expect(scope.references[1].identifier.name).to.be.equal("i"); + expect(scope.references[1].resolved).to.be.equal(iterScope.variables[0]); + expect(scope.references[2].identifier.name).to.be.equal("j"); + expect(scope.references[2].resolved).to.be.equal(iterScope.variables[1]); + expect(scope.references[3].identifier.name).to.be.equal("k"); + expect(scope.references[3].resolved).to.be.equal(iterScope.variables[2]); + }); }); }); diff --git a/tests/es6-switch.js b/tests/es6-switch.js index 05be10c..13971ba 100644 --- a/tests/es6-switch.js +++ b/tests/es6-switch.js @@ -25,49 +25,52 @@ import { expect } from "chai"; import espree from "./util/espree.js"; +import { getSupportedEcmaVersions } from "./util/ecma-version.js"; import { analyze } from "../lib/index.js"; describe("ES6 switch", () => { it("materialize scope", () => { - const ast = espree(` - switch (ok) { - case hello: - let i = 20; - i; - break; + getSupportedEcmaVersions({ min: 6 }).forEach(ecmaVersion => { + const ast = espree(` + switch (ok) { + case hello: + let i = 20; + i; + break; - default: - let test = 30; - test; - } - `); + default: + let test = 30; + test; + } + `); - const scopeManager = analyze(ast, { ecmaVersion: 6 }); + const scopeManager = analyze(ast, { ecmaVersion }); - expect(scopeManager.scopes).to.have.length(2); + expect(scopeManager.scopes).to.have.length(2); - let scope = scopeManager.scopes[0]; + let scope = scopeManager.scopes[0]; - expect(scope.type).to.be.equal("global"); - expect(scope.block.type).to.be.equal("Program"); - expect(scope.isStrict).to.be.false; - expect(scope.variables).to.have.length(0); - expect(scope.references).to.have.length(1); - expect(scope.references[0].identifier.name).to.be.equal("ok"); + expect(scope.type).to.be.equal("global"); + expect(scope.block.type).to.be.equal("Program"); + expect(scope.isStrict).to.be.false; + expect(scope.variables).to.have.length(0); + expect(scope.references).to.have.length(1); + expect(scope.references[0].identifier.name).to.be.equal("ok"); - scope = scopeManager.scopes[1]; - expect(scope.type).to.be.equal("switch"); - expect(scope.block.type).to.be.equal("SwitchStatement"); - expect(scope.isStrict).to.be.false; - expect(scope.variables).to.have.length(2); - expect(scope.variables[0].name).to.be.equal("i"); - expect(scope.variables[1].name).to.be.equal("test"); - expect(scope.references).to.have.length(5); - expect(scope.references[0].identifier.name).to.be.equal("hello"); - expect(scope.references[1].identifier.name).to.be.equal("i"); - expect(scope.references[2].identifier.name).to.be.equal("i"); - expect(scope.references[3].identifier.name).to.be.equal("test"); - expect(scope.references[4].identifier.name).to.be.equal("test"); + scope = scopeManager.scopes[1]; + expect(scope.type).to.be.equal("switch"); + expect(scope.block.type).to.be.equal("SwitchStatement"); + expect(scope.isStrict).to.be.false; + expect(scope.variables).to.have.length(2); + expect(scope.variables[0].name).to.be.equal("i"); + expect(scope.variables[1].name).to.be.equal("test"); + expect(scope.references).to.have.length(5); + expect(scope.references[0].identifier.name).to.be.equal("hello"); + expect(scope.references[1].identifier.name).to.be.equal("i"); + expect(scope.references[2].identifier.name).to.be.equal("i"); + expect(scope.references[3].identifier.name).to.be.equal("test"); + expect(scope.references[4].identifier.name).to.be.equal("test"); + }); }); }); diff --git a/tests/implied-strict.js b/tests/implied-strict.js index 2d07869..9168a49 100644 --- a/tests/implied-strict.js +++ b/tests/implied-strict.js @@ -25,6 +25,7 @@ import { expect } from "chai"; import espree from "./util/espree.js"; +import { getSupportedEcmaVersions } from "./util/ecma-version.js"; import { analyze } from "../lib/index.js"; describe("impliedStrict option", () => { @@ -37,25 +38,27 @@ describe("impliedStrict option", () => { } `); - const scopeManager = analyze(ast, { ecmaVersion: 5, impliedStrict: true }); + getSupportedEcmaVersions({ min: 5 }).forEach(ecmaVersion => { + const scopeManager = analyze(ast, { ecmaVersion, impliedStrict: true }); - expect(scopeManager.scopes).to.have.length(3); + expect(scopeManager.scopes).to.have.length(3); - let scope = scopeManager.scopes[0]; + let scope = scopeManager.scopes[0]; - expect(scope.type).to.be.equal("global"); - expect(scope.block.type).to.be.equal("Program"); - expect(scope.isStrict).to.be.true; + expect(scope.type).to.be.equal("global"); + expect(scope.block.type).to.be.equal("Program"); + expect(scope.isStrict).to.be.true; - scope = scopeManager.scopes[1]; - expect(scope.type).to.be.equal("function"); - expect(scope.block.type).to.be.equal("FunctionDeclaration"); - expect(scope.isStrict).to.be.true; + scope = scopeManager.scopes[1]; + expect(scope.type).to.be.equal("function"); + expect(scope.block.type).to.be.equal("FunctionDeclaration"); + expect(scope.isStrict).to.be.true; - scope = scopeManager.scopes[2]; - expect(scope.type).to.be.equal("function"); - expect(scope.block.type).to.be.equal("FunctionDeclaration"); - expect(scope.isStrict).to.be.true; + scope = scopeManager.scopes[2]; + expect(scope.type).to.be.equal("function"); + expect(scope.block.type).to.be.equal("FunctionDeclaration"); + expect(scope.isStrict).to.be.true; + }); }); it("ensures impliedStrict option is only effective when ecmaVersion option >= 5", () => { diff --git a/tests/util/ecma-version.js b/tests/util/ecma-version.js new file mode 100644 index 0000000..befc4ff --- /dev/null +++ b/tests/util/ecma-version.js @@ -0,0 +1,28 @@ +/** + * @fileoverview ECMAScript version utilities used in tests + * @author Milos Djermanovic + */ + +import * as espree from "espree"; + +/** + * Gets an array of supported ECMAScript versions. + * @param {number} [min] Minimum ECMAScript version to get. This should be a revision-based number (3, 5, 6, 7...). + * @returns {number[]} Supported ECMAScript versions, including their year-based representations. + * @example + * + * getSupportedEcmaVersions() + * // => [3, 5, 6, 2015, 7, 2016, 8, 2017, 9, 2018, 10, 2019, 11, 2020, 12, 2021, 13, 2022] + * + * getSupportedEcmaVersions({ min: 8 }) + * // => [8, 2017, 9, 2018, 10, 2019, 11, 2020, 12, 2021, 13, 2022] + */ +export function getSupportedEcmaVersions({ min = 0 } = {}) { + return espree.supportedEcmaVersions + .filter( + ecmaVersion => ecmaVersion >= min + ) + .flatMap( + ecmaVersion => (ecmaVersion >= 6 ? [ecmaVersion, ecmaVersion + 2009] : [ecmaVersion]) + ); +}