blob: 99e78f64f9a8b12c284bd136227fc14fc6c8a6aa [file] [log] [blame]
Tim van der Lippeefb716a2020-12-01 12:54:04 +00001'use strict';
2
3const assignDisabledRanges = require('./assignDisabledRanges');
Tim van der Lippeefb716a2020-12-01 12:54:04 +00004const getOsEol = require('./utils/getOsEol');
5const reportUnknownRuleNames = require('./reportUnknownRuleNames');
6const rulesOrder = require('./rules');
7
Tim van der Lippe16b82282021-11-08 13:50:26 +00008/** @typedef {import('stylelint').LinterOptions} LinterOptions */
Tim van der Lippeefb716a2020-12-01 12:54:04 +00009/** @typedef {import('stylelint').PostcssResult} PostcssResult */
Tim van der Lippe16b82282021-11-08 13:50:26 +000010/** @typedef {import('stylelint').Config} StylelintConfig */
Tim van der Lippeefb716a2020-12-01 12:54:04 +000011
12/**
Tim van der Lippe16b82282021-11-08 13:50:26 +000013 * @param {LinterOptions} stylelintOptions
Tim van der Lippeefb716a2020-12-01 12:54:04 +000014 * @param {PostcssResult} postcssResult
15 * @param {StylelintConfig} config
16 * @returns {Promise<any>}
17 */
18function lintPostcssResult(stylelintOptions, postcssResult, config) {
19 postcssResult.stylelint.ruleSeverities = {};
20 postcssResult.stylelint.customMessages = {};
21 postcssResult.stylelint.stylelintError = false;
22 postcssResult.stylelint.quiet = config.quiet;
23 postcssResult.stylelint.config = config;
24
Tim van der Lippe16b82282021-11-08 13:50:26 +000025 /** @type {string | undefined} */
Tim van der Lippeefb716a2020-12-01 12:54:04 +000026 let newline;
27 const postcssDoc = postcssResult.root;
28
29 if (postcssDoc) {
30 if (!('type' in postcssDoc)) {
31 throw new Error('Unexpected Postcss root object!');
32 }
33
Tim van der Lippeefb716a2020-12-01 12:54:04 +000034 const newlineMatch = postcssDoc.source && postcssDoc.source.input.css.match(/\r?\n/);
35
36 newline = newlineMatch ? newlineMatch[0] : getOsEol();
37
38 assignDisabledRanges(postcssDoc, postcssResult);
39 }
40
Tim van der Lippeefb716a2020-12-01 12:54:04 +000041 const isFileFixCompatible = isFixCompatible(postcssResult);
42
43 if (!isFileFixCompatible) {
44 postcssResult.stylelint.disableWritingFix = true;
45 }
46
Tim van der Lippe16b82282021-11-08 13:50:26 +000047 const postcssRoots = /** @type {import('postcss').Root[]} */ (
48 postcssDoc && postcssDoc.constructor.name === 'Document' ? postcssDoc.nodes : [postcssDoc]
49 );
Tim van der Lippeefb716a2020-12-01 12:54:04 +000050
51 // Promises for the rules. Although the rule code runs synchronously now,
52 // the use of Promises makes it compatible with the possibility of async
53 // rules down the line.
54 /** @type {Array<Promise<any>>} */
55 const performRules = [];
56
57 const rules = config.rules
58 ? Object.keys(config.rules).sort(
59 (a, b) => Object.keys(rulesOrder).indexOf(a) - Object.keys(rulesOrder).indexOf(b),
60 )
61 : [];
62
Tim van der Lippe4cb09742022-01-07 14:25:03 +010063 for (const ruleName of rules) {
Tim van der Lippe16b82282021-11-08 13:50:26 +000064 const ruleFunction =
65 rulesOrder[ruleName] || (config.pluginFunctions && config.pluginFunctions[ruleName]);
Tim van der Lippeefb716a2020-12-01 12:54:04 +000066
67 if (ruleFunction === undefined) {
68 performRules.push(
69 Promise.all(
70 postcssRoots.map((postcssRoot) =>
71 reportUnknownRuleNames(ruleName, postcssRoot, postcssResult),
72 ),
73 ),
74 );
75
Tim van der Lippe4cb09742022-01-07 14:25:03 +010076 continue;
Tim van der Lippeefb716a2020-12-01 12:54:04 +000077 }
78
Tim van der Lippe16b82282021-11-08 13:50:26 +000079 const ruleSettings = config.rules && config.rules[ruleName];
Tim van der Lippeefb716a2020-12-01 12:54:04 +000080
81 if (ruleSettings === null || ruleSettings[0] === null) {
Tim van der Lippe4cb09742022-01-07 14:25:03 +010082 continue;
Tim van der Lippeefb716a2020-12-01 12:54:04 +000083 }
84
85 const primaryOption = ruleSettings[0];
86 const secondaryOptions = ruleSettings[1];
87
88 // Log the rule's severity in the PostCSS result
89 const defaultSeverity = config.defaultSeverity || 'error';
Tim van der Lippe16b82282021-11-08 13:50:26 +000090 // disableFix in secondary option
91 const disableFix = (secondaryOptions && secondaryOptions.disableFix === true) || false;
Tim van der Lippeefb716a2020-12-01 12:54:04 +000092
Tim van der Lippe16b82282021-11-08 13:50:26 +000093 if (disableFix) {
94 postcssResult.stylelint.ruleDisableFix = true;
95 }
96
97 postcssResult.stylelint.ruleSeverities[ruleName] =
98 (secondaryOptions && secondaryOptions.severity) || defaultSeverity;
99 postcssResult.stylelint.customMessages[ruleName] = secondaryOptions && secondaryOptions.message;
Tim van der Lippeefb716a2020-12-01 12:54:04 +0000100
101 performRules.push(
102 Promise.all(
103 postcssRoots.map((postcssRoot) =>
104 ruleFunction(primaryOption, secondaryOptions, {
105 fix:
Tim van der Lippe16b82282021-11-08 13:50:26 +0000106 !disableFix &&
Tim van der Lippeefb716a2020-12-01 12:54:04 +0000107 stylelintOptions.fix &&
108 // Next two conditionals are temporary measures until #2643 is resolved
109 isFileFixCompatible &&
110 !postcssResult.stylelint.disabledRanges[ruleName],
111 newline,
112 })(postcssRoot, postcssResult),
113 ),
114 ),
115 );
Tim van der Lippe4cb09742022-01-07 14:25:03 +0100116 }
Tim van der Lippeefb716a2020-12-01 12:54:04 +0000117
118 return Promise.all(performRules);
119}
120
121/**
122 * There are currently some bugs in the autofixer of Stylelint.
123 * The autofixer does not yet adhere to stylelint-disable comments, so if there are disabled
124 * ranges we can not autofix this document. More info in issue #2643.
125 *
126 * @param {PostcssResult} postcssResult
127 * @returns {boolean}
128 */
129function isFixCompatible({ stylelint }) {
130 // Check for issue #2643
131 if (stylelint.disabledRanges.all.length) return false;
132
133 return true;
134}
135
136module.exports = lintPostcssResult;