.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / newline-per-chained-call.js
1 /**
2  * @fileoverview Rule to ensure newline per method call when chaining calls
3  * @author Rajendra Patil
4  * @author Burak Yigit Kaya
5  */
6
7 "use strict";
8
9 const astUtils = require("./utils/ast-utils");
10
11 //------------------------------------------------------------------------------
12 // Rule Definition
13 //------------------------------------------------------------------------------
14
15 module.exports = {
16     meta: {
17         type: "layout",
18
19         docs: {
20             description: "require a newline after each call in a method chain",
21             category: "Stylistic Issues",
22             recommended: false,
23             url: "https://eslint.org/docs/rules/newline-per-chained-call"
24         },
25
26         fixable: "whitespace",
27
28         schema: [{
29             type: "object",
30             properties: {
31                 ignoreChainWithDepth: {
32                     type: "integer",
33                     minimum: 1,
34                     maximum: 10,
35                     default: 2
36                 }
37             },
38             additionalProperties: false
39         }],
40         messages: {
41             expected: "Expected line break before `{{callee}}`."
42         }
43     },
44
45     create(context) {
46
47         const options = context.options[0] || {},
48             ignoreChainWithDepth = options.ignoreChainWithDepth || 2;
49
50         const sourceCode = context.getSourceCode();
51
52         /**
53          * Get the prefix of a given MemberExpression node.
54          * If the MemberExpression node is a computed value it returns a
55          * left bracket. If not it returns a period.
56          * @param  {ASTNode} node A MemberExpression node to get
57          * @returns {string} The prefix of the node.
58          */
59         function getPrefix(node) {
60             if (node.computed) {
61                 if (node.optional) {
62                     return "?.[";
63                 }
64                 return "[";
65             }
66             if (node.optional) {
67                 return "?.";
68             }
69             return ".";
70         }
71
72         /**
73          * Gets the property text of a given MemberExpression node.
74          * If the text is multiline, this returns only the first line.
75          * @param {ASTNode} node A MemberExpression node to get.
76          * @returns {string} The property text of the node.
77          */
78         function getPropertyText(node) {
79             const prefix = getPrefix(node);
80             const lines = sourceCode.getText(node.property).split(astUtils.LINEBREAK_MATCHER);
81             const suffix = node.computed && lines.length === 1 ? "]" : "";
82
83             return prefix + lines[0] + suffix;
84         }
85
86         return {
87             "CallExpression:exit"(node) {
88                 const callee = astUtils.skipChainExpression(node.callee);
89
90                 if (callee.type !== "MemberExpression") {
91                     return;
92                 }
93
94                 let parent = astUtils.skipChainExpression(callee.object);
95                 let depth = 1;
96
97                 while (parent && parent.callee) {
98                     depth += 1;
99                     parent = astUtils.skipChainExpression(astUtils.skipChainExpression(parent.callee).object);
100                 }
101
102                 if (depth > ignoreChainWithDepth && astUtils.isTokenOnSameLine(callee.object, callee.property)) {
103                     const firstTokenAfterObject = sourceCode.getTokenAfter(callee.object, astUtils.isNotClosingParenToken);
104
105                     context.report({
106                         node: callee.property,
107                         loc: {
108                             start: firstTokenAfterObject.loc.start,
109                             end: callee.loc.end
110                         },
111                         messageId: "expected",
112                         data: {
113                             callee: getPropertyText(callee)
114                         },
115                         fix(fixer) {
116                             return fixer.insertTextBefore(firstTokenAfterObject, "\n");
117                         }
118                     });
119                 }
120             }
121         };
122     }
123 };