Permalink
Cannot retrieve contributors at this time
| /** | |
| * @fileoverview Rule to flag use of comma operator | |
| * @author Brandon Mills | |
| */ | |
| "use strict"; | |
| //------------------------------------------------------------------------------ | |
| // Requirements | |
| //------------------------------------------------------------------------------ | |
| const astUtils = require("./utils/ast-utils"); | |
| //------------------------------------------------------------------------------ | |
| // Rule Definition | |
| //------------------------------------------------------------------------------ | |
| module.exports = { | |
| meta: { | |
| type: "suggestion", | |
| docs: { | |
| description: "disallow comma operators", | |
| category: "Best Practices", | |
| recommended: false, | |
| url: "https://eslint.org/docs/rules/no-sequences" | |
| }, | |
| schema: [] | |
| }, | |
| create(context) { | |
| const sourceCode = context.getSourceCode(); | |
| /** | |
| * Parts of the grammar that are required to have parens. | |
| */ | |
| const parenthesized = { | |
| DoWhileStatement: "test", | |
| IfStatement: "test", | |
| SwitchStatement: "discriminant", | |
| WhileStatement: "test", | |
| WithStatement: "object", | |
| ArrowFunctionExpression: "body" | |
| /* | |
| * Omitting CallExpression - commas are parsed as argument separators | |
| * Omitting NewExpression - commas are parsed as argument separators | |
| * Omitting ForInStatement - parts aren't individually parenthesised | |
| * Omitting ForStatement - parts aren't individually parenthesised | |
| */ | |
| }; | |
| /** | |
| * Determines whether a node is required by the grammar to be wrapped in | |
| * parens, e.g. the test of an if statement. | |
| * @param {ASTNode} node The AST node | |
| * @returns {boolean} True if parens around node belong to parent node. | |
| */ | |
| function requiresExtraParens(node) { | |
| return node.parent && parenthesized[node.parent.type] && | |
| node === node.parent[parenthesized[node.parent.type]]; | |
| } | |
| /** | |
| * Check if a node is wrapped in parens. | |
| * @param {ASTNode} node The AST node | |
| * @returns {boolean} True if the node has a paren on each side. | |
| */ | |
| function isParenthesised(node) { | |
| return astUtils.isParenthesised(sourceCode, node); | |
| } | |
| /** | |
| * Check if a node is wrapped in two levels of parens. | |
| * @param {ASTNode} node The AST node | |
| * @returns {boolean} True if two parens surround the node on each side. | |
| */ | |
| function isParenthesisedTwice(node) { | |
| const previousToken = sourceCode.getTokenBefore(node, 1), | |
| nextToken = sourceCode.getTokenAfter(node, 1); | |
| return isParenthesised(node) && previousToken && nextToken && | |
| astUtils.isOpeningParenToken(previousToken) && previousToken.range[1] <= node.range[0] && | |
| astUtils.isClosingParenToken(nextToken) && nextToken.range[0] >= node.range[1]; | |
| } | |
| return { | |
| SequenceExpression(node) { | |
| // Always allow sequences in for statement update | |
| if (node.parent.type === "ForStatement" && | |
| (node === node.parent.init || node === node.parent.update)) { | |
| return; | |
| } | |
| // Wrapping a sequence in extra parens indicates intent | |
| if (requiresExtraParens(node)) { | |
| if (isParenthesisedTwice(node)) { | |
| return; | |
| } | |
| } else { | |
| if (isParenthesised(node)) { | |
| return; | |
| } | |
| } | |
| const firstCommaToken = sourceCode.getTokenAfter(node.expressions[0], astUtils.isCommaToken); | |
| context.report({ node, loc: firstCommaToken.loc, message: "Unexpected use of comma operator." }); | |
| } | |
| }; | |
| } | |
| }; |