UNPKG

2.81 kBJavaScriptView Raw
1'use strict';
2
3const postcss = require('postcss');
4const report = require('../../utils/report');
5const ruleMessages = require('../../utils/ruleMessages');
6const validateOptions = require('../../utils/validateOptions');
7
8const ruleName = 'linebreaks';
9
10const messages = ruleMessages(ruleName, {
11 expected: (linebreak) => `Expected linebreak to be ${linebreak}`,
12});
13
14const meta = {
15 url: 'https://stylelint.io/user-guide/rules/list/linebreaks',
16};
17
18/** @type {import('stylelint').Rule} */
19const rule = (primary, _secondaryOptions, context) => {
20 return (root, result) => {
21 const validOptions = validateOptions(result, ruleName, {
22 actual: primary,
23 possible: ['unix', 'windows'],
24 });
25
26 if (!validOptions) {
27 return;
28 }
29
30 const shouldHaveCR = primary === 'windows';
31
32 if (context.fix) {
33 root.walk((node) => {
34 if ('selector' in node) {
35 node.selector = fixData(node.selector);
36 }
37
38 if ('value' in node) {
39 node.value = fixData(node.value);
40 }
41
42 if ('text' in node) {
43 node.text = fixData(node.text);
44 }
45
46 if (node.raws.before) {
47 node.raws.before = fixData(node.raws.before);
48 }
49
50 if (typeof node.raws.after === 'string') {
51 node.raws.after = fixData(node.raws.after);
52 }
53 });
54
55 if (typeof root.raws.after === 'string') {
56 root.raws.after = fixData(root.raws.after);
57 }
58 } else {
59 if (root.source == null) throw new Error('The root node must have a source');
60
61 const lines = root.source.input.css.split('\n');
62
63 for (let i = 0; i < lines.length; i++) {
64 let line = lines[i];
65
66 if (i < lines.length - 1 && !line.includes('\r')) {
67 line += '\n';
68 }
69
70 if (hasError(line)) {
71 const lineNum = i + 1;
72 const colNum = line.length;
73
74 reportNewlineError(lineNum, colNum);
75 }
76 }
77 }
78
79 /**
80 * @param {string} dataToCheck
81 */
82 function hasError(dataToCheck) {
83 const hasNewlineToVerify = /[\r\n]/.test(dataToCheck);
84 const hasCR = hasNewlineToVerify ? /\r/.test(dataToCheck) : false;
85
86 return hasNewlineToVerify && hasCR !== shouldHaveCR;
87 }
88
89 /**
90 * @param {string} data
91 */
92 function fixData(data) {
93 if (data) {
94 let res = data.replace(/\r/g, '');
95
96 if (shouldHaveCR) {
97 res = res.replace(/\n/g, '\r\n');
98 }
99
100 return res;
101 }
102
103 return data;
104 }
105
106 /**
107 * @param {number} line
108 * @param {number} column
109 */
110 function reportNewlineError(line, column) {
111 // Creating a node manually helps us to point to empty lines.
112 const node = postcss.rule({
113 source: {
114 start: { line, column, offset: 0 },
115 input: new postcss.Input(''),
116 },
117 });
118
119 report({
120 message: messages.expected(primary),
121 node,
122 result,
123 ruleName,
124 });
125 }
126 };
127};
128
129rule.ruleName = ruleName;
130rule.messages = messages;
131rule.meta = meta;
132module.exports = rule;