Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Move getDeclaredVariables and getAncestors to SourceCode #17059

Merged
merged 12 commits into from Apr 7, 2023
3 changes: 2 additions & 1 deletion docs/src/extend/code-path-analysis.md
Expand Up @@ -259,7 +259,8 @@ Please use a map of information instead.
```js
function hasCb(node, context) {
if (node.type.indexOf("Function") !== -1) {
return context.getDeclaredVariables(node).some(function(v) {
const sourceCode = context.getSourceCode();
return sourceCode.getDeclaredVariables(node).some(function(v) {
return v.type === "Parameter" && v.name === "cb";
});
}
Expand Down
6 changes: 3 additions & 3 deletions docs/src/extend/custom-rules.md
Expand Up @@ -117,9 +117,9 @@ The `context` object contains additional functionality that is helpful for rules

Additionally, the `context` object has the following methods:

* `getAncestors()` - returns an array of the ancestors of the currently-traversed node, starting at the root of the AST and continuing through the direct parent of the current node. This array does not include the currently-traversed node itself.
* `getAncestors()` - (**Deprecated:** Use `SourceCode#getAncestors(node)` instead.) returns an array of the ancestors of the currently-traversed node, starting at the root of the AST and continuing through the direct parent of the current node. This array does not include the currently-traversed node itself.
* `getCwd()` - returns the `cwd` passed to [Linter](../integrate/nodejs-api#linter). It is a path to a directory that should be considered as the current working directory.
* `getDeclaredVariables(node)` - returns a list of [variables](./scope-manager-interface#variable-interface) declared by the given node. This information can be used to track references to variables.
* `getDeclaredVariables(node)` - (**Deprecated:** Use `SourceCode#getDeclaredVariables(node)` instead.) returns a list of [variables](./scope-manager-interface#variable-interface) declared by the given node. This information can be used to track references to variables.
* If the node is a `VariableDeclaration`, all variables declared in the declaration are returned.
* If the node is a `VariableDeclarator`, all variables declared in the declarator are returned.
* If the node is a `FunctionDeclaration` or `FunctionExpression`, the variable for the function name is returned, in addition to variables for the function parameters.
Expand All @@ -131,7 +131,7 @@ Additionally, the `context` object has the following methods:
* Otherwise, if the node does not declare any variables, an empty array is returned.
* `getFilename()` - returns the filename associated with the source.
* `getPhysicalFilename()` - when linting a file, it returns the full path of the file on disk without any code block information. When linting text, it returns the value passed to `—stdin-filename` or `<text>` if not specified.
* `getScope()` - (**Deprecated: Use `SourceCode.getScope(node)` instead.**) returns the [scope](./scope-manager-interface#scope-interface) of the currently-traversed node. This information can be used to track references to variables.
* `getScope()` - (**Deprecated:** Use `SourceCode#getScope(node)` instead.) returns the [scope](./scope-manager-interface#scope-interface) of the currently-traversed node. This information can be used to track references to variables.
* `getSourceCode()` - returns a [`SourceCode`](#contextgetsourcecode) object that you can use to work with the source that was passed to ESLint.
* `markVariableAsUsed(name)` - marks a variable with the given name in the current scope as used. This affects the [no-unused-vars](../rules/no-unused-vars) rule. Returns `true` if a variable with the given name was found and marked as used, otherwise `false`.
* `report(descriptor)` - reports a problem in the code (see the [dedicated section](#contextreport)).
Expand Down
20 changes: 2 additions & 18 deletions lib/linter/linter.js
Expand Up @@ -905,22 +905,6 @@ function createRuleListeners(rule, ruleContext) {
}
}

/**
* Gets all the ancestors of a given node
* @param {ASTNode} node The node
* @returns {ASTNode[]} All the ancestor nodes in the AST, not including the provided node, starting
* from the root node and going inwards to the parent node.
*/
function getAncestors(node) {
const ancestorsStartingAtParent = [];

for (let ancestor = node.parent; ancestor; ancestor = ancestor.parent) {
ancestorsStartingAtParent.push(ancestor);
}

return ancestorsStartingAtParent.reverse();
}

// methods that exist on SourceCode object
const DEPRECATED_SOURCECODE_PASSTHROUGHS = {
getSource: "getText",
Expand Down Expand Up @@ -996,8 +980,8 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserName, languageO
Object.assign(
Object.create(BASE_TRAVERSAL_CONTEXT),
{
getAncestors: () => getAncestors(currentNode),
getDeclaredVariables: sourceCode.scopeManager.getDeclaredVariables.bind(sourceCode.scopeManager),
getAncestors: () => sourceCode.getAncestors(currentNode),
getDeclaredVariables: node => sourceCode.getDeclaredVariables(node),
getCwd: () => cwd,
getFilename: () => filename,
getPhysicalFilename: () => physicalFilename || filename,
Expand Down
3 changes: 2 additions & 1 deletion lib/rules/block-scoped-var.js
Expand Up @@ -28,6 +28,7 @@ module.exports = {

create(context) {
let stack = [];
const sourceCode = context.getSourceCode();

/**
* Makes a block scope.
Expand Down Expand Up @@ -83,7 +84,7 @@ module.exports = {
}

// Gets declared variables, and checks its references.
const variables = context.getDeclaredVariables(node);
const variables = sourceCode.getDeclaredVariables(node);

for (let i = 0; i < variables.length; ++i) {

Expand Down
4 changes: 2 additions & 2 deletions lib/rules/camelcase.js
Expand Up @@ -296,7 +296,7 @@ module.exports = {
"ClassExpression",
"CatchClause"
]](node) {
for (const variable of context.getDeclaredVariables(node)) {
for (const variable of sourceCode.getDeclaredVariables(node)) {
if (isGoodName(variable.name)) {
continue;
}
Expand Down Expand Up @@ -346,7 +346,7 @@ module.exports = {

// Report camelcase in import --------------------------------------
ImportDeclaration(node) {
for (const variable of context.getDeclaredVariables(node)) {
for (const variable of sourceCode.getDeclaredVariables(node)) {
if (isGoodName(variable.name)) {
continue;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/func-names.js
Expand Up @@ -159,7 +159,7 @@ module.exports = {
function handleFunction(node) {

// Skip recursive functions.
const nameVar = context.getDeclaredVariables(node)[0];
const nameVar = sourceCode.getDeclaredVariables(node)[0];

if (isFunctionName(nameVar) && nameVar.references.length > 0) {
return;
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/global-require.js
Expand Up @@ -78,7 +78,7 @@ module.exports = {
const currentScope = sourceCode.getScope(node);

if (node.callee.name === "require" && !isShadowed(currentScope, node.callee)) {
const isGoodRequire = context.getAncestors().every(parent => ACCEPTABLE_PARENTS.has(parent.type));
const isGoodRequire = sourceCode.getAncestors(node).every(parent => ACCEPTABLE_PARENTS.has(parent.type));

if (!isGoodRequire) {
context.report({ node, messageId: "unexpected" });
Expand Down
4 changes: 3 additions & 1 deletion lib/rules/no-class-assign.js
Expand Up @@ -31,6 +31,8 @@ module.exports = {

create(context) {

const sourceCode = context.getSourceCode();

/**
* Finds and reports references that are non initializer and writable.
* @param {Variable} variable A variable to check.
Expand All @@ -49,7 +51,7 @@ module.exports = {
* @returns {void}
*/
function checkForClass(node) {
context.getDeclaredVariables(node).forEach(checkVariable);
sourceCode.getDeclaredVariables(node).forEach(checkVariable);
}

return {
Expand Down
4 changes: 3 additions & 1 deletion lib/rules/no-const-assign.js
Expand Up @@ -31,6 +31,8 @@ module.exports = {

create(context) {

const sourceCode = context.getSourceCode();

/**
* Finds and reports references that are non initializer and writable.
* @param {Variable} variable A variable to check.
Expand All @@ -45,7 +47,7 @@ module.exports = {
return {
VariableDeclaration(node) {
if (node.kind === "const") {
context.getDeclaredVariables(node).forEach(checkVariable);
sourceCode.getDeclaredVariables(node).forEach(checkVariable);
}
}
};
Expand Down
4 changes: 3 additions & 1 deletion lib/rules/no-dupe-args.js
Expand Up @@ -29,6 +29,8 @@ module.exports = {

create(context) {

const sourceCode = context.getSourceCode();

//--------------------------------------------------------------------------
// Helpers
//--------------------------------------------------------------------------
Expand All @@ -49,7 +51,7 @@ module.exports = {
* @private
*/
function checkParams(node) {
const variables = context.getDeclaredVariables(node);
const variables = sourceCode.getDeclaredVariables(node);

for (let i = 0; i < variables.length; ++i) {
const variable = variables[i];
Expand Down
4 changes: 3 additions & 1 deletion lib/rules/no-ex-assign.js
Expand Up @@ -31,6 +31,8 @@ module.exports = {

create(context) {

const sourceCode = context.getSourceCode();

/**
* Finds and reports references that are non initializer and writable.
* @param {Variable} variable A variable to check.
Expand All @@ -44,7 +46,7 @@ module.exports = {

return {
CatchClause(node) {
context.getDeclaredVariables(node).forEach(checkVariable);
sourceCode.getDeclaredVariables(node).forEach(checkVariable);
}
};

Expand Down
4 changes: 3 additions & 1 deletion lib/rules/no-func-assign.js
Expand Up @@ -31,6 +31,8 @@ module.exports = {

create(context) {

const sourceCode = context.getSourceCode();

/**
* Reports a reference if is non initializer and writable.
* @param {References} references Collection of reference to check.
Expand Down Expand Up @@ -65,7 +67,7 @@ module.exports = {
* @returns {void}
*/
function checkForFunction(node) {
context.getDeclaredVariables(node).forEach(checkVariable);
sourceCode.getDeclaredVariables(node).forEach(checkVariable);
}

return {
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/no-import-assign.js
Expand Up @@ -200,7 +200,7 @@ module.exports = {
ImportDeclaration(node) {
const scope = sourceCode.getScope(node);

for (const variable of context.getDeclaredVariables(node)) {
for (const variable of sourceCode.getDeclaredVariables(node)) {
const shouldCheckMembers = variable.defs.some(
d => d.node.type === "ImportNamespaceSpecifier"
);
Expand Down
9 changes: 5 additions & 4 deletions lib/rules/no-lone-blocks.js
Expand Up @@ -68,14 +68,15 @@ module.exports = {
/**
* Checks the enclosing block of the current node for block-level bindings,
* and "marks it" as valid if any.
* @param {ASTNode} node The current node to check.
* @returns {void}
*/
function markLoneBlock() {
function markLoneBlock(node) {
if (loneBlocks.length === 0) {
return;
}

const block = context.getAncestors().pop();
const block = sourceCode.getAncestors(node).pop();

if (loneBlocks[loneBlocks.length - 1] === block) {
loneBlocks.pop();
Expand Down Expand Up @@ -117,13 +118,13 @@ module.exports = {

ruleDef.VariableDeclaration = function(node) {
if (node.kind === "let" || node.kind === "const") {
markLoneBlock();
markLoneBlock(node);
}
};

ruleDef.FunctionDeclaration = function(node) {
if (sourceCode.getScope(node).isStrict) {
markLoneBlock();
markLoneBlock(node);
}
};

Expand Down
2 changes: 1 addition & 1 deletion lib/rules/no-lonely-if.js
Expand Up @@ -32,7 +32,7 @@ module.exports = {

return {
IfStatement(node) {
const ancestors = context.getAncestors(),
const ancestors = sourceCode.getAncestors(node),
parent = ancestors.pop(),
grandparent = ancestors.pop();

Expand Down
3 changes: 2 additions & 1 deletion lib/rules/no-param-reassign.js
Expand Up @@ -70,6 +70,7 @@ module.exports = {
const props = context.options[0] && context.options[0].props;
const ignoredPropertyAssignmentsFor = context.options[0] && context.options[0].ignorePropertyModificationsFor || [];
const ignoredPropertyAssignmentsForRegex = context.options[0] && context.options[0].ignorePropertyModificationsForRegex || [];
const sourceCode = context.getSourceCode();

/**
* Checks whether or not the reference modifies properties of its variable.
Expand Down Expand Up @@ -214,7 +215,7 @@ module.exports = {
* @returns {void}
*/
function checkForFunction(node) {
context.getDeclaredVariables(node).forEach(checkVariable);
sourceCode.getDeclaredVariables(node).forEach(checkVariable);
}

return {
Expand Down
3 changes: 2 additions & 1 deletion lib/rules/no-restricted-exports.js
Expand Up @@ -99,6 +99,7 @@ module.exports = {

const restrictedNames = new Set(context.options[0] && context.options[0].restrictedNamedExports);
const restrictDefaultExports = context.options[0] && context.options[0].restrictDefaultExports;
const sourceCode = context.getSourceCode();

/**
* Checks and reports given exported name.
Expand Down Expand Up @@ -176,7 +177,7 @@ module.exports = {
if (declaration.type === "FunctionDeclaration" || declaration.type === "ClassDeclaration") {
checkExportedName(declaration.id);
} else if (declaration.type === "VariableDeclaration") {
context.getDeclaredVariables(declaration)
sourceCode.getDeclaredVariables(declaration)
.map(v => v.defs.find(d => d.parent === declaration))
.map(d => d.name) // Identifier nodes
.forEach(checkExportedName);
Expand Down
3 changes: 2 additions & 1 deletion lib/rules/no-shadow-restricted-names.js
Expand Up @@ -43,10 +43,11 @@ module.exports = {


const RESTRICTED = new Set(["undefined", "NaN", "Infinity", "arguments", "eval"]);
const sourceCode = context.getSourceCode();

return {
"VariableDeclaration, :function, CatchClause"(node) {
for (const variable of context.getDeclaredVariables(node)) {
for (const variable of sourceCode.getDeclaredVariables(node)) {
if (variable.defs.length > 0 && RESTRICTED.has(variable.name) && !safelyShadowsUndefined(variable)) {
context.report({
node: variable.defs[0].name,
Expand Down
3 changes: 2 additions & 1 deletion lib/rules/no-underscore-dangle.js
Expand Up @@ -84,6 +84,7 @@ module.exports = {
const allowFunctionParams = typeof options.allowFunctionParams !== "undefined" ? options.allowFunctionParams : true;
const allowInArrayDestructuring = typeof options.allowInArrayDestructuring !== "undefined" ? options.allowInArrayDestructuring : true;
const allowInObjectDestructuring = typeof options.allowInObjectDestructuring !== "undefined" ? options.allowInObjectDestructuring : true;
const sourceCode = context.getSourceCode();

//-------------------------------------------------------------------------
// Helpers
Expand Down Expand Up @@ -213,7 +214,7 @@ module.exports = {
* @private
*/
function checkForDanglingUnderscoreInVariableExpression(node) {
context.getDeclaredVariables(node).forEach(variable => {
sourceCode.getDeclaredVariables(node).forEach(variable => {
const definition = variable.defs.find(def => def.node === node);
const identifierNode = definition.name;
const identifier = identifierNode.name;
Expand Down
5 changes: 3 additions & 2 deletions lib/rules/no-unused-expressions.js
Expand Up @@ -70,7 +70,8 @@ module.exports = {
allowShortCircuit = config.allowShortCircuit || false,
allowTernary = config.allowTernary || false,
allowTaggedTemplates = config.allowTaggedTemplates || false,
enforceForJSX = config.enforceForJSX || false;
enforceForJSX = config.enforceForJSX || false,
sourceCode = context.getSourceCode();

/**
* Has AST suggesting a directive.
Expand Down Expand Up @@ -180,7 +181,7 @@ module.exports = {

return {
ExpressionStatement(node) {
if (Checker.isDisallowed(node.expression) && !isDirective(node, context.getAncestors())) {
if (Checker.isDisallowed(node.expression) && !isDirective(node, sourceCode.getAncestors(node))) {
context.report({ node, messageId: "unusedExpression" });
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/no-unused-vars.js
Expand Up @@ -555,7 +555,7 @@ module.exports = {
*/
function isAfterLastUsedArg(variable) {
const def = variable.defs[0];
const params = context.getDeclaredVariables(def.node);
const params = sourceCode.getDeclaredVariables(def.node);
const posteriorParams = params.slice(params.indexOf(variable) + 1);

// If any used parameters occur after this parameter, do not report.
Expand Down
4 changes: 2 additions & 2 deletions lib/rules/no-var.js
Expand Up @@ -210,7 +210,7 @@ module.exports = {
if (!declarator.init) {
return false;
}
const variables = context.getDeclaredVariables(declarator);
const variables = sourceCode.getDeclaredVariables(declarator);

return variables.some(hasReferenceInTDZ(declarator.init));
}
Expand Down Expand Up @@ -268,7 +268,7 @@ module.exports = {
* @returns {boolean} `true` if it can fix the node.
*/
function canFix(node) {
const variables = context.getDeclaredVariables(node);
const variables = sourceCode.getDeclaredVariables(node);
const scopeNode = getScopeNode(node);

if (node.parent.type === "SwitchCase" ||
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/prefer-arrow-callback.js
Expand Up @@ -263,7 +263,7 @@ module.exports = {
}

// Skip recursive functions.
const nameVar = context.getDeclaredVariables(node)[0];
const nameVar = sourceCode.getDeclaredVariables(node)[0];

if (isFunctionName(nameVar) && nameVar.references.length > 0) {
return;
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/prefer-const.js
Expand Up @@ -493,7 +493,7 @@ module.exports = {

VariableDeclaration(node) {
if (node.kind === "let" && !isInitOfForStatement(node)) {
variables.push(...context.getDeclaredVariables(node));
variables.push(...sourceCode.getDeclaredVariables(node));
}
}
};
Expand Down