UNPKG

2.83 kBJavaScriptView Raw
1// @ts-nocheck
2
3'use strict';
4
5const atRuleParamIndex = require('../../utils/atRuleParamIndex');
6const declarationValueIndex = require('../../utils/declarationValueIndex');
7const isStandardSyntaxSelector = require('../../utils/isStandardSyntaxSelector');
8const parseSelector = require('../../utils/parseSelector');
9const report = require('../../utils/report');
10const ruleMessages = require('../../utils/ruleMessages');
11const validateOptions = require('../../utils/validateOptions');
12const valueParser = require('postcss-value-parser');
13
14const ruleName = 'string-no-newline';
15const reNewLine = /(\r?\n)/;
16
17const messages = ruleMessages(ruleName, {
18 rejected: 'Unexpected newline in string',
19});
20
21function rule(actual) {
22 return (root, result) => {
23 const validOptions = validateOptions(result, ruleName, { actual });
24
25 if (!validOptions) {
26 return;
27 }
28
29 root.walk((node) => {
30 switch (node.type) {
31 case 'atrule':
32 checkDeclOrAtRule(node, node.params, atRuleParamIndex);
33 break;
34 case 'decl':
35 checkDeclOrAtRule(node, node.value, declarationValueIndex);
36 break;
37 case 'rule':
38 checkRule(node);
39 break;
40 }
41 });
42
43 function checkRule(rule) {
44 // Get out quickly if there are no new line
45 if (!reNewLine.test(rule.selector)) {
46 return;
47 }
48
49 if (!isStandardSyntaxSelector(rule.selector)) {
50 return;
51 }
52
53 parseSelector(rule.selector, result, rule, (selectorTree) => {
54 selectorTree.walkAttributes((attributeNode) => {
55 if (!reNewLine.test(attributeNode.value)) {
56 return;
57 }
58
59 const openIndex = [
60 // length of our attribute
61 attributeNode.attribute,
62 // length of our operator , ie '='
63 attributeNode.operator,
64 // length of the contents before newline
65 RegExp.leftContext,
66 ].reduce(
67 (index, str) => index + str.length,
68 // index of the start of our attribute node in our source
69 attributeNode.sourceIndex,
70 );
71
72 report({
73 message: messages.rejected,
74 node: rule,
75 index: openIndex,
76 result,
77 ruleName,
78 });
79 });
80 });
81 }
82
83 function checkDeclOrAtRule(node, value, getIndex) {
84 // Get out quickly if there are no new line
85 if (!reNewLine.test(value)) {
86 return;
87 }
88
89 valueParser(value).walk((valueNode) => {
90 if (valueNode.type !== 'string' || !reNewLine.test(valueNode.value)) {
91 return;
92 }
93
94 const openIndex = [
95 // length of the quote
96 valueNode.quote,
97 // length of the contents before newline
98 RegExp.leftContext,
99 ].reduce((index, str) => index + str.length, valueNode.sourceIndex);
100
101 report({
102 message: messages.rejected,
103 node,
104 index: getIndex(node) + openIndex,
105 result,
106 ruleName,
107 });
108 });
109 }
110 };
111}
112
113rule.ruleName = ruleName;
114rule.messages = messages;
115module.exports = rule;