.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / stylelint / lib / rules / block-closing-brace-empty-line-before / index.js
1 "use strict";
2
3 const blockString = require("../../utils/blockString");
4 const hasBlock = require("../../utils/hasBlock");
5 const hasEmptyBlock = require("../../utils/hasEmptyBlock");
6 const hasEmptyLine = require("../../utils/hasEmptyLine");
7 const isSingleLineString = require("../../utils/isSingleLineString");
8 const optionsMatches = require("../../utils/optionsMatches");
9 const report = require("../../utils/report");
10 const ruleMessages = require("../../utils/ruleMessages");
11 const validateOptions = require("../../utils/validateOptions");
12
13 const ruleName = "block-closing-brace-empty-line-before";
14
15 const messages = ruleMessages(ruleName, {
16   expected: "Expected empty line before closing brace",
17   rejected: "Unexpected empty line before closing brace"
18 });
19
20 const rule = function(expectation, options) {
21   return (root, result) => {
22     const validOptions = validateOptions(
23       result,
24       ruleName,
25       {
26         actual: expectation,
27         possible: ["always-multi-line", "never"]
28       },
29       {
30         actual: options,
31         possible: {
32           except: ["after-closing-brace"]
33         },
34         optional: true
35       }
36     );
37     if (!validOptions) {
38       return;
39     }
40
41     // Check both kinds of statements: rules and at-rules
42     root.walkRules(check);
43     root.walkAtRules(check);
44
45     function check(statement) {
46       // Return early if blockless or has empty block
47       if (!hasBlock(statement) || hasEmptyBlock(statement)) {
48         return;
49       }
50
51       // Get whitespace after ""}", ignoring extra semicolon
52       const before = (statement.raws.after || "").replace(/;+/, "");
53       if (before === undefined) {
54         return;
55       }
56
57       // Calculate index
58       const statementString = statement.toString();
59       let index = statementString.length - 1;
60       if (statementString[index - 1] === "\r") {
61         index -= 1;
62       }
63
64       // Set expectation
65       const expectEmptyLineBefore = (() => {
66         const childNodeTypes = statement.nodes.map(item => item.type);
67
68         // Reverse the primary options if `after-closing-brace` is set
69         if (
70           optionsMatches(options, "except", "after-closing-brace") &&
71           (statement.type === "atrule" && childNodeTypes.indexOf("decl") === -1)
72         ) {
73           return expectation === "never" ? true : false;
74         }
75
76         return expectation === "always-multi-line" &&
77           !isSingleLineString(blockString(statement))
78           ? true
79           : false;
80       })();
81
82       // Check for at least one empty line
83       const hasEmptyLineBefore = hasEmptyLine(before);
84
85       // Return if the expectation is met
86       if (expectEmptyLineBefore === hasEmptyLineBefore) {
87         return;
88       }
89
90       const message = expectEmptyLineBefore
91         ? messages.expected
92         : messages.rejected;
93
94       report({
95         message,
96         result,
97         ruleName,
98         node: statement,
99         index
100       });
101     }
102   };
103 };
104
105 rule.ruleName = ruleName;
106 rule.messages = messages;
107 module.exports = rule;