diff options
Diffstat (limited to 'tools/eslint/lib/linter.js')
-rwxr-xr-x | tools/eslint/lib/linter.js | 78 |
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 |