Skip to content

Commit

Permalink
Update: Add Fixer method to Linter API
Browse files Browse the repository at this point in the history
  • Loading branch information
gyandeeps committed May 21, 2017
1 parent f62cff6 commit ec37cb3
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 79 deletions.
78 changes: 1 addition & 77 deletions lib/cli-engine.js
Expand Up @@ -23,11 +23,9 @@ const fs = require("fs"),
Config = require("./config"),
fileEntryCache = require("file-entry-cache"),
globUtil = require("./util/glob-util"),
SourceCodeFixer = require("./util/source-code-fixer"),
validator = require("./config/config-validator"),
stringify = require("json-stable-stringify"),
hash = require("./util/hash"),

pkg = require("../package.json");

const debug = require("debug")("eslint:cli-engine");
Expand Down Expand Up @@ -132,80 +130,6 @@ function calculateStatsPerRun(results) {
});
}

/**
* 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.
* @param {Linter} linter Linter context
* @returns {Object} The result of the fix operation as returned from the
* SourceCodeFixer.
* @private
*/
function multipassFix(text, config, options, linter) {
const MAX_PASSES = 10;
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 = linter.verify(text, config, options);

debug(`Generating fixed text for ${options.filename} (pass ${passNumber})`);
fixedResult = SourceCodeFixer.applyFixes(linter.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_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 = linter.verify(text, config, options);
}


// ensure the last result properly reflects if fixes were done
fixedResult.fixed = fixed;
fixedResult.output = text;

return fixedResult;

}

/**
* Processes an source code using ESLint.
* @param {string} text The source code to check.
Expand Down Expand Up @@ -269,7 +193,7 @@ function processText(text, configHelper, filename, fix, allowInlineConfig, linte
} else {

if (fix) {
fixedResult = multipassFix(text, config, {
fixedResult = linter.verifyAndFix(text, config, {
filename,
allowInlineConfig
}, linter);
Expand Down
74 changes: 72 additions & 2 deletions lib/linter.js
Expand Up @@ -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_PASSES = 10;

//------------------------------------------------------------------------------
// Typedefs
Expand Down Expand Up @@ -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_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
Expand Down

0 comments on commit ec37cb3

Please sign in to comment.