Skip to content

Commit

Permalink
Simplify avoidCapture function
Browse files Browse the repository at this point in the history
  • Loading branch information
fisker committed Jul 3, 2021
1 parent 100e906 commit c42b8ac
Show file tree
Hide file tree
Showing 8 changed files with 15 additions and 55 deletions.
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -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",
Expand All @@ -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"
},
Expand Down
4 changes: 1 addition & 3 deletions rules/catch-error-name.js
Expand Up @@ -33,8 +33,6 @@ const selector = matches([
]);

const create = context => {
const {ecmaVersion} = context.parserOptions;

const options = {
name: 'error',
ignore: [],
Expand Down Expand Up @@ -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,
Expand Down
3 changes: 1 addition & 2 deletions rules/consistent-destructuring.js
Expand Up @@ -52,7 +52,6 @@ const isChildInParentScope = (child, parent) => {
};

const create = context => {
const {ecmaVersion} = context.parserOptions;
const source = context.getSourceCode();
const declarations = new Map();

Expand Down Expand Up @@ -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;
}
}
Expand Down
2 changes: 1 addition & 1 deletion rules/no-for-loop.js
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion rules/prefer-array-find.js
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion rules/prefer-ternary.js
Expand Up @@ -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)) {
Expand Down
3 changes: 1 addition & 2 deletions rules/prevent-abbreviations.js
Expand Up @@ -313,7 +313,6 @@ const isInternalImport = node => {
};

const create = context => {
const {ecmaVersion} = context.parserOptions;
const options = prepareOptions(context.options[0]);
const filenameWithExtension = context.getPhysicalFilename();

Expand Down Expand Up @@ -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 = {
Expand Down
52 changes: 8 additions & 44 deletions 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.
Expand All @@ -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;

Expand All @@ -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);
}
Expand Down

0 comments on commit c42b8ac

Please sign in to comment.