@textlint/source-code-fixer
Version:
Apply @textlint/kernel lint result to text.
144 lines • 5.11 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.applyFixesToText = applyFixesToText;
exports.applyFixesToSourceCode = applyFixesToSourceCode;
exports.revertSourceCode = revertSourceCode;
const debug_1 = __importDefault(require("debug"));
const debug = (0, debug_1.default)("textlint:source-code-fixer");
const BOM = "\uFEFF";
/**
* Compares items in a messages array by line and column.
* @param {TextlintMessage} a The first message.
* @param {TextlintMessage} b The second message.
* @returns {int} -1 if a comes before b, 1 if a comes after b, 0 if equal.
* @private
*/
function compareMessagesByLocation(a, b) {
const lineDiff = a.line - b.line;
if (lineDiff === 0) {
return a.column - b.column;
}
else {
return lineDiff;
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function clone(object) {
return JSON.parse(JSON.stringify(object));
}
/**
* Applies the fixes to text and return string
* use applyFixes If you want to use primitive function,
*/
function applyFixesToText(text, messages) {
const hasBOM = text.charCodeAt(0) === 0xfeff;
return applyFixesToSourceCode({
text,
hasBOM
}, messages).output;
}
/**
* Applies the fixes specified by the messages to the given text. Tries to be
* smart about the fixes and won't apply fixes over the same area in the text.
* @param sourceCode The source code to apply the changes to.
* @param messages The array of messages reported by textlint.
* @returns An object containing the fixed text and any unfixed messages.
*/
function applyFixesToSourceCode(sourceCode, messages) {
debug("Applying fixes");
const text = sourceCode.text;
// As as result, show diff
const remainingMessages = [];
const applyingMessages = [];
const cloneMessages = messages.slice();
const fixes = [];
let lastFixPos = text.length;
let prefix = sourceCode.hasBOM ? BOM : "";
cloneMessages.forEach((problem) => {
if (problem && problem.fix !== undefined) {
fixes.push(problem);
}
else {
remainingMessages.push(problem);
}
});
if (fixes.length) {
debug("Found fixes to apply");
// sort in reverse order of occurrence
fixes.sort((a, b) => {
return b.fix.range[1] - a.fix.range[1] || b.fix.range[0] - a.fix.range[0];
});
// split into array of characters for easier manipulation
const chars = text.split(""); // range is code-unit based
fixes.forEach((problem) => {
// pickup fix range
const fix = problem.fix;
let start = fix.range[0];
const end = fix.range[1];
let insertionText = fix.text;
if (end <= lastFixPos) {
if (start < 0) {
// Remove BOM.
prefix = "";
start = 0;
}
if (start === 0 && insertionText[0] === BOM) {
// Set BOM.
prefix = BOM;
insertionText = insertionText.slice(1);
}
const replacedChars = chars.splice(start, end - start, insertionText);
lastFixPos = start;
const copyOfMessage = clone(problem);
copyOfMessage.fix = {
range: [start, start + insertionText.length],
text: replacedChars.join("")
};
applyingMessages.push(copyOfMessage);
}
else {
remainingMessages.push(problem);
}
});
return {
fixed: true,
messages: cloneMessages, // have order
applyingMessages: applyingMessages.reverse(), // have order
remainingMessages: remainingMessages.sort(compareMessagesByLocation), // have not order
output: prefix + chars.join("")
};
}
else {
debug("No fixes to apply");
return {
fixed: false,
messages: cloneMessages,
applyingMessages,
remainingMessages,
output: prefix + text
};
}
}
/**
* revert text using applyingMessages
* @param sourceCode The source code to apply the changes to.
* @param applyingMessages The array of TextLintMessage reported by SourceCodeFixer#applyFixes
* @returns An object containing the fixed text and any unfixed messages.
*/
function revertSourceCode(sourceCode, applyingMessages) {
debug("Restore applied fixes");
let text = sourceCode.text;
applyingMessages.forEach((message) => {
const newSource = {
text,
hasBOM: sourceCode.hasBOM
};
const result = applyFixesToSourceCode(newSource, [message]);
text = result.output;
});
return text;
}
//# sourceMappingURL=source-code-fixer.js.map