core/converters/edit.converter.ts
core/converters/edit.converter.ts is a file in GovLab Quality. 55 lines of code and 14 definitions.
import type { CuratedApplyResult, CuratedResult, CuratedSuggestion, RangeFix } from "#types/edit.types";
import { CURATED_SUGGESTIONS } from "#configuration/constants/eslint.constants";
import type { Linter } from "eslint";
const entryFor = function entryFor(message: Linter.LintMessage): CuratedSuggestion | null {
return (
CURATED_SUGGESTIONS.find(
(entry) =>
message.ruleId === entry.ruleId && (entry.messageId === null || message.messageId === entry.messageId),
) ?? null
);
};
const chosenFix = function chosenFix(message: Linter.LintMessage, entry: CuratedSuggestion): RangeFix | null {
const suggestions = message.suggestions ?? [];
if (entry.pick === "sole") {
const [only] = suggestions;
return suggestions.length === 1 && only !== undefined ? { range: only.fix.range, text: only.fix.text } : null;
}
const picked = suggestions.find((suggestion) => suggestion.fix.text.trimStart().startsWith(entry.prefix));
return picked === undefined ? null : { range: picked.fix.range, text: picked.fix.text };
};
const overlaps = function overlaps(a: RangeFix, b: RangeFix): boolean {
return a.range[0] < b.range[1] && b.range[0] < a.range[1];
};
const applyRangeFixes = function applyRangeFixes(source: string, fixes: readonly RangeFix[]): string {
const applied: RangeFix[] = [];
let out = source;
for (const fix of fixes.toSorted((a, b) => b.range[0] - a.range[0])) {
if (!applied.some((prior) => overlaps(prior, fix))) {
applied.push(fix);
out = out.slice(0, fix.range[0]) + fix.text + out.slice(fix.range[1]);
}
}
return out;
};
export const applyCuratedSuggestions = function applyCuratedSuggestions(
result: CuratedResult,
source: string,
): CuratedApplyResult | null {
const consumed = new Set<Linter.LintMessage>();
const fixes: RangeFix[] = [];
for (const message of result.messages) {
const entry = entryFor(message);
const fix = entry === null ? null : chosenFix(message, entry);
if (fix !== null) {
fixes.push(fix);
consumed.add(message);
}
}
if (fixes.length === 0) {
return null;
}
result.messages = result.messages.filter((message) => !consumed.has(message));
result.errorCount -= consumed.size;
return { appliedCount: consumed.size, output: applyRangeFixes(source, fixes) };
};