mirror of
https://github.com/Sevichecc/Urara-Blog.git
synced 2025-05-05 02:59:31 +08:00
217 lines
7.9 KiB
Text
217 lines
7.9 KiB
Text
/**
|
|
* @fileoverview Rule to require newlines before `return` statement
|
|
* @author Kai Cataldo
|
|
* @deprecated in ESLint v4.0.0
|
|
*/
|
|
"use strict";
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Rule Definition
|
|
//------------------------------------------------------------------------------
|
|
|
|
/** @type {import('../shared/types').Rule} */
|
|
module.exports = {
|
|
meta: {
|
|
type: "layout",
|
|
|
|
docs: {
|
|
description: "Require an empty line before `return` statements",
|
|
recommended: false,
|
|
url: "https://eslint.org/docs/rules/newline-before-return"
|
|
},
|
|
|
|
fixable: "whitespace",
|
|
schema: [],
|
|
messages: {
|
|
expected: "Expected newline before return statement."
|
|
},
|
|
|
|
deprecated: true,
|
|
replacedBy: ["padding-line-between-statements"]
|
|
},
|
|
|
|
create(context) {
|
|
const sourceCode = context.getSourceCode();
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Helpers
|
|
//--------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Tests whether node is preceded by supplied tokens
|
|
* @param {ASTNode} node node to check
|
|
* @param {Array} testTokens array of tokens to test against
|
|
* @returns {boolean} Whether or not the node is preceded by one of the supplied tokens
|
|
* @private
|
|
*/
|
|
function isPrecededByTokens(node, testTokens) {
|
|
const tokenBefore = sourceCode.getTokenBefore(node);
|
|
|
|
return testTokens.includes(tokenBefore.value);
|
|
}
|
|
|
|
/**
|
|
* Checks whether node is the first node after statement or in block
|
|
* @param {ASTNode} node node to check
|
|
* @returns {boolean} Whether or not the node is the first node after statement or in block
|
|
* @private
|
|
*/
|
|
function isFirstNode(node) {
|
|
const parentType = node.parent.type;
|
|
|
|
if (node.parent.body) {
|
|
return Array.isArray(node.parent.body)
|
|
? node.parent.body[0] === node
|
|
: node.parent.body === node;
|
|
}
|
|
|
|
if (parentType === "IfStatement") {
|
|
return isPrecededByTokens(node, ["else", ")"]);
|
|
}
|
|
if (parentType === "DoWhileStatement") {
|
|
return isPrecededByTokens(node, ["do"]);
|
|
}
|
|
if (parentType === "SwitchCase") {
|
|
return isPrecededByTokens(node, [":"]);
|
|
}
|
|
return isPrecededByTokens(node, [")"]);
|
|
|
|
}
|
|
|
|
/**
|
|
* Returns the number of lines of comments that precede the node
|
|
* @param {ASTNode} node node to check for overlapping comments
|
|
* @param {number} lineNumTokenBefore line number of previous token, to check for overlapping comments
|
|
* @returns {number} Number of lines of comments that precede the node
|
|
* @private
|
|
*/
|
|
function calcCommentLines(node, lineNumTokenBefore) {
|
|
const comments = sourceCode.getCommentsBefore(node);
|
|
let numLinesComments = 0;
|
|
|
|
if (!comments.length) {
|
|
return numLinesComments;
|
|
}
|
|
|
|
comments.forEach(comment => {
|
|
numLinesComments++;
|
|
|
|
if (comment.type === "Block") {
|
|
numLinesComments += comment.loc.end.line - comment.loc.start.line;
|
|
}
|
|
|
|
// avoid counting lines with inline comments twice
|
|
if (comment.loc.start.line === lineNumTokenBefore) {
|
|
numLinesComments--;
|
|
}
|
|
|
|
if (comment.loc.end.line === node.loc.start.line) {
|
|
numLinesComments--;
|
|
}
|
|
});
|
|
|
|
return numLinesComments;
|
|
}
|
|
|
|
/**
|
|
* Returns the line number of the token before the node that is passed in as an argument
|
|
* @param {ASTNode} node The node to use as the start of the calculation
|
|
* @returns {number} Line number of the token before `node`
|
|
* @private
|
|
*/
|
|
function getLineNumberOfTokenBefore(node) {
|
|
const tokenBefore = sourceCode.getTokenBefore(node);
|
|
let lineNumTokenBefore;
|
|
|
|
/**
|
|
* Global return (at the beginning of a script) is a special case.
|
|
* If there is no token before `return`, then we expect no line
|
|
* break before the return. Comments are allowed to occupy lines
|
|
* before the global return, just no blank lines.
|
|
* Setting lineNumTokenBefore to zero in that case results in the
|
|
* desired behavior.
|
|
*/
|
|
if (tokenBefore) {
|
|
lineNumTokenBefore = tokenBefore.loc.end.line;
|
|
} else {
|
|
lineNumTokenBefore = 0; // global return at beginning of script
|
|
}
|
|
|
|
return lineNumTokenBefore;
|
|
}
|
|
|
|
/**
|
|
* Checks whether node is preceded by a newline
|
|
* @param {ASTNode} node node to check
|
|
* @returns {boolean} Whether or not the node is preceded by a newline
|
|
* @private
|
|
*/
|
|
function hasNewlineBefore(node) {
|
|
const lineNumNode = node.loc.start.line;
|
|
const lineNumTokenBefore = getLineNumberOfTokenBefore(node);
|
|
const commentLines = calcCommentLines(node, lineNumTokenBefore);
|
|
|
|
return (lineNumNode - lineNumTokenBefore - commentLines) > 1;
|
|
}
|
|
|
|
/**
|
|
* Checks whether it is safe to apply a fix to a given return statement.
|
|
*
|
|
* The fix is not considered safe if the given return statement has leading comments,
|
|
* as we cannot safely determine if the newline should be added before or after the comments.
|
|
* For more information, see: https://github.com/eslint/eslint/issues/5958#issuecomment-222767211
|
|
* @param {ASTNode} node The return statement node to check.
|
|
* @returns {boolean} `true` if it can fix the node.
|
|
* @private
|
|
*/
|
|
function canFix(node) {
|
|
const leadingComments = sourceCode.getCommentsBefore(node);
|
|
const lastLeadingComment = leadingComments[leadingComments.length - 1];
|
|
const tokenBefore = sourceCode.getTokenBefore(node);
|
|
|
|
if (leadingComments.length === 0) {
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* if the last leading comment ends in the same line as the previous token and
|
|
* does not share a line with the `return` node, we can consider it safe to fix.
|
|
* Example:
|
|
* function a() {
|
|
* var b; //comment
|
|
* return;
|
|
* }
|
|
*/
|
|
if (lastLeadingComment.loc.end.line === tokenBefore.loc.end.line &&
|
|
lastLeadingComment.loc.end.line !== node.loc.start.line) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Public
|
|
//--------------------------------------------------------------------------
|
|
|
|
return {
|
|
ReturnStatement(node) {
|
|
if (!isFirstNode(node) && !hasNewlineBefore(node)) {
|
|
context.report({
|
|
node,
|
|
messageId: "expected",
|
|
fix(fixer) {
|
|
if (canFix(node)) {
|
|
const tokenBefore = sourceCode.getTokenBefore(node);
|
|
const newlines = node.loc.start.line === tokenBefore.loc.end.line ? "\n\n" : "\n";
|
|
|
|
return fixer.insertTextBefore(node, newlines);
|
|
}
|
|
return null;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
};
|
|
}
|
|
};
|