Spaces:
Runtime error
Runtime error
/** | |
* @fileoverview An object that caches and applies source code fixes. | |
* @author Nicholas C. Zakas | |
*/ | |
; | |
//------------------------------------------------------------------------------ | |
// Requirements | |
//------------------------------------------------------------------------------ | |
const debug = require("debug")("eslint:source-code-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 (Object.prototype.hasOwnProperty.call(problem, "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; | |