diff --git a/package.json b/package.json index 136aa956ee..22eba0ae83 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "xo" ], "dependencies": { + "@babel/types": "^7.14.5", "ci-info": "^3.2.0", "clean-regexp": "^1.0.0", "eslint-template-visitor": "^2.3.2", @@ -46,7 +47,6 @@ "pluralize": "^8.0.0", "read-pkg-up": "^7.0.1", "regexp-tree": "^0.1.23", - "reserved-words": "^0.1.2", "safe-regex": "^2.1.1", "semver": "^7.3.5" }, diff --git a/rules/catch-error-name.js b/rules/catch-error-name.js index a244144717..2a094ca612 100644 --- a/rules/catch-error-name.js +++ b/rules/catch-error-name.js @@ -33,8 +33,6 @@ const selector = matches([ ]); const create = context => { - const {ecmaVersion} = context.parserOptions; - const options = { name: 'error', ignore: [], @@ -79,7 +77,7 @@ const create = context => { variable.scope, ...variable.references.map(({from}) => from) ]; - const fixedName = avoidCapture(expectedName, scopes, ecmaVersion); + const fixedName = avoidCapture(expectedName, scopes); return { node, diff --git a/rules/consistent-destructuring.js b/rules/consistent-destructuring.js index 7a44d22695..3b743a17bd 100644 --- a/rules/consistent-destructuring.js +++ b/rules/consistent-destructuring.js @@ -52,7 +52,6 @@ const isChildInParentScope = (child, parent) => { }; const create = context => { - const {ecmaVersion} = context.parserOptions; const source = context.getSourceCode(); const declarations = new Map(); @@ -108,7 +107,7 @@ const create = context => { } // Destructured member collides with an existing identifier - if (avoidCapture(member, [memberScope], ecmaVersion) !== member) { + if (avoidCapture(member, [memberScope]) !== member) { return; } } diff --git a/rules/no-for-loop.js b/rules/no-for-loop.js index 133714d0af..277763007b 100644 --- a/rules/no-for-loop.js +++ b/rules/no-for-loop.js @@ -355,7 +355,7 @@ const create = context => { const index = indexIdentifierName; const element = elementIdentifierName || - avoidCapture(singular(arrayIdentifierName) || defaultElementName, getChildScopesRecursive(bodyScope), context.parserOptions.ecmaVersion); + avoidCapture(singular(arrayIdentifierName) || defaultElementName, getChildScopesRecursive(bodyScope)); const array = arrayIdentifierName; let declarationElement = element; diff --git a/rules/prefer-array-find.js b/rules/prefer-array-find.js index b4d1f24c9a..d2a17b36f4 100644 --- a/rules/prefer-array-find.js +++ b/rules/prefer-array-find.js @@ -299,7 +299,7 @@ const create = context => { const singularName = singular(node.id.name); if (singularName) { // Rename variable to be singularized now that it refers to a single item in the array instead of the entire array. - const singularizedName = avoidCapture(singularName, getChildScopesRecursive(scope), context.parserOptions.ecmaVersion); + const singularizedName = avoidCapture(singularName, getChildScopesRecursive(scope)); yield * renameVariable(variable, singularizedName, fixer); // Prevent possible variable conflicts diff --git a/rules/prefer-ternary.js b/rules/prefer-ternary.js index 7537abb11f..a8a3c7a94b 100644 --- a/rules/prefer-ternary.js +++ b/rules/prefer-ternary.js @@ -216,7 +216,7 @@ const create = context => { let generateNewVariables = false; if (type === 'ThrowStatement') { const scopes = getScopes(scope); - const errorName = avoidCapture('error', scopes, context.parserOptions.ecmaVersion, isSafeName); + const errorName = avoidCapture('error', scopes, isSafeName); for (const scope of scopes) { if (!scopeToNamesGeneratedByFixer.has(scope)) { diff --git a/rules/prevent-abbreviations.js b/rules/prevent-abbreviations.js index 4fab188410..40739df5ad 100644 --- a/rules/prevent-abbreviations.js +++ b/rules/prevent-abbreviations.js @@ -313,7 +313,6 @@ const isInternalImport = node => { }; const create = context => { - const {ecmaVersion} = context.parserOptions; const options = prepareOptions(context.options[0]); const filenameWithExtension = context.getPhysicalFilename(); @@ -416,7 +415,7 @@ const create = context => { variable.scope ]; variableReplacements.samples = variableReplacements.samples.map( - name => avoidCapture(name, scopes, ecmaVersion, isSafeName) + name => avoidCapture(name, scopes, isSafeName) ); const problem = { diff --git a/rules/utils/avoid-capture.js b/rules/utils/avoid-capture.js index 9df03e93bd..67e0d22247 100644 --- a/rules/utils/avoid-capture.js +++ b/rules/utils/avoid-capture.js @@ -1,34 +1,10 @@ 'use strict'; -const reservedWords = require('reserved-words'); +const {isValidES3Identifier} = require('@babel/types'); const resolveVariableName = require('./resolve-variable-name.js'); const indexifyName = (name, index) => name + '_'.repeat(index); - -const scopeHasArgumentsSpecial = scope => { - while (scope) { - /* istanbul ignore next: `someScopeHasVariableName` seems already handle this */ - if (scope.taints.get('arguments')) { - return true; - } - - scope = scope.upper; - } - - return false; -}; - const someScopeHasVariableName = (name, scopes) => scopes.some(scope => resolveVariableName(name, scope)); -const someScopeIsStrict = scopes => scopes.some(scope => scope.isStrict); - -const nameCollidesWithArgumentsSpecial = (name, scopes, isStrict) => { - if (name !== 'arguments') { - return false; - } - - return isStrict || scopes.some(scope => scopeHasArgumentsSpecial(scope)); -}; - /* Unresolved reference is probably from the global scope. We should avoid using that name. @@ -51,16 +27,10 @@ const isUnresolvedName = (name, scopes) => scopes.some(scope => isUnresolvedName(name, scope.childScopes) ); -const isSafeName = (name, scopes, ecmaVersion, isStrict) => { - ecmaVersion = Math.min(6, ecmaVersion); // 6 is the latest version understood by `reservedWords` - - return ( - !someScopeHasVariableName(name, scopes) && - !reservedWords.check(name, ecmaVersion, isStrict) && - !nameCollidesWithArgumentsSpecial(name, scopes, isStrict) && - !isUnresolvedName(name, scopes) - ); -}; +const isSafeName = (name, scopes) => + !someScopeHasVariableName(name, scopes) && + !isValidES3Identifier(name) && + !isUnresolvedName(name, scopes); const alwaysTrue = () => true; @@ -84,19 +54,13 @@ Useful when you want to rename a variable (or create a new variable) while being @param {string} name - The desired name for a new variable. @param {Scope[]} scopes - The list of scopes the new variable will be referenced in. -@param {number} ecmaVersion - The language version, get it from `context.parserOptions.ecmaVersion`. @param {isSafe} [isSafe] - Rule-specific name check function. @returns {string} - Either `name` as is, or a string like `${name}_` suffixed with underscores to make the name unique. */ -module.exports = (name, scopes, ecmaVersion, isSafe = alwaysTrue) => { - const isStrict = someScopeIsStrict(scopes); - +module.exports = (name, scopes, isSafe = alwaysTrue) => { let index = 0; - let indexifiedName = indexifyName(name, index); - while ( - !isSafeName(indexifiedName, scopes, ecmaVersion, isStrict) || - !isSafe(indexifiedName, scopes) - ) { + let indexifiedName = name; + while (!isSafeName(indexifiedName, scopes) || !isSafe(indexifiedName, scopes)) { index++; indexifiedName = indexifyName(name, index); }