2 * @fileoverview Rule to flag use of comma operator
3 * @author Brandon Mills
8 //------------------------------------------------------------------------------
10 //------------------------------------------------------------------------------
12 const astUtils
= require("./utils/ast-utils");
14 //------------------------------------------------------------------------------
16 //------------------------------------------------------------------------------
18 const DEFAULT_OPTIONS
= {
19 allowInParentheses
: true
22 //------------------------------------------------------------------------------
24 //------------------------------------------------------------------------------
26 /** @type {import('../shared/types').Rule} */
32 description
: "disallow comma operators",
34 url
: "https://eslint.org/docs/rules/no-sequences"
44 additionalProperties
: false
48 unexpectedCommaExpression
: "Unexpected use of comma operator."
53 const options
= Object
.assign({}, DEFAULT_OPTIONS
, context
.options
[0]);
54 const sourceCode
= context
.getSourceCode();
57 * Parts of the grammar that are required to have parens.
59 const parenthesized
= {
60 DoWhileStatement
: "test",
62 SwitchStatement
: "discriminant",
63 WhileStatement
: "test",
64 WithStatement
: "object",
65 ArrowFunctionExpression
: "body"
68 * Omitting CallExpression - commas are parsed as argument separators
69 * Omitting NewExpression - commas are parsed as argument separators
70 * Omitting ForInStatement - parts aren't individually parenthesised
71 * Omitting ForStatement - parts aren't individually parenthesised
76 * Determines whether a node is required by the grammar to be wrapped in
77 * parens, e.g. the test of an if statement.
78 * @param {ASTNode} node The AST node
79 * @returns {boolean} True if parens around node belong to parent node.
81 function requiresExtraParens(node
) {
82 return node
.parent
&& parenthesized
[node
.parent
.type
] &&
83 node
=== node
.parent
[parenthesized
[node
.parent
.type
]];
87 * Check if a node is wrapped in parens.
88 * @param {ASTNode} node The AST node
89 * @returns {boolean} True if the node has a paren on each side.
91 function isParenthesised(node
) {
92 return astUtils
.isParenthesised(sourceCode
, node
);
96 * Check if a node is wrapped in two levels of parens.
97 * @param {ASTNode} node The AST node
98 * @returns {boolean} True if two parens surround the node on each side.
100 function isParenthesisedTwice(node
) {
101 const previousToken
= sourceCode
.getTokenBefore(node
, 1),
102 nextToken
= sourceCode
.getTokenAfter(node
, 1);
104 return isParenthesised(node
) && previousToken
&& nextToken
&&
105 astUtils
.isOpeningParenToken(previousToken
) && previousToken
.range
[1] <= node
.range
[0] &&
106 astUtils
.isClosingParenToken(nextToken
) && nextToken
.range
[0] >= node
.range
[1];
110 SequenceExpression(node
) {
112 // Always allow sequences in for statement update
113 if (node
.parent
.type
=== "ForStatement" &&
114 (node
=== node
.parent
.init
|| node
=== node
.parent
.update
)) {
118 // Wrapping a sequence in extra parens indicates intent
119 if (options
.allowInParentheses
) {
120 if (requiresExtraParens(node
)) {
121 if (isParenthesisedTwice(node
)) {
125 if (isParenthesised(node
)) {
131 const firstCommaToken
= sourceCode
.getTokenAfter(node
.expressions
[0], astUtils
.isCommaToken
);
133 context
.report({ node
, loc
: firstCommaToken
.loc
, messageId
: "unexpectedCommaExpression" });