.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / stylelint / lib / rules / rule-empty-line-before / index.js
1 "use strict";
2
3 const addEmptyLineBefore = require("../../utils/addEmptyLineBefore");
4 const getPreviousNonSharedLineCommentNode = require("../../utils/getPreviousNonSharedLineCommentNode");
5 const hasEmptyLine = require("../../utils/hasEmptyLine");
6 const isAfterSingleLineComment = require("../../utils/isAfterSingleLineComment");
7 const isFirstNested = require("../../utils/isFirstNested");
8 const isFirstNodeOfRoot = require("../../utils/isFirstNodeOfRoot");
9 const isSingleLineString = require("../../utils/isSingleLineString");
10 const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule");
11 const optionsMatches = require("../../utils/optionsMatches");
12 const removeEmptyLinesBefore = require("../../utils/removeEmptyLinesBefore");
13 const report = require("../../utils/report");
14 const ruleMessages = require("../../utils/ruleMessages");
15 const validateOptions = require("../../utils/validateOptions");
16
17 const ruleName = "rule-empty-line-before";
18
19 const messages = ruleMessages(ruleName, {
20   expected: "Expected empty line before rule",
21   rejected: "Unexpected empty line before rule"
22 });
23
24 const rule = function(expectation, options, context) {
25   return (root, result) => {
26     const validOptions = validateOptions(
27       result,
28       ruleName,
29       {
30         actual: expectation,
31         possible: ["always", "never", "always-multi-line", "never-multi-line"]
32       },
33       {
34         actual: options,
35         possible: {
36           ignore: ["after-comment", "inside-block"],
37           except: [
38             "after-rule",
39             "after-single-line-comment",
40             "first-nested",
41             "inside-block-and-after-rule",
42             "inside-block"
43           ]
44         },
45         optional: true
46       }
47     );
48
49     if (!validOptions) {
50       return;
51     }
52
53     root.walkRules(rule => {
54       if (!isStandardSyntaxRule(rule)) {
55         return;
56       }
57
58       // Ignore the first node
59       if (isFirstNodeOfRoot(rule)) {
60         return;
61       }
62
63       // Optionally ignore the expectation if a comment precedes this node
64       if (
65         optionsMatches(options, "ignore", "after-comment") &&
66         rule.prev() &&
67         rule.prev().type === "comment"
68       ) {
69         return;
70       }
71
72       const isNested = rule.parent.type !== "root";
73
74       // Optionally ignore the expectation if inside a block
75       if (optionsMatches(options, "ignore", "inside-block") && isNested) {
76         return;
77       }
78
79       // Ignore if the expectation is for multiple and the rule is single-line
80       if (
81         expectation.indexOf("multi-line") !== -1 &&
82         isSingleLineString(rule.toString())
83       ) {
84         return;
85       }
86
87       let expectEmptyLineBefore =
88         expectation.indexOf("always") !== -1 ? true : false;
89
90       // Optionally reverse the expectation if any exceptions apply
91       if (
92         (optionsMatches(options, "except", "first-nested") &&
93           isFirstNested(rule)) ||
94         (optionsMatches(options, "except", "after-rule") &&
95           isAfterRule(rule)) ||
96         (optionsMatches(options, "except", "inside-block-and-after-rule") &&
97           isNested &&
98           isAfterRule(rule)) ||
99         (optionsMatches(options, "except", "after-single-line-comment") &&
100           isAfterSingleLineComment(rule)) ||
101         (optionsMatches(options, "except", "inside-block") && isNested)
102       ) {
103         expectEmptyLineBefore = !expectEmptyLineBefore;
104       }
105
106       const hasEmptyLineBefore = hasEmptyLine(rule.raws.before);
107
108       // Return if the expectation is met
109       if (expectEmptyLineBefore === hasEmptyLineBefore) {
110         return;
111       }
112
113       // Fix
114       if (context.fix) {
115         if (expectEmptyLineBefore) {
116           addEmptyLineBefore(rule, context.newline);
117         } else {
118           removeEmptyLinesBefore(rule, context.newline);
119         }
120
121         return;
122       }
123
124       const message = expectEmptyLineBefore
125         ? messages.expected
126         : messages.rejected;
127
128       report({
129         message,
130         node: rule,
131         result,
132         ruleName
133       });
134     });
135   };
136 };
137
138 function isAfterRule(rule) {
139   const prevNode = getPreviousNonSharedLineCommentNode(rule);
140   return prevNode && prevNode.type === "rule";
141 }
142
143 rule.ruleName = ruleName;
144 rule.messages = messages;
145 module.exports = rule;