2 * @fileoverview Specify the maximum number of statements allowed per line.
3 * @author Kenneth Williams
7 //------------------------------------------------------------------------------
9 //------------------------------------------------------------------------------
11 const astUtils
= require("./utils/ast-utils");
13 //------------------------------------------------------------------------------
15 //------------------------------------------------------------------------------
17 /** @type {import('../shared/types').Rule} */
23 description
: "Enforce a maximum number of statements allowed per line",
25 url
: "https://eslint.org/docs/rules/max-statements-per-line"
38 additionalProperties
: false
42 exceed
: "This line has {{numberOfStatementsOnThisLine}} {{statements}}. Maximum allowed is {{maxStatementsPerLine}}."
48 const sourceCode
= context
.getSourceCode(),
49 options
= context
.options
[0] || {},
50 maxStatementsPerLine
= typeof options
.max
!== "undefined" ? options
.max
: 1;
52 let lastStatementLine
= 0,
53 numberOfStatementsOnThisLine
= 0,
56 //--------------------------------------------------------------------------
58 //--------------------------------------------------------------------------
60 const SINGLE_CHILD_ALLOWED
= /^(?:(?:DoWhile|For|ForIn|ForOf|If|Labeled|While)Statement|Export(?:Default|Named)Declaration)$/u;
63 * Reports with the first extra statement, and clears it.
66 function reportFirstExtraStatementAndClear() {
67 if (firstExtraStatement
) {
69 node
: firstExtraStatement
,
72 numberOfStatementsOnThisLine
,
74 statements
: numberOfStatementsOnThisLine
=== 1 ? "statement" : "statements"
78 firstExtraStatement
= null;
82 * Gets the actual last token of a given node.
83 * @param {ASTNode} node A node to get. This is a node except EmptyStatement.
84 * @returns {Token} The actual last token.
86 function getActualLastToken(node
) {
87 return sourceCode
.getLastToken(node
, astUtils
.isNotSemicolonToken
);
91 * Addresses a given node.
92 * It updates the state of this rule, then reports the node if the node violated this rule.
93 * @param {ASTNode} node A node to check.
96 function enterStatement(node
) {
97 const line
= node
.loc
.start
.line
;
100 * Skip to allow non-block statements if this is direct child of control statements.
101 * `if (a) foo();` is counted as 1.
102 * But `if (a) foo(); else foo();` should be counted as 2.
104 if (SINGLE_CHILD_ALLOWED
.test(node
.parent
.type
) &&
105 node
.parent
.alternate
!== node
111 if (line
=== lastStatementLine
) {
112 numberOfStatementsOnThisLine
+= 1;
114 reportFirstExtraStatementAndClear();
115 numberOfStatementsOnThisLine
= 1;
116 lastStatementLine
= line
;
119 // Reports if the node violated this rule.
120 if (numberOfStatementsOnThisLine
=== maxStatementsPerLine
+ 1) {
121 firstExtraStatement
= firstExtraStatement
|| node
;
126 * Updates the state of this rule with the end line of leaving node to check with the next statement.
127 * @param {ASTNode} node A node to check.
130 function leaveStatement(node
) {
131 const line
= getActualLastToken(node
).loc
.end
.line
;
134 if (line
!== lastStatementLine
) {
135 reportFirstExtraStatementAndClear();
136 numberOfStatementsOnThisLine
= 1;
137 lastStatementLine
= line
;
141 //--------------------------------------------------------------------------
143 //--------------------------------------------------------------------------
146 BreakStatement
: enterStatement
,
147 ClassDeclaration
: enterStatement
,
148 ContinueStatement
: enterStatement
,
149 DebuggerStatement
: enterStatement
,
150 DoWhileStatement
: enterStatement
,
151 ExpressionStatement
: enterStatement
,
152 ForInStatement
: enterStatement
,
153 ForOfStatement
: enterStatement
,
154 ForStatement
: enterStatement
,
155 FunctionDeclaration
: enterStatement
,
156 IfStatement
: enterStatement
,
157 ImportDeclaration
: enterStatement
,
158 LabeledStatement
: enterStatement
,
159 ReturnStatement
: enterStatement
,
160 SwitchStatement
: enterStatement
,
161 ThrowStatement
: enterStatement
,
162 TryStatement
: enterStatement
,
163 VariableDeclaration
: enterStatement
,
164 WhileStatement
: enterStatement
,
165 WithStatement
: enterStatement
,
166 ExportNamedDeclaration
: enterStatement
,
167 ExportDefaultDeclaration
: enterStatement
,
168 ExportAllDeclaration
: enterStatement
,
170 "BreakStatement:exit": leaveStatement
,
171 "ClassDeclaration:exit": leaveStatement
,
172 "ContinueStatement:exit": leaveStatement
,
173 "DebuggerStatement:exit": leaveStatement
,
174 "DoWhileStatement:exit": leaveStatement
,
175 "ExpressionStatement:exit": leaveStatement
,
176 "ForInStatement:exit": leaveStatement
,
177 "ForOfStatement:exit": leaveStatement
,
178 "ForStatement:exit": leaveStatement
,
179 "FunctionDeclaration:exit": leaveStatement
,
180 "IfStatement:exit": leaveStatement
,
181 "ImportDeclaration:exit": leaveStatement
,
182 "LabeledStatement:exit": leaveStatement
,
183 "ReturnStatement:exit": leaveStatement
,
184 "SwitchStatement:exit": leaveStatement
,
185 "ThrowStatement:exit": leaveStatement
,
186 "TryStatement:exit": leaveStatement
,
187 "VariableDeclaration:exit": leaveStatement
,
188 "WhileStatement:exit": leaveStatement
,
189 "WithStatement:exit": leaveStatement
,
190 "ExportNamedDeclaration:exit": leaveStatement
,
191 "ExportDefaultDeclaration:exit": leaveStatement
,
192 "ExportAllDeclaration:exit": leaveStatement
,
193 "Program:exit": reportFirstExtraStatementAndClear