first commit
This commit is contained in:
202
node_modules/stylelint/lib/utils/report.mjs
generated
vendored
Normal file
202
node_modules/stylelint/lib/utils/report.mjs
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
import { isFunction as isFn, isNumber, isString } from '../utils/validateTypes.mjs';
|
||||
|
||||
import {
|
||||
DEFAULT_SEVERITY,
|
||||
RULE_NAME_ALL,
|
||||
SEVERITY_ERROR,
|
||||
SEVERITY_WARNING,
|
||||
} from '../constants.mjs';
|
||||
|
||||
/** @import { DisabledRangeObject, Problem, Range, RuleMessage, StylelintPostcssResult, Utils, WarningOptions } from 'stylelint' */
|
||||
|
||||
/**
|
||||
* Report a problem.
|
||||
*
|
||||
* This function accounts for `disabledRanges` attached to the result.
|
||||
* That is, if the reported problem is within a disabledRange,
|
||||
* it is ignored. Otherwise, it is attached to the result as a
|
||||
* postcss warning.
|
||||
*
|
||||
* It also accounts for the rule's severity.
|
||||
*
|
||||
* You *must* pass *either* a node or a line number.
|
||||
*
|
||||
* @type {Utils['report']}
|
||||
*/
|
||||
export default function report(problem) {
|
||||
const { node, index, endIndex, line, start, end, result, ruleName, word, fix, ...rest } = problem;
|
||||
const {
|
||||
disabledRanges,
|
||||
quiet,
|
||||
ruleSeverities,
|
||||
config: { defaultSeverity, ignoreDisables } = {},
|
||||
customMessages: { [ruleName]: message = rest.message },
|
||||
customUrls: { [ruleName]: customUrl },
|
||||
ruleMetadata: { [ruleName]: metadata },
|
||||
} = result.stylelint;
|
||||
const { messageArgs = [], severity = ruleSeverities[ruleName] } = rest;
|
||||
const ruleSeverity =
|
||||
(isFn(severity) ? severity(...messageArgs) : severity) ?? defaultSeverity ?? DEFAULT_SEVERITY;
|
||||
|
||||
// In quiet mode, mere warnings are ignored
|
||||
if (quiet && ruleSeverity === SEVERITY_WARNING) return;
|
||||
|
||||
if (isFn(fix) && metadata && !metadata.fixable) {
|
||||
throw new Error(
|
||||
`The "${ruleName}" rule requires "meta.fixable" to be truthy if the "fix" callback is being passed`,
|
||||
);
|
||||
}
|
||||
|
||||
// If a line is not passed, use the node.rangeBy method to get the
|
||||
// line number that the complaint pertains to
|
||||
const startLine = line ?? node?.rangeBy({ index, endIndex }).start.line;
|
||||
|
||||
if (!startLine) {
|
||||
throw new Error(
|
||||
`The "${ruleName}" rule failed to pass either a node or a line number to the \`report()\` function.`,
|
||||
);
|
||||
}
|
||||
|
||||
if (isFixApplied({ ...problem, line: startLine })) return;
|
||||
|
||||
if (isDisabled(ruleName, startLine, disabledRanges)) {
|
||||
// Collect disabled warnings
|
||||
// Used to report `needlessDisables` in subsequent processing.
|
||||
const disabledWarnings = (result.stylelint.disabledWarnings ||= []);
|
||||
|
||||
disabledWarnings.push({
|
||||
rule: ruleName,
|
||||
line: startLine,
|
||||
});
|
||||
|
||||
if (!ignoreDisables) return;
|
||||
}
|
||||
|
||||
if (!result.stylelint.stylelintError && ruleSeverity === SEVERITY_ERROR) {
|
||||
result.stylelint.stylelintError = true;
|
||||
}
|
||||
|
||||
if (!result.stylelint.stylelintWarning && ruleSeverity === SEVERITY_WARNING) {
|
||||
result.stylelint.stylelintWarning = true;
|
||||
}
|
||||
|
||||
/** @type {WarningOptions} */
|
||||
const warningProperties = {
|
||||
severity: ruleSeverity,
|
||||
rule: ruleName,
|
||||
};
|
||||
|
||||
if (node) {
|
||||
warningProperties.node = node;
|
||||
}
|
||||
|
||||
if (start) {
|
||||
warningProperties.start = start;
|
||||
} else if (isNumber(index)) {
|
||||
warningProperties.index = index;
|
||||
}
|
||||
|
||||
if (end) {
|
||||
warningProperties.end = end;
|
||||
} else if (isNumber(endIndex)) {
|
||||
warningProperties.endIndex = endIndex;
|
||||
}
|
||||
|
||||
if (word) {
|
||||
warningProperties.word = word;
|
||||
}
|
||||
|
||||
if (customUrl) {
|
||||
warningProperties.url = customUrl;
|
||||
}
|
||||
|
||||
const warningMessage = buildWarningMessage(message, messageArgs);
|
||||
|
||||
result.warn(warningMessage, warningProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {RuleMessage} message
|
||||
* @param {NonNullable<Problem['messageArgs']>} messageArgs
|
||||
* @returns {string}
|
||||
*/
|
||||
function buildWarningMessage(message, messageArgs) {
|
||||
if (isString(message)) {
|
||||
return printfLike(message, ...messageArgs);
|
||||
}
|
||||
|
||||
return message(...messageArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} format
|
||||
* @param {Array<unknown>} args
|
||||
* @returns {string}
|
||||
*/
|
||||
function printfLike(format, ...args) {
|
||||
return args.reduce((/** @type {string} */ result, arg) => {
|
||||
return result.replace(/%[ds]/, String(arg));
|
||||
}, format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a rule is disabled for a given line
|
||||
* @param {string} ruleName
|
||||
* @param {number} startLine
|
||||
* @param {DisabledRangeObject} disabledRanges
|
||||
*/
|
||||
function isDisabled(ruleName, startLine, disabledRanges) {
|
||||
const ranges = disabledRanges[ruleName] ?? disabledRanges[RULE_NAME_ALL] ?? [];
|
||||
|
||||
for (const range of ranges) {
|
||||
if (
|
||||
// If the problem is within a disabledRange,
|
||||
// and that disabledRange's rules include this one
|
||||
range.start <= startLine &&
|
||||
(range.end === undefined || range.end >= startLine) &&
|
||||
/** @todo populate rules in assignDisabledRanges util */
|
||||
(!range.rules || range.rules.includes(ruleName))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @param {Problem & { line: number }} problem */
|
||||
function isFixApplied({ fix, line, result: { stylelint }, ruleName }) {
|
||||
const { disabledRanges, config = {}, fixersData } = stylelint;
|
||||
|
||||
if (!isFn(fix)) {
|
||||
addFixData({ fixersData, ruleName, fixed: false });
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const shouldFix = Boolean(config.fix && !config.rules?.[ruleName][1]?.disableFix);
|
||||
const mayFix =
|
||||
shouldFix && (config.ignoreDisables || !isDisabled(ruleName, line, disabledRanges));
|
||||
|
||||
addFixData({ fixersData, ruleName, fixed: mayFix });
|
||||
|
||||
if (!mayFix) return false;
|
||||
|
||||
fix();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} o
|
||||
* @param {StylelintPostcssResult['fixersData']} o.fixersData
|
||||
* @param {string} o.ruleName
|
||||
* @param {Range} [o.range]
|
||||
* @param {boolean} o.fixed
|
||||
* @todo stylelint/stylelint#7192
|
||||
*/
|
||||
function addFixData({ fixersData, ruleName, range, fixed }) {
|
||||
const ruleFixers = (fixersData[ruleName] ??= []);
|
||||
|
||||
ruleFixers.push({ range, fixed });
|
||||
}
|
||||
Reference in New Issue
Block a user