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");
17 const ruleName = "rule-empty-line-before";
19 const messages = ruleMessages(ruleName, {
20 expected: "Expected empty line before rule",
21 rejected: "Unexpected empty line before rule"
24 const rule = function(expectation, options, context) {
25 return (root, result) => {
26 const validOptions = validateOptions(
31 possible: ["always", "never", "always-multi-line", "never-multi-line"]
36 ignore: ["after-comment", "inside-block"],
39 "after-single-line-comment",
41 "inside-block-and-after-rule",
53 root.walkRules(rule => {
54 if (!isStandardSyntaxRule(rule)) {
58 // Ignore the first node
59 if (isFirstNodeOfRoot(rule)) {
63 // Optionally ignore the expectation if a comment precedes this node
65 optionsMatches(options, "ignore", "after-comment") &&
67 rule.prev().type === "comment"
72 const isNested = rule.parent.type !== "root";
74 // Optionally ignore the expectation if inside a block
75 if (optionsMatches(options, "ignore", "inside-block") && isNested) {
79 // Ignore if the expectation is for multiple and the rule is single-line
81 expectation.indexOf("multi-line") !== -1 &&
82 isSingleLineString(rule.toString())
87 let expectEmptyLineBefore =
88 expectation.indexOf("always") !== -1 ? true : false;
90 // Optionally reverse the expectation if any exceptions apply
92 (optionsMatches(options, "except", "first-nested") &&
93 isFirstNested(rule)) ||
94 (optionsMatches(options, "except", "after-rule") &&
96 (optionsMatches(options, "except", "inside-block-and-after-rule") &&
99 (optionsMatches(options, "except", "after-single-line-comment") &&
100 isAfterSingleLineComment(rule)) ||
101 (optionsMatches(options, "except", "inside-block") && isNested)
103 expectEmptyLineBefore = !expectEmptyLineBefore;
106 const hasEmptyLineBefore = hasEmptyLine(rule.raws.before);
108 // Return if the expectation is met
109 if (expectEmptyLineBefore === hasEmptyLineBefore) {
115 if (expectEmptyLineBefore) {
116 addEmptyLineBefore(rule, context.newline);
118 removeEmptyLinesBefore(rule, context.newline);
124 const message = expectEmptyLineBefore
138 function isAfterRule(rule) {
139 const prevNode = getPreviousNonSharedLineCommentNode(rule);
140 return prevNode && prevNode.type === "rule";
143 rule.ruleName = ruleName;
144 rule.messages = messages;
145 module.exports = rule;