Permalink
Cannot retrieve contributors at this time
152 lines (129 sloc)
4.57 KB
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
codeql-action/node_modules/eslint/lib/linter/source-code-fixer.js
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @fileoverview An object that caches and applies source code fixes. | |
* @author Nicholas C. Zakas | |
*/ | |
"use strict"; | |
//------------------------------------------------------------------------------ | |
// 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; |