1 | 'use strict';
|
2 |
|
3 | const postcss = require('postcss');
|
4 | const report = require('../../utils/report');
|
5 | const ruleMessages = require('../../utils/ruleMessages');
|
6 | const validateOptions = require('../../utils/validateOptions');
|
7 |
|
8 | const ruleName = 'linebreaks';
|
9 |
|
10 | const messages = ruleMessages(ruleName, {
|
11 | expected: (linebreak) => `Expected linebreak to be ${linebreak}`,
|
12 | });
|
13 |
|
14 | const meta = {
|
15 | url: 'https://stylelint.io/user-guide/rules/list/linebreaks',
|
16 | };
|
17 |
|
18 |
|
19 | const 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 |
|
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 |
|
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 |
|
108 |
|
109 |
|
110 | function reportNewlineError(line, column) {
|
111 |
|
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 |
|
129 | rule.ruleName = ruleName;
|
130 | rule.messages = messages;
|
131 | rule.meta = meta;
|
132 | module.exports = rule;
|