Spaces:
Runtime error
Runtime error
File size: 4,691 Bytes
4a51346 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
/**
* @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;
|