From cf456bfe4a2e1a76a328637166c3c1e51f1663ea Mon Sep 17 00:00:00 2001 From: Daniel Tschinder Date: Wed, 20 Apr 2016 02:56:15 +0200 Subject: [PATCH] Fix escope to take sourceType and ecmaVersion from options (babel/babel-eslint#288) escope was hardcoded to sourcetype: "module" and ecmaVersion: "6" This changes it to take the configuration from the eslint options and still defaulting to "module" and "6". This is done by having to global variables, as monkeypatch is only triggered once. To fix scoping issues, the same logic as in eslint is applied. It disables the nodejs scope if the sourceType is module. --- eslint/babel-eslint-parser/index.js | 17 ++- .../test/non-regression.js | 104 ++++++++++++++---- 2 files changed, 99 insertions(+), 22 deletions(-) diff --git a/eslint/babel-eslint-parser/index.js b/eslint/babel-eslint-parser/index.js index c9e7bc4df9..70980797b2 100644 --- a/eslint/babel-eslint-parser/index.js +++ b/eslint/babel-eslint-parser/index.js @@ -10,6 +10,7 @@ var traverse = require("babel-traverse").default; var estraverse; var hasPatched = false; +var eslintOptions = {}; function createModule(filename) { var mod = new Module(filename); @@ -75,8 +76,11 @@ function monkeypatch() { var escope = require(escopeLoc); var analyze = escope.analyze; escope.analyze = function (ast, opts) { - opts.ecmaVersion = 6; - opts.sourceType = "module"; + opts.ecmaVersion = eslintOptions.ecmaVersion; + opts.sourceType = eslintOptions.sourceType; + if (eslintOptions.globalReturn !== undefined) { + opts.nodejsScope = eslintOptions.globalReturn; + } var results = analyze.call(this, ast, opts); return results; @@ -353,6 +357,13 @@ function monkeypatch() { exports.parse = function (code, options) { options = options || {}; + eslintOptions.ecmaVersion = options.ecmaVersion = options.ecmaVersion || 6; + eslintOptions.sourceType = options.sourceType = options.sourceType || "module"; + if (options.sourceType === "module") { + eslintOptions.globalReturn = false; + } else { + delete eslintOptions.globalReturn; + } try { monkeypatch(); @@ -366,7 +377,7 @@ exports.parse = function (code, options) { exports.parseNoPatch = function (code, options) { var opts = { - sourceType: options.sourceType || "module", + sourceType: options.sourceType, strictMode: true, allowImportExportEverywhere: false, // consistent with espree allowReturnOutsideFunction: true, diff --git a/eslint/babel-eslint-parser/test/non-regression.js b/eslint/babel-eslint-parser/test/non-regression.js index e34e9f506b..f88ba58cef 100644 --- a/eslint/babel-eslint-parser/test/non-regression.js +++ b/eslint/babel-eslint-parser/test/non-regression.js @@ -2,27 +2,32 @@ "use strict"; var eslint = require("eslint"); -function verifyAndAssertMessages(code, rules, expectedMessages, sourceType) { - var messages = eslint.linter.verify( - code, - { - parser: require.resolve(".."), - rules: rules, - env: { - node: true, - es6: true +function verifyAndAssertMessages(code, rules, expectedMessages, sourceType, overrideConfig) { + var config = { + parser: require.resolve(".."), + rules: rules, + env: { + node: true, + es6: true + }, + parserOptions: { + ecmaVersion: 6, + ecmaFeatures: { + jsx: true, + experimentalObjectRestSpread: true, + globalReturn: true }, - parserOptions: { - ecmaVersion: 6, - ecmaFeatures: { - jsx: true, - experimentalObjectRestSpread: true, - globalReturn: true - }, - sourceType: sourceType || "module" - } + sourceType: sourceType } - ); + }; + + if (overrideConfig) { + for (var key in overrideConfig) { + config[key] = overrideConfig[key] + } + } + + var messages = eslint.linter.verify(code, config); if (messages.length !== expectedMessages.length) { throw new Error("Expected " + expectedMessages.length + " message(s), got " + messages.length + " " + JSON.stringify(messages)); @@ -1362,6 +1367,67 @@ describe("verify", function () { ); }); + it("correctly detects redeclares if in script mode #217", function () { + verifyAndAssertMessages([ + "var a = 321;", + "var a = 123;", + ].join("\n"), + { "no-redeclare": 1 }, + [ "2:5 'a' is already defined no-redeclare" ], + "script" + ); + }); + + it("correctly detects redeclares if in module mode #217", function () { + verifyAndAssertMessages([ + "var a = 321;", + "var a = 123;", + ].join("\n"), + { "no-redeclare": 1 }, + [ "2:5 'a' is already defined no-redeclare" ], + "module" + ); + }); + + it("no-implicit-globals in script", function () { + verifyAndAssertMessages( + "var leakedGlobal = 1;", + { "no-implicit-globals": 1 }, + [ "1:5 Implicit global variable, assign as global property instead. no-implicit-globals" ], + "script", + { + env: {}, + parserOptions: { ecmaVersion: 6, sourceType: "script" } + } + ); + }); + + it("no-implicit-globals in module", function () { + verifyAndAssertMessages( + "var leakedGlobal = 1;", + { "no-implicit-globals": 1 }, + [], + "module", + { + env: {}, + parserOptions: { ecmaVersion: 6, sourceType: "module" } + } + ); + }); + + it("no-implicit-globals in default", function () { + verifyAndAssertMessages( + "var leakedGlobal = 1;", + { "no-implicit-globals": 1 }, + [], + null, + { + env: {}, + parserOptions: { ecmaVersion: 6 } + } + ); + }); + // it("regex with es6 unicodeCodePointEscapes", function () { // verifyAndAssertMessages( // "string.replace(/[\u{0000A0}-\u{10FFFF}<>\&]/gmiu, (char) => `&#x${char.codePointAt(0).toString(16)};`);",