summaryrefslogtreecommitdiff
path: root/tools/eslint/lib/linter.js
diff options
context:
space:
mode:
Diffstat (limited to 'tools/eslint/lib/linter.js')
-rwxr-xr-xtools/eslint/lib/linter.js78
1 files changed, 74 insertions, 4 deletions
diff --git a/tools/eslint/lib/linter.js b/tools/eslint/lib/linter.js
index 25af05223d..d2f1f46574 100755
--- a/tools/eslint/lib/linter.js
+++ b/tools/eslint/lib/linter.js
@@ -27,9 +27,11 @@ const assert = require("assert"),
Rules = require("./rules"),
timing = require("./timing"),
astUtils = require("./ast-utils"),
+ pkg = require("../package.json"),
+ SourceCodeFixer = require("./util/source-code-fixer");
- pkg = require("../package.json");
-
+const debug = require("debug")("eslint:linter");
+const MAX_AUTOFIX_PASSES = 10;
//------------------------------------------------------------------------------
// Typedefs
@@ -453,8 +455,8 @@ function normalizeEcmaVersion(ecmaVersion, isModule) {
*/
function prepareConfig(config, envContext) {
config.globals = config.globals || {};
- const copiedRules = Object.assign({}, defaultConfig.rules);
- let parserOptions = Object.assign({}, defaultConfig.parserOptions);
+ const copiedRules = {};
+ let parserOptions = {};
if (typeof config.rules === "object") {
Object.keys(config.rules).forEach(k => {
@@ -1185,6 +1187,74 @@ class Linter extends EventEmitter {
getDeclaredVariables(node) {
return (this.scopeManager && this.scopeManager.getDeclaredVariables(node)) || [];
}
+
+ /**
+ * Performs multiple autofix passes over the text until as many fixes as possible
+ * have been applied.
+ * @param {string} text The source text to apply fixes to.
+ * @param {Object} config The ESLint config object to use.
+ * @param {Object} options The ESLint options object to use.
+ * @param {string} options.filename The filename from which the text was read.
+ * @param {boolean} options.allowInlineConfig Flag indicating if inline comments
+ * should be allowed.
+ * @returns {Object} The result of the fix operation as returned from the
+ * SourceCodeFixer.
+ */
+ verifyAndFix(text, config, options) {
+ let messages = [],
+ fixedResult,
+ fixed = false,
+ passNumber = 0;
+
+ /**
+ * This loop continues until one of the following is true:
+ *
+ * 1. No more fixes have been applied.
+ * 2. Ten passes have been made.
+ *
+ * That means anytime a fix is successfully applied, there will be another pass.
+ * Essentially, guaranteeing a minimum of two passes.
+ */
+ do {
+ passNumber++;
+
+ debug(`Linting code for ${options.filename} (pass ${passNumber})`);
+ messages = this.verify(text, config, options);
+
+ debug(`Generating fixed text for ${options.filename} (pass ${passNumber})`);
+ fixedResult = SourceCodeFixer.applyFixes(this.getSourceCode(), messages);
+
+ // stop if there are any syntax errors.
+ // 'fixedResult.output' is a empty string.
+ if (messages.length === 1 && messages[0].fatal) {
+ break;
+ }
+
+ // keep track if any fixes were ever applied - important for return value
+ fixed = fixed || fixedResult.fixed;
+
+ // update to use the fixed output instead of the original text
+ text = fixedResult.output;
+
+ } while (
+ fixedResult.fixed &&
+ passNumber < MAX_AUTOFIX_PASSES
+ );
+
+ /*
+ * If the last result had fixes, we need to lint again to be sure we have
+ * the most up-to-date information.
+ */
+ if (fixedResult.fixed) {
+ fixedResult.messages = this.verify(text, config, options);
+ }
+
+ // ensure the last result properly reflects if fixes were done
+ fixedResult.fixed = fixed;
+ fixedResult.output = text;
+
+ return fixedResult;
+ }
}
// methods that exist on SourceCode object