blob: d55b01afaf1fbee9b1fe2554ca212174a25f9ca5 [file] [log] [blame]
'use strict';
const assignDisabledRanges = require('./assignDisabledRanges');
const getOsEol = require('./utils/getOsEol');
const reportUnknownRuleNames = require('./reportUnknownRuleNames');
const rulesOrder = require('./rules');
/** @typedef {import('stylelint').LinterOptions} LinterOptions */
/** @typedef {import('stylelint').PostcssResult} PostcssResult */
/** @typedef {import('stylelint').Config} StylelintConfig */
/**
* @param {LinterOptions} stylelintOptions
* @param {PostcssResult} postcssResult
* @param {StylelintConfig} config
* @returns {Promise<any>}
*/
function lintPostcssResult(stylelintOptions, postcssResult, config) {
postcssResult.stylelint.ruleSeverities = {};
postcssResult.stylelint.customMessages = {};
postcssResult.stylelint.stylelintError = false;
postcssResult.stylelint.quiet = config.quiet;
postcssResult.stylelint.config = config;
/** @type {string | undefined} */
let newline;
const postcssDoc = postcssResult.root;
if (postcssDoc) {
if (!('type' in postcssDoc)) {
throw new Error('Unexpected Postcss root object!');
}
const newlineMatch = postcssDoc.source && postcssDoc.source.input.css.match(/\r?\n/);
newline = newlineMatch ? newlineMatch[0] : getOsEol();
assignDisabledRanges(postcssDoc, postcssResult);
}
const isFileFixCompatible = isFixCompatible(postcssResult);
if (!isFileFixCompatible) {
postcssResult.stylelint.disableWritingFix = true;
}
const postcssRoots = /** @type {import('postcss').Root[]} */ (
postcssDoc && postcssDoc.constructor.name === 'Document' ? postcssDoc.nodes : [postcssDoc]
);
// Promises for the rules. Although the rule code runs synchronously now,
// the use of Promises makes it compatible with the possibility of async
// rules down the line.
/** @type {Array<Promise<any>>} */
const performRules = [];
const rules = config.rules
? Object.keys(config.rules).sort(
(a, b) => Object.keys(rulesOrder).indexOf(a) - Object.keys(rulesOrder).indexOf(b),
)
: [];
rules.forEach((ruleName) => {
const ruleFunction =
rulesOrder[ruleName] || (config.pluginFunctions && config.pluginFunctions[ruleName]);
if (ruleFunction === undefined) {
performRules.push(
Promise.all(
postcssRoots.map((postcssRoot) =>
reportUnknownRuleNames(ruleName, postcssRoot, postcssResult),
),
),
);
return;
}
const ruleSettings = config.rules && config.rules[ruleName];
if (ruleSettings === null || ruleSettings[0] === null) {
return;
}
const primaryOption = ruleSettings[0];
const secondaryOptions = ruleSettings[1];
// Log the rule's severity in the PostCSS result
const defaultSeverity = config.defaultSeverity || 'error';
// disableFix in secondary option
const disableFix = (secondaryOptions && secondaryOptions.disableFix === true) || false;
if (disableFix) {
postcssResult.stylelint.ruleDisableFix = true;
}
postcssResult.stylelint.ruleSeverities[ruleName] =
(secondaryOptions && secondaryOptions.severity) || defaultSeverity;
postcssResult.stylelint.customMessages[ruleName] = secondaryOptions && secondaryOptions.message;
performRules.push(
Promise.all(
postcssRoots.map((postcssRoot) =>
ruleFunction(primaryOption, secondaryOptions, {
fix:
!disableFix &&
stylelintOptions.fix &&
// Next two conditionals are temporary measures until #2643 is resolved
isFileFixCompatible &&
!postcssResult.stylelint.disabledRanges[ruleName],
newline,
})(postcssRoot, postcssResult),
),
),
);
});
return Promise.all(performRules);
}
/**
* There are currently some bugs in the autofixer of Stylelint.
* The autofixer does not yet adhere to stylelint-disable comments, so if there are disabled
* ranges we can not autofix this document. More info in issue #2643.
*
* @param {PostcssResult} postcssResult
* @returns {boolean}
*/
function isFixCompatible({ stylelint }) {
// Check for issue #2643
if (stylelint.disabledRanges.all.length) return false;
return true;
}
module.exports = lintPostcssResult;