From 4e1d24ca4a747c14b37f059543cf08d1e1820b2d Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Sat, 5 Feb 2022 02:27:30 +0100 Subject: [PATCH] fix: ignore `"use strict"` directives in ES3 (#87) --- lib/scope.js | 4 +- tests/use-strict.js | 101 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 tests/use-strict.js diff --git a/lib/scope.js b/lib/scope.js index 42c0693..0619b90 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -263,7 +263,9 @@ class Scope { * Whether 'use strict' is in effect in this scope. * @member {boolean} Scope#isStrict */ - this.isStrict = isStrictScope(this, block, isMethodDefinition, scopeManager.__useDirective()); + this.isStrict = scopeManager.isStrictModeSupported() + ? isStrictScope(this, block, isMethodDefinition, scopeManager.__useDirective()) + : false; /** * List of nested {@link Scope}s. diff --git a/tests/use-strict.js b/tests/use-strict.js new file mode 100644 index 0000000..e7f6916 --- /dev/null +++ b/tests/use-strict.js @@ -0,0 +1,101 @@ +/** + * @fileoverview Tests for "use strict" directives. + * @author Milos Djermanovic + */ + +import assert from "assert"; +import * as espree from "espree"; +import { KEYS } from "eslint-visitor-keys"; +import { analyze } from "../lib/index.js"; +import { getSupportedEcmaVersions } from "./util/ecma-version.js"; + +/** + * Asserts `isStrict` property value for the given scope and all its descendants. + * @param {Scope} scope The scope to check. + * @param {boolean} expected The expected value for `isStrict` property. + * @throws {AssertionError} If `isStrict` property value of `scope` or of + * any of its descendant scopes doesn't match `expected`. + * @returns {void} + */ +function assertIsStrictRecursively(scope, expected) { + assert.strictEqual(scope.isStrict, expected); + + scope.childScopes.forEach(childScope => { + assertIsStrictRecursively(childScope, expected); + }); +} + +describe("'use strict' directives", () => { + + it("should be ignored when ecmaVersion = 3", () => { + const ecmaVersion = 3; + + const ast = espree.parse(` + "use strict"; + function a() { + "use strict"; + function b() { + foo(); + } + } + `, { ecmaVersion, range: true }); + + const { globalScope } = analyze(ast, { ecmaVersion, childVisitorKeys: KEYS }); + + assertIsStrictRecursively(globalScope, false); + }); + + it("at the top level should make all scopes strict when ecmaVersion >= 5", () => { + getSupportedEcmaVersions({ min: 5 }).forEach(ecmaVersion => { + const ast = espree.parse(` + "use strict"; + if (a) { + foo(); + } + function b() { + if (c) { + foo(); + } + function d() { + if (e) { + foo(); + } + } + } + `, { ecmaVersion, range: true }); + + const { globalScope } = analyze(ast, { ecmaVersion, childVisitorKeys: KEYS }); + + assertIsStrictRecursively(globalScope, true); + }); + }); + + it("at the function level should make the function's scope and all its descendants strict when ecmaVersion >= 5", () => { + getSupportedEcmaVersions({ min: 5 }).forEach(ecmaVersion => { + const ast = espree.parse(` + function a() { + "use strict"; + if (b) { + foo(); + } + function c() { + if (d) { + foo(); + } + } + } + function e() { + if (f) { + foo(); + } + } + `, { ecmaVersion, range: true }); + + const { globalScope } = analyze(ast, { ecmaVersion, childVisitorKeys: KEYS }); + + assert.strictEqual(globalScope.isStrict, false); + assertIsStrictRecursively(globalScope.childScopes[0], true); // function a() { ... } + assertIsStrictRecursively(globalScope.childScopes[1], false); // function e() { ... } + }); + }); +});