| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 | /** * @fileoverview An object that caches and applies source code fixes. * @author Nicholas C. Zakas */"use strict";//------------------------------------------------------------------------------// Requirements//------------------------------------------------------------------------------const debug = require("debug")("eslint:text-fixer");//------------------------------------------------------------------------------// Helpers//------------------------------------------------------------------------------const BOM = "\uFEFF";/** * Compares items in a messages array by range. * @param {Message} a The first message. * @param {Message} b The second message. * @returns {int} -1 if a comes before b, 1 if a comes after b, 0 if equal. * @private */function compareMessagesByFixRange(a, b) {    return a.fix.range[0] - b.fix.range[0] || a.fix.range[1] - b.fix.range[1];}/** * Compares items in a messages array by line and column. * @param {Message} a The first message. * @param {Message} 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) {    return a.line - b.line || a.column - b.column;}//------------------------------------------------------------------------------// Public Interface//------------------------------------------------------------------------------/** * Utility for apply fixes to source code. * @constructor */function SourceCodeFixer() {    Object.freeze(this);}/** * 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 {string} sourceText The text to apply the changes to. * @param {Message[]} messages The array of messages reported by ESLint. * @param {boolean|Function} [shouldFix=true] Determines whether each message should be fixed * @returns {Object} An object containing the fixed text and any unfixed messages. */SourceCodeFixer.applyFixes = function(sourceText, messages, shouldFix) {    debug("Applying fixes");    if (shouldFix === false) {        debug("shouldFix parameter was false, not attempting fixes");        return {            fixed: false,            messages,            output: sourceText        };    }    // clone the array    const remainingMessages = [],        fixes = [],        bom = sourceText.startsWith(BOM) ? BOM : "",        text = bom ? sourceText.slice(1) : sourceText;    let lastPos = Number.NEGATIVE_INFINITY,        output = bom;    /**     * Try to use the 'fix' from a problem.     * @param   {Message} problem The message object to apply fixes from     * @returns {boolean}         Whether fix was successfully applied     */    function attemptFix(problem) {        const fix = problem.fix;        const start = fix.range[0];        const end = fix.range[1];        // Remain it as a problem if it's overlapped or it's a negative range        if (lastPos >= start || start > end) {            remainingMessages.push(problem);            return false;        }        // Remove BOM.        if ((start < 0 && end >= 0) || (start === 0 && fix.text.startsWith(BOM))) {            output = "";        }        // Make output to this fix.        output += text.slice(Math.max(0, lastPos), Math.max(0, start));        output += fix.text;        lastPos = end;        return true;    }    messages.forEach(problem => {        if (problem.hasOwnProperty("fix")) {            fixes.push(problem);        } else {            remainingMessages.push(problem);        }    });    if (fixes.length) {        debug("Found fixes to apply");        let fixesWereApplied = false;        for (const problem of fixes.sort(compareMessagesByFixRange)) {            if (typeof shouldFix !== "function" || shouldFix(problem)) {                attemptFix(problem);                /*                 * The only time attemptFix will fail is if a previous fix was                 * applied which conflicts with it.  So we can mark this as true.                 */                fixesWereApplied = true;            } else {                remainingMessages.push(problem);            }        }        output += text.slice(Math.max(0, lastPos));        return {            fixed: fixesWereApplied,            messages: remainingMessages.sort(compareMessagesByLocation),            output        };    }    debug("No fixes to apply");    return {        fixed: false,        messages,        output: bom + text    };};module.exports = SourceCodeFixer;
 |