.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / no-sequences.js
1 /**
2  * @fileoverview Rule to flag use of comma operator
3  * @author Brandon Mills
4  */
5
6 "use strict";
7
8 //------------------------------------------------------------------------------
9 // Requirements
10 //------------------------------------------------------------------------------
11
12 const astUtils = require("./utils/ast-utils");
13
14 //------------------------------------------------------------------------------
15 // Helpers
16 //------------------------------------------------------------------------------
17
18 const DEFAULT_OPTIONS = {
19     allowInParentheses: true
20 };
21
22 //------------------------------------------------------------------------------
23 // Rule Definition
24 //------------------------------------------------------------------------------
25
26 module.exports = {
27     meta: {
28         type: "suggestion",
29
30         docs: {
31             description: "disallow comma operators",
32             category: "Best Practices",
33             recommended: false,
34             url: "https://eslint.org/docs/rules/no-sequences"
35         },
36
37         schema: [{
38             properties: {
39                 allowInParentheses: {
40                     type: "boolean",
41                     default: true
42                 }
43             },
44             additionalProperties: false
45         }],
46
47         messages: {
48             unexpectedCommaExpression: "Unexpected use of comma operator."
49         }
50     },
51
52     create(context) {
53         const options = Object.assign({}, DEFAULT_OPTIONS, context.options[0]);
54         const sourceCode = context.getSourceCode();
55
56         /**
57          * Parts of the grammar that are required to have parens.
58          */
59         const parenthesized = {
60             DoWhileStatement: "test",
61             IfStatement: "test",
62             SwitchStatement: "discriminant",
63             WhileStatement: "test",
64             WithStatement: "object",
65             ArrowFunctionExpression: "body"
66
67             /*
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
72              */
73         };
74
75         /**
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.
80          */
81         function requiresExtraParens(node) {
82             return node.parent && parenthesized[node.parent.type] &&
83                     node === node.parent[parenthesized[node.parent.type]];
84         }
85
86         /**
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.
90          */
91         function isParenthesised(node) {
92             return astUtils.isParenthesised(sourceCode, node);
93         }
94
95         /**
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.
99          */
100         function isParenthesisedTwice(node) {
101             const previousToken = sourceCode.getTokenBefore(node, 1),
102                 nextToken = sourceCode.getTokenAfter(node, 1);
103
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];
107         }
108
109         return {
110             SequenceExpression(node) {
111
112                 // Always allow sequences in for statement update
113                 if (node.parent.type === "ForStatement" &&
114                         (node === node.parent.init || node === node.parent.update)) {
115                     return;
116                 }
117
118                 // Wrapping a sequence in extra parens indicates intent
119                 if (options.allowInParentheses) {
120                     if (requiresExtraParens(node)) {
121                         if (isParenthesisedTwice(node)) {
122                             return;
123                         }
124                     } else {
125                         if (isParenthesised(node)) {
126                             return;
127                         }
128                     }
129                 }
130
131                 const firstCommaToken = sourceCode.getTokenAfter(node.expressions[0], astUtils.isCommaToken);
132
133                 context.report({ node, loc: firstCommaToken.loc, messageId: "unexpectedCommaExpression" });
134             }
135         };
136
137     }
138 };