blob: 21beee5a1fbef2cade980aebfcd46d637b6e217b [file] [log] [blame]
'use strict';
const postcss = require('postcss');
const report = require('../../utils/report');
const ruleMessages = require('../../utils/ruleMessages');
const validateOptions = require('../../utils/validateOptions');
const ruleName = 'linebreaks';
const messages = ruleMessages(ruleName, {
expected: (linebreak) => `Expected linebreak to be ${linebreak}`,
});
/** @type {import('stylelint').Rule} */
const rule = (primary, _secondaryOptions, context) => {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, {
actual: primary,
possible: ['unix', 'windows'],
});
if (!validOptions) {
return;
}
const shouldHaveCR = primary === 'windows';
if (context.fix) {
root.walk((node) => {
if ('selector' in node) {
node.selector = fixData(node.selector);
}
if ('value' in node) {
node.value = fixData(node.value);
}
if ('text' in node) {
node.text = fixData(node.text);
}
if (node.raws.before) {
node.raws.before = fixData(node.raws.before);
}
if ('after' in node.raws && node.raws.after) {
node.raws.after = fixData(node.raws.after);
}
});
if ('after' in root.raws && root.raws.after) {
root.raws.after = fixData(root.raws.after);
}
} else {
if (root.source == null) throw new Error('The root node must have a source');
const lines = root.source.input.css.split('\n');
for (let i = 0; i < lines.length; i++) {
let line = lines[i];
if (i < lines.length - 1 && !line.includes('\r')) {
line += '\n';
}
if (hasError(line)) {
const lineNum = i + 1;
const colNum = line.length;
reportNewlineError(lineNum, colNum);
}
}
}
/**
* @param {string} dataToCheck
*/
function hasError(dataToCheck) {
const hasNewlineToVerify = /[\r\n]/.test(dataToCheck);
const hasCR = hasNewlineToVerify ? /\r/.test(dataToCheck) : false;
return hasNewlineToVerify && hasCR !== shouldHaveCR;
}
/**
* @param {string} data
*/
function fixData(data) {
if (data) {
let res = data.replace(/\r/g, '');
if (shouldHaveCR) {
res = res.replace(/\n/g, '\r\n');
}
return res;
}
return data;
}
/**
* @param {number} line
* @param {number} column
*/
function reportNewlineError(line, column) {
// Creating a node manually helps us to point to empty lines.
const node = postcss.rule({
source: {
start: { line, column, offset: 0 },
input: new postcss.Input(''),
},
});
report({
message: messages.expected(primary),
node,
result,
ruleName,
});
}
};
};
rule.ruleName = ruleName;
rule.messages = messages;
module.exports = rule;