summaryrefslogtreecommitdiff
path: root/tools/node_modules/eslint/lib/util/source-code-fixer.js
diff options
context:
space:
mode:
Diffstat (limited to 'tools/node_modules/eslint/lib/util/source-code-fixer.js')
-rw-r--r--tools/node_modules/eslint/lib/util/source-code-fixer.js152
1 files changed, 152 insertions, 0 deletions
diff --git a/tools/node_modules/eslint/lib/util/source-code-fixer.js b/tools/node_modules/eslint/lib/util/source-code-fixer.js
new file mode 100644
index 0000000000..b5bfc7457a
--- /dev/null
+++ b/tools/node_modules/eslint/lib/util/source-code-fixer.js
@@ -0,0 +1,152 @@
+/**
+ * @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;