stylelint
Version:
A mighty, modern CSS linter.
97 lines (83 loc) • 2.7 kB
JavaScript
;
const _ = require("lodash");
const optionsMatches = require("../../utils/optionsMatches");
const report = require("../../utils/report");
const ruleMessages = require("../../utils/ruleMessages");
const styleSearch = require("style-search");
const validateOptions = require("../../utils/validateOptions");
const ruleName = "max-empty-lines";
const messages = ruleMessages(ruleName, {
expected: max =>
`Expected no more than ${max} empty ${max === 1 ? "line" : "lines"}`
});
const rule = function(max, options) {
const maxAdjacentNewlines = max + 1;
return (root, result) => {
const validOptions = validateOptions(
result,
ruleName,
{
actual: max,
possible: _.isNumber
},
{
actual: options,
possible: {
ignore: ["comments"]
},
optional: true
}
);
if (!validOptions) {
return;
}
const rootString = root.toString();
const repeatLFNewLines = _.repeat("\n", maxAdjacentNewlines);
const repeatCRLFNewLines = _.repeat("\r\n", maxAdjacentNewlines);
const ignoreComments = optionsMatches(options, "ignore", "comments");
styleSearch({ source: rootString, target: "\n" }, match => {
checkMatch(rootString, match.endIndex, root);
});
// We must check comments separately in order to accommodate stupid
// `//`-comments from SCSS, which postcss-scss converts to `/* ... */`,
// which adds to extra characters at the end, which messes up our
// warning position
if (!ignoreComments) {
root.walkComments(comment => {
const source =
(comment.raws.left || "") + comment.text + (comment.raws.right || "");
styleSearch({ source, target: "\n" }, match => {
checkMatch(source, match.endIndex, comment, 2);
});
});
}
function checkMatch(source, matchEndIndex, node) {
const offset =
arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
let violationIndex = false;
if (
source.substr(matchEndIndex, maxAdjacentNewlines) === repeatLFNewLines
) {
violationIndex = matchEndIndex + maxAdjacentNewlines;
} else if (
source.substr(matchEndIndex, maxAdjacentNewlines * 2) ===
repeatCRLFNewLines
) {
violationIndex = matchEndIndex + maxAdjacentNewlines * 2;
}
if (!violationIndex) {
return;
}
report({
message: messages.expected(max),
node,
index: violationIndex + offset,
result,
ruleName
});
}
};
};
rule.ruleName = ruleName;
rule.messages = messages;
module.exports = rule;