.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / lines-around-directive.js
1 /**
2  * @fileoverview Require or disallow newlines around directives.
3  * @author Kai Cataldo
4  * @deprecated
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 or disallow newlines around directives",
21             category: "Stylistic Issues",
22             recommended: false,
23             url: "https://eslint.org/docs/rules/lines-around-directive"
24         },
25
26         schema: [{
27             oneOf: [
28                 {
29                     enum: ["always", "never"]
30                 },
31                 {
32                     type: "object",
33                     properties: {
34                         before: {
35                             enum: ["always", "never"]
36                         },
37                         after: {
38                             enum: ["always", "never"]
39                         }
40                     },
41                     additionalProperties: false,
42                     minProperties: 2
43                 }
44             ]
45         }],
46
47         fixable: "whitespace",
48         messages: {
49             expected: "Expected newline {{location}} \"{{value}}\" directive.",
50             unexpected: "Unexpected newline {{location}} \"{{value}}\" directive."
51         },
52         deprecated: true,
53         replacedBy: ["padding-line-between-statements"]
54     },
55
56     create(context) {
57         const sourceCode = context.getSourceCode();
58         const config = context.options[0] || "always";
59         const expectLineBefore = typeof config === "string" ? config : config.before;
60         const expectLineAfter = typeof config === "string" ? config : config.after;
61
62         //--------------------------------------------------------------------------
63         // Helpers
64         //--------------------------------------------------------------------------
65
66         /**
67          * Check if node is preceded by a blank newline.
68          * @param {ASTNode} node Node to check.
69          * @returns {boolean} Whether or not the passed in node is preceded by a blank newline.
70          */
71         function hasNewlineBefore(node) {
72             const tokenBefore = sourceCode.getTokenBefore(node, { includeComments: true });
73             const tokenLineBefore = tokenBefore ? tokenBefore.loc.end.line : 0;
74
75             return node.loc.start.line - tokenLineBefore >= 2;
76         }
77
78         /**
79          * Gets the last token of a node that is on the same line as the rest of the node.
80          * This will usually be the last token of the node, but it will be the second-to-last token if the node has a trailing
81          * semicolon on a different line.
82          * @param {ASTNode} node A directive node
83          * @returns {Token} The last token of the node on the line
84          */
85         function getLastTokenOnLine(node) {
86             const lastToken = sourceCode.getLastToken(node);
87             const secondToLastToken = sourceCode.getTokenBefore(lastToken);
88
89             return astUtils.isSemicolonToken(lastToken) && lastToken.loc.start.line > secondToLastToken.loc.end.line
90                 ? secondToLastToken
91                 : lastToken;
92         }
93
94         /**
95          * Check if node is followed by a blank newline.
96          * @param {ASTNode} node Node to check.
97          * @returns {boolean} Whether or not the passed in node is followed by a blank newline.
98          */
99         function hasNewlineAfter(node) {
100             const lastToken = getLastTokenOnLine(node);
101             const tokenAfter = sourceCode.getTokenAfter(lastToken, { includeComments: true });
102
103             return tokenAfter.loc.start.line - lastToken.loc.end.line >= 2;
104         }
105
106         /**
107          * Report errors for newlines around directives.
108          * @param {ASTNode} node Node to check.
109          * @param {string} location Whether the error was found before or after the directive.
110          * @param {boolean} expected Whether or not a newline was expected or unexpected.
111          * @returns {void}
112          */
113         function reportError(node, location, expected) {
114             context.report({
115                 node,
116                 messageId: expected ? "expected" : "unexpected",
117                 data: {
118                     value: node.expression.value,
119                     location
120                 },
121                 fix(fixer) {
122                     const lastToken = getLastTokenOnLine(node);
123
124                     if (expected) {
125                         return location === "before" ? fixer.insertTextBefore(node, "\n") : fixer.insertTextAfter(lastToken, "\n");
126                     }
127                     return fixer.removeRange(location === "before" ? [node.range[0] - 1, node.range[0]] : [lastToken.range[1], lastToken.range[1] + 1]);
128                 }
129             });
130         }
131
132         /**
133          * Check lines around directives in node
134          * @param {ASTNode} node node to check
135          * @returns {void}
136          */
137         function checkDirectives(node) {
138             const directives = astUtils.getDirectivePrologue(node);
139
140             if (!directives.length) {
141                 return;
142             }
143
144             const firstDirective = directives[0];
145             const leadingComments = sourceCode.getCommentsBefore(firstDirective);
146
147             /*
148              * Only check before the first directive if it is preceded by a comment or if it is at the top of
149              * the file and expectLineBefore is set to "never". This is to not force a newline at the top of
150              * the file if there are no comments as well as for compatibility with padded-blocks.
151              */
152             if (leadingComments.length) {
153                 if (expectLineBefore === "always" && !hasNewlineBefore(firstDirective)) {
154                     reportError(firstDirective, "before", true);
155                 }
156
157                 if (expectLineBefore === "never" && hasNewlineBefore(firstDirective)) {
158                     reportError(firstDirective, "before", false);
159                 }
160             } else if (
161                 node.type === "Program" &&
162                 expectLineBefore === "never" &&
163                 !leadingComments.length &&
164                 hasNewlineBefore(firstDirective)
165             ) {
166                 reportError(firstDirective, "before", false);
167             }
168
169             const lastDirective = directives[directives.length - 1];
170             const statements = node.type === "Program" ? node.body : node.body.body;
171
172             /*
173              * Do not check after the last directive if the body only
174              * contains a directive prologue and isn't followed by a comment to ensure
175              * this rule behaves well with padded-blocks.
176              */
177             if (lastDirective === statements[statements.length - 1] && !lastDirective.trailingComments) {
178                 return;
179             }
180
181             if (expectLineAfter === "always" && !hasNewlineAfter(lastDirective)) {
182                 reportError(lastDirective, "after", true);
183             }
184
185             if (expectLineAfter === "never" && hasNewlineAfter(lastDirective)) {
186                 reportError(lastDirective, "after", false);
187             }
188         }
189
190         //--------------------------------------------------------------------------
191         // Public
192         //--------------------------------------------------------------------------
193
194         return {
195             Program: checkDirectives,
196             FunctionDeclaration: checkDirectives,
197             FunctionExpression: checkDirectives,
198             ArrowFunctionExpression: checkDirectives
199         };
200     }
201 };