You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
196 lines
7.3 KiB
196 lines
7.3 KiB
/** |
|
* @fileoverview Specify the maximum number of statements allowed per line. |
|
* @author Kenneth Williams |
|
*/ |
|
"use strict"; |
|
|
|
//------------------------------------------------------------------------------ |
|
// Requirements |
|
//------------------------------------------------------------------------------ |
|
|
|
const astUtils = require("./utils/ast-utils"); |
|
|
|
//------------------------------------------------------------------------------ |
|
// Rule Definition |
|
//------------------------------------------------------------------------------ |
|
|
|
/** @type {import('../shared/types').Rule} */ |
|
module.exports = { |
|
meta: { |
|
type: "layout", |
|
|
|
docs: { |
|
description: "Enforce a maximum number of statements allowed per line", |
|
recommended: false, |
|
url: "https://eslint.org/docs/rules/max-statements-per-line" |
|
}, |
|
|
|
schema: [ |
|
{ |
|
type: "object", |
|
properties: { |
|
max: { |
|
type: "integer", |
|
minimum: 1, |
|
default: 1 |
|
} |
|
}, |
|
additionalProperties: false |
|
} |
|
], |
|
messages: { |
|
exceed: "This line has {{numberOfStatementsOnThisLine}} {{statements}}. Maximum allowed is {{maxStatementsPerLine}}." |
|
} |
|
}, |
|
|
|
create(context) { |
|
|
|
const sourceCode = context.getSourceCode(), |
|
options = context.options[0] || {}, |
|
maxStatementsPerLine = typeof options.max !== "undefined" ? options.max : 1; |
|
|
|
let lastStatementLine = 0, |
|
numberOfStatementsOnThisLine = 0, |
|
firstExtraStatement; |
|
|
|
//-------------------------------------------------------------------------- |
|
// Helpers |
|
//-------------------------------------------------------------------------- |
|
|
|
const SINGLE_CHILD_ALLOWED = /^(?:(?:DoWhile|For|ForIn|ForOf|If|Labeled|While)Statement|Export(?:Default|Named)Declaration)$/u; |
|
|
|
/** |
|
* Reports with the first extra statement, and clears it. |
|
* @returns {void} |
|
*/ |
|
function reportFirstExtraStatementAndClear() { |
|
if (firstExtraStatement) { |
|
context.report({ |
|
node: firstExtraStatement, |
|
messageId: "exceed", |
|
data: { |
|
numberOfStatementsOnThisLine, |
|
maxStatementsPerLine, |
|
statements: numberOfStatementsOnThisLine === 1 ? "statement" : "statements" |
|
} |
|
}); |
|
} |
|
firstExtraStatement = null; |
|
} |
|
|
|
/** |
|
* Gets the actual last token of a given node. |
|
* @param {ASTNode} node A node to get. This is a node except EmptyStatement. |
|
* @returns {Token} The actual last token. |
|
*/ |
|
function getActualLastToken(node) { |
|
return sourceCode.getLastToken(node, astUtils.isNotSemicolonToken); |
|
} |
|
|
|
/** |
|
* Addresses a given node. |
|
* It updates the state of this rule, then reports the node if the node violated this rule. |
|
* @param {ASTNode} node A node to check. |
|
* @returns {void} |
|
*/ |
|
function enterStatement(node) { |
|
const line = node.loc.start.line; |
|
|
|
/* |
|
* Skip to allow non-block statements if this is direct child of control statements. |
|
* `if (a) foo();` is counted as 1. |
|
* But `if (a) foo(); else foo();` should be counted as 2. |
|
*/ |
|
if (SINGLE_CHILD_ALLOWED.test(node.parent.type) && |
|
node.parent.alternate !== node |
|
) { |
|
return; |
|
} |
|
|
|
// Update state. |
|
if (line === lastStatementLine) { |
|
numberOfStatementsOnThisLine += 1; |
|
} else { |
|
reportFirstExtraStatementAndClear(); |
|
numberOfStatementsOnThisLine = 1; |
|
lastStatementLine = line; |
|
} |
|
|
|
// Reports if the node violated this rule. |
|
if (numberOfStatementsOnThisLine === maxStatementsPerLine + 1) { |
|
firstExtraStatement = firstExtraStatement || node; |
|
} |
|
} |
|
|
|
/** |
|
* Updates the state of this rule with the end line of leaving node to check with the next statement. |
|
* @param {ASTNode} node A node to check. |
|
* @returns {void} |
|
*/ |
|
function leaveStatement(node) { |
|
const line = getActualLastToken(node).loc.end.line; |
|
|
|
// Update state. |
|
if (line !== lastStatementLine) { |
|
reportFirstExtraStatementAndClear(); |
|
numberOfStatementsOnThisLine = 1; |
|
lastStatementLine = line; |
|
} |
|
} |
|
|
|
//-------------------------------------------------------------------------- |
|
// Public API |
|
//-------------------------------------------------------------------------- |
|
|
|
return { |
|
BreakStatement: enterStatement, |
|
ClassDeclaration: enterStatement, |
|
ContinueStatement: enterStatement, |
|
DebuggerStatement: enterStatement, |
|
DoWhileStatement: enterStatement, |
|
ExpressionStatement: enterStatement, |
|
ForInStatement: enterStatement, |
|
ForOfStatement: enterStatement, |
|
ForStatement: enterStatement, |
|
FunctionDeclaration: enterStatement, |
|
IfStatement: enterStatement, |
|
ImportDeclaration: enterStatement, |
|
LabeledStatement: enterStatement, |
|
ReturnStatement: enterStatement, |
|
SwitchStatement: enterStatement, |
|
ThrowStatement: enterStatement, |
|
TryStatement: enterStatement, |
|
VariableDeclaration: enterStatement, |
|
WhileStatement: enterStatement, |
|
WithStatement: enterStatement, |
|
ExportNamedDeclaration: enterStatement, |
|
ExportDefaultDeclaration: enterStatement, |
|
ExportAllDeclaration: enterStatement, |
|
|
|
"BreakStatement:exit": leaveStatement, |
|
"ClassDeclaration:exit": leaveStatement, |
|
"ContinueStatement:exit": leaveStatement, |
|
"DebuggerStatement:exit": leaveStatement, |
|
"DoWhileStatement:exit": leaveStatement, |
|
"ExpressionStatement:exit": leaveStatement, |
|
"ForInStatement:exit": leaveStatement, |
|
"ForOfStatement:exit": leaveStatement, |
|
"ForStatement:exit": leaveStatement, |
|
"FunctionDeclaration:exit": leaveStatement, |
|
"IfStatement:exit": leaveStatement, |
|
"ImportDeclaration:exit": leaveStatement, |
|
"LabeledStatement:exit": leaveStatement, |
|
"ReturnStatement:exit": leaveStatement, |
|
"SwitchStatement:exit": leaveStatement, |
|
"ThrowStatement:exit": leaveStatement, |
|
"TryStatement:exit": leaveStatement, |
|
"VariableDeclaration:exit": leaveStatement, |
|
"WhileStatement:exit": leaveStatement, |
|
"WithStatement:exit": leaveStatement, |
|
"ExportNamedDeclaration:exit": leaveStatement, |
|
"ExportDefaultDeclaration:exit": leaveStatement, |
|
"ExportAllDeclaration:exit": leaveStatement, |
|
"Program:exit": reportFirstExtraStatementAndClear |
|
}; |
|
} |
|
};
|
|
|