blob: 6a49acd750ae99e4e63958f0ece608f5b2c6636c [file] [log] [blame]
"use strict";
const atRuleParamIndex = require("../../utils/atRuleParamIndex");
const declarationValueIndex = require("../../utils/declarationValueIndex");
const parseSelector = require("../../utils/parseSelector");
const report = require("../../utils/report");
const ruleMessages = require("../../utils/ruleMessages");
const validateOptions = require("../../utils/validateOptions");
const valueParser = require("postcss-value-parser");
const ruleName = "string-no-newline";
const reNewLine = /(\r?\n)/;
const messages = ruleMessages(ruleName, {
rejected: "Unexpected newline in string"
});
const rule = function(actual) {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual });
if (!validOptions) {
return;
}
root.walk(node => {
switch (node.type) {
case "atrule":
checkDeclOrAtRule(node, node.params, atRuleParamIndex);
break;
case "decl":
checkDeclOrAtRule(node, node.value, declarationValueIndex);
break;
case "rule":
checkRule(node);
break;
}
});
function checkRule(rule) {
// Get out quickly if there are no new line
if (!reNewLine.test(rule.selector)) {
return;
}
parseSelector(rule.selector, result, rule, selectorTree => {
selectorTree.walkAttributes(attributeNode => {
if (!reNewLine.test(attributeNode.value)) {
return;
}
const openIndex = [
// length of our attribute
attributeNode.attribute,
// length of our operator , ie '='
attributeNode.operator,
// length of the contents before newline
RegExp.leftContext
].reduce(
(index, str) => index + str.length,
// index of the start of our attribute node in our source
attributeNode.sourceIndex
);
report({
message: messages.rejected,
node: rule,
index: openIndex,
result,
ruleName
});
});
});
}
function checkDeclOrAtRule(node, value, getIndex) {
// Get out quickly if there are no new line
if (!reNewLine.test(value)) {
return;
}
valueParser(value).walk(valueNode => {
if (valueNode.type !== "string" || !reNewLine.test(valueNode.value)) {
return;
}
const openIndex = [
// length of the quote
valueNode.quote,
// length of the contents before newline
RegExp.leftContext
].reduce((index, str) => index + str.length, valueNode.sourceIndex);
report({
message: messages.rejected,
node,
index: getIndex(node) + openIndex,
result,
ruleName
});
});
}
};
};
rule.ruleName = ruleName;
rule.messages = messages;
module.exports = rule;