3 const _ = require("lodash");
4 const optionsMatches = require("../../utils/optionsMatches");
5 const report = require("../../utils/report");
6 const ruleMessages = require("../../utils/ruleMessages");
7 const styleSearch = require("style-search");
8 const validateOptions = require("../../utils/validateOptions");
10 const ruleName = "max-empty-lines";
12 const messages = ruleMessages(ruleName, {
14 `Expected no more than ${max} empty ${max === 1 ? "line" : "lines"}`
17 const rule = function(max, options) {
18 const maxAdjacentNewlines = max + 1;
20 return (root, result) => {
21 const validOptions = validateOptions(
40 const rootString = root.toString();
41 const repeatLFNewLines = _.repeat("\n", maxAdjacentNewlines);
42 const repeatCRLFNewLines = _.repeat("\r\n", maxAdjacentNewlines);
43 const ignoreComments = optionsMatches(options, "ignore", "comments");
45 styleSearch({ source: rootString, target: "\n" }, match => {
46 checkMatch(rootString, match.endIndex, root);
49 // We must check comments separately in order to accommodate stupid
50 // `//`-comments from SCSS, which postcss-scss converts to `/* ... */`,
51 // which adds to extra characters at the end, which messes up our
53 if (!ignoreComments) {
54 root.walkComments(comment => {
56 (comment.raws.left || "") + comment.text + (comment.raws.right || "");
57 styleSearch({ source, target: "\n" }, match => {
58 checkMatch(source, match.endIndex, comment, 2);
63 function checkMatch(source, matchEndIndex, node) {
65 arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
67 let violationIndex = false;
69 source.substr(matchEndIndex, maxAdjacentNewlines) === repeatLFNewLines
71 violationIndex = matchEndIndex + maxAdjacentNewlines;
73 source.substr(matchEndIndex, maxAdjacentNewlines * 2) ===
76 violationIndex = matchEndIndex + maxAdjacentNewlines * 2;
79 if (!violationIndex) {
84 message: messages.expected(max),
86 index: violationIndex + offset,
94 rule.ruleName = ruleName;
95 rule.messages = messages;
96 module.exports = rule;