UNPKG

7.49 kBJavaScriptView Raw
1/**
2 * @fileoverview Specify the maximum number of statements allowed per line.
3 * @author Kenneth Williams
4 */
5"use strict";
6
7//------------------------------------------------------------------------------
8// Requirements
9//------------------------------------------------------------------------------
10
11const astUtils = require("./utils/ast-utils");
12
13//------------------------------------------------------------------------------
14// Rule Definition
15//------------------------------------------------------------------------------
16
17module.exports = {
18 meta: {
19 type: "layout",
20
21 docs: {
22 description: "enforce a maximum number of statements allowed per line",
23 category: "Stylistic Issues",
24 recommended: false,
25 url: "https://eslint.org/docs/rules/max-statements-per-line"
26 },
27
28 schema: [
29 {
30 type: "object",
31 properties: {
32 max: {
33 type: "integer",
34 minimum: 1,
35 default: 1
36 }
37 },
38 additionalProperties: false
39 }
40 ],
41 messages: {
42 exceed: "This line has {{numberOfStatementsOnThisLine}} {{statements}}. Maximum allowed is {{maxStatementsPerLine}}."
43 }
44 },
45
46 create(context) {
47
48 const sourceCode = context.getSourceCode(),
49 options = context.options[0] || {},
50 maxStatementsPerLine = typeof options.max !== "undefined" ? options.max : 1;
51
52 let lastStatementLine = 0,
53 numberOfStatementsOnThisLine = 0,
54 firstExtraStatement;
55
56 //--------------------------------------------------------------------------
57 // Helpers
58 //--------------------------------------------------------------------------
59
60 const SINGLE_CHILD_ALLOWED = /^(?:(?:DoWhile|For|ForIn|ForOf|If|Labeled|While)Statement|Export(?:Default|Named)Declaration)$/u;
61
62 /**
63 * Reports with the first extra statement, and clears it.
64 *
65 * @returns {void}
66 */
67 function reportFirstExtraStatementAndClear() {
68 if (firstExtraStatement) {
69 context.report({
70 node: firstExtraStatement,
71 messageId: "exceed",
72 data: {
73 numberOfStatementsOnThisLine,
74 maxStatementsPerLine,
75 statements: numberOfStatementsOnThisLine === 1 ? "statement" : "statements"
76 }
77 });
78 }
79 firstExtraStatement = null;
80 }
81
82 /**
83 * Gets the actual last token of a given node.
84 *
85 * @param {ASTNode} node - A node to get. This is a node except EmptyStatement.
86 * @returns {Token} The actual last token.
87 */
88 function getActualLastToken(node) {
89 return sourceCode.getLastToken(node, astUtils.isNotSemicolonToken);
90 }
91
92 /**
93 * Addresses a given node.
94 * It updates the state of this rule, then reports the node if the node violated this rule.
95 *
96 * @param {ASTNode} node - A node to check.
97 * @returns {void}
98 */
99 function enterStatement(node) {
100 const line = node.loc.start.line;
101
102 /*
103 * Skip to allow non-block statements if this is direct child of control statements.
104 * `if (a) foo();` is counted as 1.
105 * But `if (a) foo(); else foo();` should be counted as 2.
106 */
107 if (SINGLE_CHILD_ALLOWED.test(node.parent.type) &&
108 node.parent.alternate !== node
109 ) {
110 return;
111 }
112
113 // Update state.
114 if (line === lastStatementLine) {
115 numberOfStatementsOnThisLine += 1;
116 } else {
117 reportFirstExtraStatementAndClear();
118 numberOfStatementsOnThisLine = 1;
119 lastStatementLine = line;
120 }
121
122 // Reports if the node violated this rule.
123 if (numberOfStatementsOnThisLine === maxStatementsPerLine + 1) {
124 firstExtraStatement = firstExtraStatement || node;
125 }
126 }
127
128 /**
129 * Updates the state of this rule with the end line of leaving node to check with the next statement.
130 *
131 * @param {ASTNode} node - A node to check.
132 * @returns {void}
133 */
134 function leaveStatement(node) {
135 const line = getActualLastToken(node).loc.end.line;
136
137 // Update state.
138 if (line !== lastStatementLine) {
139 reportFirstExtraStatementAndClear();
140 numberOfStatementsOnThisLine = 1;
141 lastStatementLine = line;
142 }
143 }
144
145 //--------------------------------------------------------------------------
146 // Public API
147 //--------------------------------------------------------------------------
148
149 return {
150 BreakStatement: enterStatement,
151 ClassDeclaration: enterStatement,
152 ContinueStatement: enterStatement,
153 DebuggerStatement: enterStatement,
154 DoWhileStatement: enterStatement,
155 ExpressionStatement: enterStatement,
156 ForInStatement: enterStatement,
157 ForOfStatement: enterStatement,
158 ForStatement: enterStatement,
159 FunctionDeclaration: enterStatement,
160 IfStatement: enterStatement,
161 ImportDeclaration: enterStatement,
162 LabeledStatement: enterStatement,
163 ReturnStatement: enterStatement,
164 SwitchStatement: enterStatement,
165 ThrowStatement: enterStatement,
166 TryStatement: enterStatement,
167 VariableDeclaration: enterStatement,
168 WhileStatement: enterStatement,
169 WithStatement: enterStatement,
170 ExportNamedDeclaration: enterStatement,
171 ExportDefaultDeclaration: enterStatement,
172 ExportAllDeclaration: enterStatement,
173
174 "BreakStatement:exit": leaveStatement,
175 "ClassDeclaration:exit": leaveStatement,
176 "ContinueStatement:exit": leaveStatement,
177 "DebuggerStatement:exit": leaveStatement,
178 "DoWhileStatement:exit": leaveStatement,
179 "ExpressionStatement:exit": leaveStatement,
180 "ForInStatement:exit": leaveStatement,
181 "ForOfStatement:exit": leaveStatement,
182 "ForStatement:exit": leaveStatement,
183 "FunctionDeclaration:exit": leaveStatement,
184 "IfStatement:exit": leaveStatement,
185 "ImportDeclaration:exit": leaveStatement,
186 "LabeledStatement:exit": leaveStatement,
187 "ReturnStatement:exit": leaveStatement,
188 "SwitchStatement:exit": leaveStatement,
189 "ThrowStatement:exit": leaveStatement,
190 "TryStatement:exit": leaveStatement,
191 "VariableDeclaration:exit": leaveStatement,
192 "WhileStatement:exit": leaveStatement,
193 "WithStatement:exit": leaveStatement,
194 "ExportNamedDeclaration:exit": leaveStatement,
195 "ExportDefaultDeclaration:exit": leaveStatement,
196 "ExportAllDeclaration:exit": leaveStatement,
197 "Program:exit": reportFirstExtraStatementAndClear
198 };
199 }
200};