From c333bd64cb014cac8b56062421e9a5c0d28d798b Mon Sep 17 00:00:00 2001 From: Brian Ng Date: Tue, 25 Sep 2018 13:07:46 -0500 Subject: [PATCH] Drop old monkeypatching behavior (#689) An alternative to adding a direct dep on estraverse (https://github.com/babel/babel-eslint/pull/685), let's just drop the old monkeypatching behavior. Closes #685, Closes #680 --- lib/index.js | 5 +- lib/parse-with-patch.js | 9 - lib/patch-eslint-scope.js | 374 -------------------------------- package.json | 3 +- test/fixtures/use-eslint-old.js | 12 - test/integration.js | 1 + yarn.lock | 50 +---- 7 files changed, 7 insertions(+), 447 deletions(-) delete mode 100644 lib/parse-with-patch.js delete mode 100644 lib/patch-eslint-scope.js delete mode 100644 test/fixtures/use-eslint-old.js diff --git a/lib/index.js b/lib/index.js index c4655280..9e527d26 100644 --- a/lib/index.js +++ b/lib/index.js @@ -11,10 +11,7 @@ exports.parseForESLint = function(code, options) { options.allowImportExportEverywhere = options.allowImportExportEverywhere || false; - if (options.eslintVisitorKeys && options.eslintScopeManager) { - return require("./parse-with-scope")(code, options); - } - return { ast: require("./parse-with-patch")(code, options) }; + return require("./parse-with-scope")(code, options); }; exports.parseNoPatch = function(code, options) { diff --git a/lib/parse-with-patch.js b/lib/parse-with-patch.js deleted file mode 100644 index ba1b95b5..00000000 --- a/lib/parse-with-patch.js +++ /dev/null @@ -1,9 +0,0 @@ -"use strict"; - -var parse = require("./parse"); -var patchEscope = require("./patch-eslint-scope"); - -module.exports = function(code, options) { - patchEscope(options); - return parse(code, options); -}; diff --git a/lib/patch-eslint-scope.js b/lib/patch-eslint-scope.js deleted file mode 100644 index 2bf2b350..00000000 --- a/lib/patch-eslint-scope.js +++ /dev/null @@ -1,374 +0,0 @@ -"use strict"; - -var Module = require("module"); -var path = require("path"); -var t = require("@babel/types"); - -function getModules() { - try { - // avoid importing a local copy of eslint, try to find a peer dependency - var eslintLoc = Module._resolveFilename("eslint", module.parent); - } catch (err) { - try { - // avoids breaking in jest where module.parent is undefined - eslintLoc = require.resolve("eslint"); - } catch (err) { - throw new ReferenceError("couldn't resolve eslint"); - } - } - - // get modules relative to what eslint will load - var eslintMod = new Module(eslintLoc); - eslintMod.filename = eslintLoc; - eslintMod.paths = Module._nodeModulePaths(path.dirname(eslintLoc)); - - try { - var escope = eslintMod.require("eslint-scope"); - var Definition = eslintMod.require("eslint-scope/lib/definition") - .Definition; - var referencer = eslintMod.require("eslint-scope/lib/referencer"); - } catch (err) { - escope = eslintMod.require("escope"); - Definition = eslintMod.require("escope/lib/definition").Definition; - referencer = eslintMod.require("escope/lib/referencer"); - } - - var estraverse = eslintMod.require("estraverse"); - - if (referencer.__esModule) referencer = referencer.default; - - return { - Definition, - escope, - estraverse, - referencer, - }; -} - -function monkeypatch(modules) { - var Definition = modules.Definition; - var escope = modules.escope; - var estraverse = modules.estraverse; - var referencer = modules.referencer; - - Object.assign(estraverse.VisitorKeys, t.VISITOR_KEYS); - estraverse.VisitorKeys.MethodDefinition.push("decorators"); - estraverse.VisitorKeys.Property.push("decorators"); - - // if there are decorators, then visit each - function visitDecorators(node) { - if (!node.decorators) { - return; - } - for (var i = 0; i < node.decorators.length; i++) { - if (node.decorators[i].expression) { - this.visit(node.decorators[i]); - } - } - } - - // iterate through part of t.VISITOR_KEYS - var flowFlippedAliasKeys = t.FLIPPED_ALIAS_KEYS.Flow.concat([ - "ArrayPattern", - "ClassDeclaration", - "ClassExpression", - "FunctionDeclaration", - "FunctionExpression", - "Identifier", - "ObjectPattern", - "RestElement", - ]); - var visitorKeysMap = Object.keys(t.VISITOR_KEYS).reduce(function(acc, key) { - var value = t.VISITOR_KEYS[key]; - if (flowFlippedAliasKeys.indexOf(value) === -1) { - acc[key] = value; - } - return acc; - }, {}); - - var propertyTypes = { - // loops - callProperties: { type: "loop", values: ["value"] }, - indexers: { type: "loop", values: ["key", "value"] }, - properties: { type: "loop", values: ["argument", "value"] }, - types: { type: "loop" }, - params: { type: "loop" }, - // single property - argument: { type: "single" }, - elementType: { type: "single" }, - qualification: { type: "single" }, - rest: { type: "single" }, - returnType: { type: "single" }, - // others - typeAnnotation: { type: "typeAnnotation" }, - typeParameters: { type: "typeParameters" }, - id: { type: "id" }, - }; - - function visitTypeAnnotation(node) { - // get property to check (params, id, etc...) - var visitorValues = visitorKeysMap[node.type]; - if (!visitorValues) { - return; - } - - // can have multiple properties - for (var i = 0; i < visitorValues.length; i++) { - var visitorValue = visitorValues[i]; - var propertyType = propertyTypes[visitorValue]; - var nodeProperty = node[visitorValue]; - // check if property or type is defined - if (propertyType == null || nodeProperty == null) { - continue; - } - if (propertyType.type === "loop") { - for (var j = 0; j < nodeProperty.length; j++) { - if (Array.isArray(propertyType.values)) { - for (var k = 0; k < propertyType.values.length; k++) { - var loopPropertyNode = nodeProperty[j][propertyType.values[k]]; - if (loopPropertyNode) { - checkIdentifierOrVisit.call(this, loopPropertyNode); - } - } - } else { - checkIdentifierOrVisit.call(this, nodeProperty[j]); - } - } - } else if (propertyType.type === "single") { - checkIdentifierOrVisit.call(this, nodeProperty); - } else if (propertyType.type === "typeAnnotation") { - visitTypeAnnotation.call(this, node.typeAnnotation); - } else if (propertyType.type === "typeParameters") { - for (var l = 0; l < node.typeParameters.params.length; l++) { - checkIdentifierOrVisit.call(this, node.typeParameters.params[l]); - } - } else if (propertyType.type === "id") { - if (node.id.type === "Identifier") { - checkIdentifierOrVisit.call(this, node.id); - } else { - visitTypeAnnotation.call(this, node.id); - } - } - } - } - - function checkIdentifierOrVisit(node) { - if (node.typeAnnotation) { - visitTypeAnnotation.call(this, node.typeAnnotation); - } else if (node.type === "Identifier") { - this.visit(node); - } else { - visitTypeAnnotation.call(this, node); - } - } - - function nestTypeParamScope(manager, node) { - var parentScope = manager.__currentScope; - var scope = new escope.Scope( - manager, - "type-parameters", - parentScope, - node, - false - ); - manager.__nestScope(scope); - for (var j = 0; j < node.typeParameters.params.length; j++) { - var name = node.typeParameters.params[j]; - scope.__define(name, new Definition("TypeParameter", name, name)); - if (name.typeAnnotation) { - checkIdentifierOrVisit.call(this, name); - } - } - scope.__define = function() { - return parentScope.__define.apply(parentScope, arguments); - }; - return scope; - } - - // visit decorators that are in: ClassDeclaration / ClassExpression - var visitClass = referencer.prototype.visitClass; - referencer.prototype.visitClass = function(node) { - visitDecorators.call(this, node); - var typeParamScope; - if (node.typeParameters) { - typeParamScope = nestTypeParamScope.call(this, this.scopeManager, node); - } - // visit flow type: ClassImplements - if (node.implements) { - for (var i = 0; i < node.implements.length; i++) { - checkIdentifierOrVisit.call(this, node.implements[i]); - } - } - if (node.superTypeParameters) { - for (var k = 0; k < node.superTypeParameters.params.length; k++) { - checkIdentifierOrVisit.call(this, node.superTypeParameters.params[k]); - } - } - visitClass.call(this, node); - if (typeParamScope) { - this.close(node); - } - }; - - // visit decorators that are in: Property / MethodDefinition - var visitProperty = referencer.prototype.visitProperty; - referencer.prototype.visitProperty = function(node) { - if (node.value && node.value.type === "TypeCastExpression") { - visitTypeAnnotation.call(this, node.value); - } - visitDecorators.call(this, node); - visitProperty.call(this, node); - }; - - function visitClassProperty(node) { - if (node.typeAnnotation) { - visitTypeAnnotation.call(this, node.typeAnnotation); - } - this.visitProperty(node); - } - - // visit ClassProperty as a Property. - referencer.prototype.ClassProperty = visitClassProperty; - - // visit ClassPrivateProperty as a Property. - referencer.prototype.ClassPrivateProperty = visitClassProperty; - - // visit OptionalMemberExpression as a MemberExpression. - referencer.prototype.OptionalMemberExpression = - referencer.prototype.MemberExpression; - - // visit flow type in FunctionDeclaration, FunctionExpression, ArrowFunctionExpression - var visitFunction = referencer.prototype.visitFunction; - referencer.prototype.visitFunction = function(node) { - var typeParamScope; - if (node.typeParameters) { - typeParamScope = nestTypeParamScope.call(this, this.scopeManager, node); - } - if (node.returnType) { - checkIdentifierOrVisit.call(this, node.returnType); - } - // only visit if function parameters have types - if (node.params) { - for (var i = 0; i < node.params.length; i++) { - var param = node.params[i]; - if (param.typeAnnotation) { - checkIdentifierOrVisit.call(this, param); - } else if (t.isAssignmentPattern(param)) { - if (param.left.typeAnnotation) { - checkIdentifierOrVisit.call(this, param.left); - } - } - } - } - // set ArrayPattern/ObjectPattern visitor keys back to their original. otherwise - // escope will traverse into them and include the identifiers within as declarations - estraverse.VisitorKeys.ObjectPattern = ["properties"]; - estraverse.VisitorKeys.ArrayPattern = ["elements"]; - visitFunction.call(this, node); - // set them back to normal... - estraverse.VisitorKeys.ObjectPattern = t.VISITOR_KEYS.ObjectPattern; - estraverse.VisitorKeys.ArrayPattern = t.VISITOR_KEYS.ArrayPattern; - if (typeParamScope) { - this.close(node); - } - }; - - // visit flow type in VariableDeclaration - var variableDeclaration = referencer.prototype.VariableDeclaration; - referencer.prototype.VariableDeclaration = function(node) { - if (node.declarations) { - for (var i = 0; i < node.declarations.length; i++) { - var id = node.declarations[i].id; - var typeAnnotation = id.typeAnnotation; - if (typeAnnotation) { - checkIdentifierOrVisit.call(this, typeAnnotation); - } - } - } - variableDeclaration.call(this, node); - }; - - function createScopeVariable(node, name) { - this.currentScope().variableScope.__define( - name, - new Definition("Variable", name, node, null, null, null) - ); - } - - referencer.prototype.InterfaceDeclaration = function(node) { - createScopeVariable.call(this, node, node.id); - var typeParamScope; - if (node.typeParameters) { - typeParamScope = nestTypeParamScope.call(this, this.scopeManager, node); - } - // TODO: Handle mixins - for (var i = 0; i < node.extends.length; i++) { - visitTypeAnnotation.call(this, node.extends[i]); - } - visitTypeAnnotation.call(this, node.body); - if (typeParamScope) { - this.close(node); - } - }; - - referencer.prototype.TypeAlias = function(node) { - createScopeVariable.call(this, node, node.id); - var typeParamScope; - if (node.typeParameters) { - typeParamScope = nestTypeParamScope.call(this, this.scopeManager, node); - } - if (node.right) { - visitTypeAnnotation.call(this, node.right); - } - if (typeParamScope) { - this.close(node); - } - }; - - referencer.prototype.DeclareModule = referencer.prototype.DeclareFunction = referencer.prototype.DeclareVariable = referencer.prototype.DeclareClass = function( - node - ) { - if (node.id) { - createScopeVariable.call(this, node, node.id); - } - - var typeParamScope; - if (node.typeParameters) { - typeParamScope = nestTypeParamScope.call(this, this.scopeManager, node); - } - if (typeParamScope) { - this.close(node); - } - }; - - referencer._babelEslintPatched = true; -} - -// To patch for each call. -var escope = null; -var escopeAnalyze = null; - -module.exports = function(parserOptions) { - // Patch `Referencer.prototype` once. - if (!escope) { - const modules = getModules(); - monkeypatch(modules); - - // Store to patch for each call. - escope = modules.escope; - escopeAnalyze = modules.escope.analyze; - } - - // Patch `escope.analyze` based on the current parserOptions. - escope.analyze = function(ast, opts) { - opts = opts || {}; - opts.ecmaVersion = parserOptions.ecmaVersion; - opts.sourceType = parserOptions.sourceType; - opts.nodejsScope = - ast.sourceType === "script" && - (parserOptions.ecmaFeatures && - parserOptions.ecmaFeatures.globalReturn) === true; - - return escopeAnalyze.call(this, ast, opts); - }; -}; diff --git a/package.json b/package.json index 2e5fbc20..f52170f5 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ }, "scripts": { "test": "npm run lint && npm run test-only", - "test-only": "mocha && mocha --require test/fixtures/preprocess-to-patch.js && mocha --require test/fixtures/use-eslint-old.js", + "test-only": "mocha && mocha --require test/fixtures/preprocess-to-patch.js", "lint": "eslint index.js babylon-to-espree test", "fix": "eslint index.js babylon-to-espree test --fix", "precommit": "lint-staged", @@ -41,7 +41,6 @@ "dedent": "^0.7.0", "eslint": "npm:eslint@4.19.1", "eslint-config-babel": "^7.0.1", - "eslint-old": "npm:eslint@4.13.1", "eslint-plugin-flowtype": "^2.30.3", "eslint-plugin-import": "^2.8.0", "eslint-plugin-prettier": "^2.1.2", diff --git a/test/fixtures/use-eslint-old.js b/test/fixtures/use-eslint-old.js deleted file mode 100644 index e26a39c8..00000000 --- a/test/fixtures/use-eslint-old.js +++ /dev/null @@ -1,12 +0,0 @@ -"use strict" - -var Module = require('module'); -var originalRequire = Module.prototype.require; - -// Override to eslint-old -Module.prototype.require = function () { - if (arguments[0] === "eslint") { - arguments[0] = "eslint-old"; - } - return originalRequire.apply(this, arguments); -}; diff --git a/test/integration.js b/test/integration.js index 8e93631a..09e4af9d 100644 --- a/test/integration.js +++ b/test/integration.js @@ -225,6 +225,7 @@ function strictSuite() { // Strip chalk colors, these are not relevant for the test const stripAnsi = str => str.replace( + // eslint-disable-next-line no-control-regex /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, "" ); diff --git a/yarn.lock b/yarn.lock index d6f8fae1..af0f7387 100644 --- a/yarn.lock +++ b/yarn.lock @@ -507,7 +507,7 @@ date-fns@^1.27.2: version "1.29.0" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.29.0.tgz#12e609cdcb935127311d04d33334e2960a2a54e6" -debug@3.1.0, debug@^3.0.1, debug@^3.1.0: +debug@3.1.0, debug@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: @@ -573,7 +573,7 @@ doctrine@1.5.0: esutils "^2.0.2" isarray "^1.0.0" -doctrine@^2.0.2, doctrine@^2.1.0: +doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" dependencies: @@ -617,48 +617,6 @@ eslint-module-utils@^2.1.1: debug "^2.6.8" pkg-dir "^1.0.0" -"eslint-old@npm:eslint@4.13.1": - version "4.13.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.13.1.tgz#0055e0014464c7eb7878caf549ef2941992b444f" - dependencies: - ajv "^5.3.0" - babel-code-frame "^6.22.0" - chalk "^2.1.0" - concat-stream "^1.6.0" - cross-spawn "^5.1.0" - debug "^3.0.1" - doctrine "^2.0.2" - eslint-scope "^3.7.1" - espree "^3.5.2" - esquery "^1.0.0" - estraverse "^4.2.0" - esutils "^2.0.2" - file-entry-cache "^2.0.0" - functional-red-black-tree "^1.0.1" - glob "^7.1.2" - globals "^11.0.1" - ignore "^3.3.3" - imurmurhash "^0.1.4" - inquirer "^3.0.6" - is-resolvable "^1.0.0" - js-yaml "^3.9.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.4" - minimatch "^3.0.2" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - optionator "^0.8.2" - path-is-inside "^1.0.2" - pluralize "^7.0.0" - progress "^2.0.0" - require-uncached "^1.0.3" - semver "^5.3.0" - strip-ansi "^4.0.0" - strip-json-comments "~2.0.1" - table "^4.0.1" - text-table "~0.2.0" - eslint-plugin-flowtype@^2.30.3: version "2.45.0" resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.45.0.tgz#20d8b15d1e1e71ea4e9498e8be3fc62c0752fcbf" @@ -771,7 +729,7 @@ esrecurse@^4.1.0: dependencies: estraverse "^4.1.0" -estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" @@ -2232,7 +2190,7 @@ symbol-observable@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" -table@4.0.2, table@^4.0.1: +table@4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" dependencies: