UNPKG

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