Permalink
Cannot retrieve contributors at this time
143 lines (120 sloc)
4.55 KB
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
codeql-action/node_modules/eslint/lib/rules/no-unused-labels.js
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @fileoverview Rule to disallow unused labels. | |
* @author Toru Nagashima | |
*/ | |
"use strict"; | |
//------------------------------------------------------------------------------ | |
// Requirements | |
//------------------------------------------------------------------------------ | |
const astUtils = require("./utils/ast-utils"); | |
//------------------------------------------------------------------------------ | |
// Rule Definition | |
//------------------------------------------------------------------------------ | |
/** @type {import('../shared/types').Rule} */ | |
module.exports = { | |
meta: { | |
type: "suggestion", | |
docs: { | |
description: "Disallow unused labels", | |
recommended: true, | |
url: "https://eslint.org/docs/latest/rules/no-unused-labels" | |
}, | |
schema: [], | |
fixable: "code", | |
messages: { | |
unused: "'{{name}}:' is defined but never used." | |
} | |
}, | |
create(context) { | |
const sourceCode = context.sourceCode; | |
let scopeInfo = null; | |
/** | |
* Adds a scope info to the stack. | |
* @param {ASTNode} node A node to add. This is a LabeledStatement. | |
* @returns {void} | |
*/ | |
function enterLabeledScope(node) { | |
scopeInfo = { | |
label: node.label.name, | |
used: false, | |
upper: scopeInfo | |
}; | |
} | |
/** | |
* Checks if a `LabeledStatement` node is fixable. | |
* For a node to be fixable, there must be no comments between the label and the body. | |
* Furthermore, is must be possible to remove the label without turning the body statement into a | |
* directive after other fixes are applied. | |
* @param {ASTNode} node The node to evaluate. | |
* @returns {boolean} Whether or not the node is fixable. | |
*/ | |
function isFixable(node) { | |
/* | |
* Only perform a fix if there are no comments between the label and the body. This will be the case | |
* when there is exactly one token/comment (the ":") between the label and the body. | |
*/ | |
if (sourceCode.getTokenAfter(node.label, { includeComments: true }) !== | |
sourceCode.getTokenBefore(node.body, { includeComments: true })) { | |
return false; | |
} | |
// Looking for the node's deepest ancestor which is not a `LabeledStatement`. | |
let ancestor = node.parent; | |
while (ancestor.type === "LabeledStatement") { | |
ancestor = ancestor.parent; | |
} | |
if (ancestor.type === "Program" || | |
(ancestor.type === "BlockStatement" && astUtils.isFunction(ancestor.parent))) { | |
const { body } = node; | |
if (body.type === "ExpressionStatement" && | |
((body.expression.type === "Literal" && typeof body.expression.value === "string") || | |
astUtils.isStaticTemplateLiteral(body.expression))) { | |
return false; // potential directive | |
} | |
} | |
return true; | |
} | |
/** | |
* Removes the top of the stack. | |
* At the same time, this reports the label if it's never used. | |
* @param {ASTNode} node A node to report. This is a LabeledStatement. | |
* @returns {void} | |
*/ | |
function exitLabeledScope(node) { | |
if (!scopeInfo.used) { | |
context.report({ | |
node: node.label, | |
messageId: "unused", | |
data: node.label, | |
fix: isFixable(node) ? fixer => fixer.removeRange([node.range[0], node.body.range[0]]) : null | |
}); | |
} | |
scopeInfo = scopeInfo.upper; | |
} | |
/** | |
* Marks the label of a given node as used. | |
* @param {ASTNode} node A node to mark. This is a BreakStatement or | |
* ContinueStatement. | |
* @returns {void} | |
*/ | |
function markAsUsed(node) { | |
if (!node.label) { | |
return; | |
} | |
const label = node.label.name; | |
let info = scopeInfo; | |
while (info) { | |
if (info.label === label) { | |
info.used = true; | |
break; | |
} | |
info = info.upper; | |
} | |
} | |
return { | |
LabeledStatement: enterLabeledScope, | |
"LabeledStatement:exit": exitLabeledScope, | |
BreakStatement: markAsUsed, | |
ContinueStatement: markAsUsed | |
}; | |
} | |
}; |