| "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; |