]> git.proxmox.com Git - pve-eslint.git/blob - eslint/lib/rules/no-unexpected-multiline.js
first commit
[pve-eslint.git] / eslint / lib / rules / no-unexpected-multiline.js
1 /**
2 * @fileoverview Rule to spot scenarios where a newline looks like it is ending a statement, but is not.
3 * @author Glen Mailer
4 */
5 "use strict";
6
7 //------------------------------------------------------------------------------
8 // Requirements
9 //------------------------------------------------------------------------------
10
11 const astUtils = require("./utils/ast-utils");
12
13 //------------------------------------------------------------------------------
14 // Rule Definition
15 //------------------------------------------------------------------------------
16
17 module.exports = {
18 meta: {
19 type: "problem",
20
21 docs: {
22 description: "disallow confusing multiline expressions",
23 category: "Possible Errors",
24 recommended: true,
25 url: "https://eslint.org/docs/rules/no-unexpected-multiline"
26 },
27
28 schema: [],
29 messages: {
30 function: "Unexpected newline between function and ( of function call.",
31 property: "Unexpected newline between object and [ of property access.",
32 taggedTemplate: "Unexpected newline between template tag and template literal.",
33 division: "Unexpected newline between numerator and division operator."
34 }
35 },
36
37 create(context) {
38
39 const REGEX_FLAG_MATCHER = /^[gimsuy]+$/u;
40
41 const sourceCode = context.getSourceCode();
42
43 /**
44 * Check to see if there is a newline between the node and the following open bracket
45 * line's expression
46 * @param {ASTNode} node The node to check.
47 * @param {string} messageId The error messageId to use.
48 * @returns {void}
49 * @private
50 */
51 function checkForBreakAfter(node, messageId) {
52 const openParen = sourceCode.getTokenAfter(node, astUtils.isNotClosingParenToken);
53 const nodeExpressionEnd = sourceCode.getTokenBefore(openParen);
54
55 if (openParen.loc.start.line !== nodeExpressionEnd.loc.end.line) {
56 context.report({ node, loc: openParen.loc.start, messageId, data: { char: openParen.value } });
57 }
58 }
59
60 //--------------------------------------------------------------------------
61 // Public API
62 //--------------------------------------------------------------------------
63
64 return {
65
66 MemberExpression(node) {
67 if (!node.computed) {
68 return;
69 }
70 checkForBreakAfter(node.object, "property");
71 },
72
73 TaggedTemplateExpression(node) {
74 if (node.tag.loc.end.line === node.quasi.loc.start.line) {
75 return;
76 }
77
78 // handle generics type parameters on template tags
79 const tokenBefore = sourceCode.getTokenBefore(node.quasi);
80
81 if (tokenBefore.loc.end.line === node.quasi.loc.start.line) {
82 return;
83 }
84
85 context.report({ node, loc: node.loc.start, messageId: "taggedTemplate" });
86 },
87
88 CallExpression(node) {
89 if (node.arguments.length === 0) {
90 return;
91 }
92 checkForBreakAfter(node.callee, "function");
93 },
94
95 "BinaryExpression[operator='/'] > BinaryExpression[operator='/'].left"(node) {
96 const secondSlash = sourceCode.getTokenAfter(node, token => token.value === "/");
97 const tokenAfterOperator = sourceCode.getTokenAfter(secondSlash);
98
99 if (
100 tokenAfterOperator.type === "Identifier" &&
101 REGEX_FLAG_MATCHER.test(tokenAfterOperator.value) &&
102 secondSlash.range[1] === tokenAfterOperator.range[0]
103 ) {
104 checkForBreakAfter(node.left, "division");
105 }
106 }
107 };
108
109 }
110 };