Skip to content

Commit 3ec436e

Browse files
gyandeepsnot-an-aardvark
authored andcommitted
Breaking: New Linter API (fixes #8454) (#8465)
1 parent 3fc9653 commit 3ec436e

36 files changed

+1842
-1689
lines changed

Makefile.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -757,13 +757,14 @@ target.browserify = function() {
757757
generateRulesIndex(TEMP_DIR);
758758

759759
// 5. browserify the temp directory
760-
nodeCLI.exec("browserify", "-x espree", `${TEMP_DIR}eslint.js`, "-o", `${BUILD_DIR}eslint.js`, "-s eslint", "--global-transform [ babelify --presets [ es2015 ] ]");
760+
nodeCLI.exec("browserify", "-x espree", `${TEMP_DIR}linter.js`, "-o", `${BUILD_DIR}eslint.js`, "-s eslint", "--global-transform [ babelify --presets [ es2015 ] ]");
761+
nodeCLI.exec("browserify", "-x espree", `${TEMP_DIR}rules.js`, "-o", `${TEMP_DIR}rules.js`, "-s rules", "--global-transform [ babelify --presets [ es2015 ] ]");
761762

762763
// 6. Browserify espree
763764
nodeCLI.exec("browserify", "-r espree", "-o", `${TEMP_DIR}espree.js`);
764765

765766
// 7. Concatenate Babel polyfill, Espree, and ESLint files together
766-
cat("./node_modules/babel-polyfill/dist/polyfill.js", `${TEMP_DIR}espree.js`, `${BUILD_DIR}eslint.js`).to(`${BUILD_DIR}eslint.js`);
767+
cat("./node_modules/babel-polyfill/dist/polyfill.js", `${TEMP_DIR}espree.js`, `${BUILD_DIR}eslint.js`, `${TEMP_DIR}rules.js`).to(`${BUILD_DIR}eslint.js`);
767768

768769
// 8. remove temp directory
769770
rm("-r", TEMP_DIR);

conf/eslint-all.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
//------------------------------------------------------------------------------
1111

1212
const load = require("../lib/load-rules"),
13-
rules = require("../lib/rules");
13+
Rules = require("../lib/rules");
14+
const rules = new Rules();
1415

1516
//------------------------------------------------------------------------------
1617
// Helpers

docs/developer-guide/nodejs-api.md

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,16 @@ var codeLines = SourceCode.splitLines(code);
4949
*/
5050
```
5151

52-
## linter
52+
## Linter
5353

54-
The `linter` object does the actual evaluation of the JavaScript code. It doesn't do any filesystem operations, it simply parses and reports on the code. In particular, the `linter` object does not process configuration objects or files. You can retrieve `linter` like this:
54+
The `Linter` object does the actual evaluation of the JavaScript code. It doesn't do any filesystem operations, it simply parses and reports on the code. In particular, the `Linter` object does not process configuration objects or files. You can retrieve instances of `Linter` like this:
5555

5656
```js
57-
var linter = require("eslint").linter;
57+
var Linter = require("eslint").Linter;
58+
var linter = new Linter();
5859
```
5960

60-
The most important method on `linter` is `verify()`, which initiates linting of the given text. This method accepts four arguments:
61+
The most important method on `Linter` is `verify()`, which initiates linting of the given text. This method accepts four arguments:
6162

6263
* `code` - the source code to lint (a string or instance of `SourceCode`).
6364
* `config` - a configuration object that has been processed and normalized by CLIEngine using eslintrc files and/or other configuration arguments.
@@ -71,7 +72,8 @@ The most important method on `linter` is `verify()`, which initiates linting of
7172
You can call `verify()` like this:
7273

7374
```js
74-
var linter = require("eslint").linter;
75+
var Linter = require("eslint").Linter;
76+
var linter = new Linter();
7577

7678
var messages = linter.verify("var foo;", {
7779
rules: {
@@ -129,7 +131,8 @@ The information available for each linting message is:
129131
You can also get an instance of the `SourceCode` object used inside of `linter` by using the `getSourceCode()` method:
130132

131133
```js
132-
var linter = require("eslint").linter;
134+
var Linter = require("eslint").Linter;
135+
var linter = new Linter();
133136

134137
var messages = linter.verify("var foo = bar;", {
135138
rules: {
@@ -144,6 +147,22 @@ console.log(code.text); // "var foo = bar;"
144147

145148
In this way, you can retrieve the text and AST used for the last run of `linter.verify()`.
146149

150+
## linter
151+
152+
The `eslint.linter` object (deprecated) is an instance of the `Linter` class as defined [above](#Linter). `eslint.linter` exists for backwards compatibility, but we do not recommend using it because any mutations to it are shared among every module that uses `eslint`. Instead, please create your own instance of `eslint.Linter`.
153+
154+
```js
155+
var linter = require("eslint").linter;
156+
157+
var messages = linter.verify("var foo;", {
158+
rules: {
159+
semi: 2
160+
}
161+
}, { filename: "foo.js" });
162+
```
163+
164+
Note: This API is deprecated as of 4.0.0.
165+
147166
## CLIEngine
148167

149168
The primary Node.js API is `CLIEngine`, which is the underlying utility that runs the ESLint command line interface. This object will read the filesystem for configuration and file information but will not output any results. Instead, it allows you direct access to the important information so you can deal with the output yourself.
@@ -566,3 +585,4 @@ CLIEngine.outputFixes(report);
566585
## Deprecated APIs
567586

568587
* `cli` - the `cli` object has been deprecated in favor of `CLIEngine`. As of v1.0.0, `cli` is no longer exported and should not be used by external tools.
588+
* `linter` - the `linter` object has has been deprecated in favor of `Linter`, as of v4.0.0

lib/api.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55

66
"use strict";
77

8+
const Linter = require("./linter");
9+
810
module.exports = {
9-
linter: require("./eslint"),
11+
linter: new Linter(),
12+
Linter,
1013
CLIEngine: require("./cli-engine"),
1114
RuleTester: require("./testers/rule-tester"),
1215
SourceCode: require("./util/source-code")

lib/cli-engine.js

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,10 @@
1717

1818
const fs = require("fs"),
1919
path = require("path"),
20-
rules = require("./rules"),
21-
eslint = require("./eslint"),
2220
defaultOptions = require("../conf/default-cli-options"),
21+
Linter = require("./linter"),
2322
IgnoredPaths = require("./ignored-paths"),
2423
Config = require("./config"),
25-
Plugins = require("./config/plugins"),
2624
fileEntryCache = require("file-entry-cache"),
2725
globUtil = require("./util/glob-util"),
2826
SourceCodeFixer = require("./util/source-code-fixer"),
@@ -143,11 +141,12 @@ function calculateStatsPerRun(results) {
143141
* @param {string} options.filename The filename from which the text was read.
144142
* @param {boolean} options.allowInlineConfig Flag indicating if inline comments
145143
* should be allowed.
144+
* @param {Linter} linter Linter context
146145
* @returns {Object} The result of the fix operation as returned from the
147146
* SourceCodeFixer.
148147
* @private
149148
*/
150-
function multipassFix(text, config, options) {
149+
function multipassFix(text, config, options, linter) {
151150
const MAX_PASSES = 10;
152151
let messages = [],
153152
fixedResult,
@@ -167,10 +166,10 @@ function multipassFix(text, config, options) {
167166
passNumber++;
168167

169168
debug(`Linting code for ${options.filename} (pass ${passNumber})`);
170-
messages = eslint.verify(text, config, options);
169+
messages = linter.verify(text, config, options);
171170

172171
debug(`Generating fixed text for ${options.filename} (pass ${passNumber})`);
173-
fixedResult = SourceCodeFixer.applyFixes(eslint.getSourceCode(), messages);
172+
fixedResult = SourceCodeFixer.applyFixes(linter.getSourceCode(), messages);
174173

175174
// stop if there are any syntax errors.
176175
// 'fixedResult.output' is a empty string.
@@ -195,7 +194,7 @@ function multipassFix(text, config, options) {
195194
* the most up-to-date information.
196195
*/
197196
if (fixedResult.fixed) {
198-
fixedResult.messages = eslint.verify(text, config, options);
197+
fixedResult.messages = linter.verify(text, config, options);
199198
}
200199

201200

@@ -214,13 +213,14 @@ function multipassFix(text, config, options) {
214213
* @param {string} filename An optional string representing the texts filename.
215214
* @param {boolean} fix Indicates if fixes should be processed.
216215
* @param {boolean} allowInlineConfig Allow/ignore comments that change config.
216+
* @param {Linter} linter Linter context
217217
* @returns {LintResult} The results for linting on this text.
218218
* @private
219219
*/
220-
function processText(text, configHelper, filename, fix, allowInlineConfig) {
220+
function processText(text, configHelper, filename, fix, allowInlineConfig, linter) {
221221

222222
// clear all existing settings for a new file
223-
eslint.reset();
223+
linter.reset();
224224

225225
let filePath,
226226
messages,
@@ -238,10 +238,10 @@ function processText(text, configHelper, filename, fix, allowInlineConfig) {
238238
const config = configHelper.getConfig(filePath);
239239

240240
if (config.plugins) {
241-
Plugins.loadAll(config.plugins);
241+
configHelper.plugins.loadAll(config.plugins);
242242
}
243243

244-
const loadedPlugins = Plugins.getAll();
244+
const loadedPlugins = configHelper.plugins.getAll();
245245

246246
for (const plugin in loadedPlugins) {
247247
if (loadedPlugins[plugin].processors && Object.keys(loadedPlugins[plugin].processors).indexOf(fileExtension) >= 0) {
@@ -256,7 +256,7 @@ function processText(text, configHelper, filename, fix, allowInlineConfig) {
256256
const unprocessedMessages = [];
257257

258258
parsedBlocks.forEach(block => {
259-
unprocessedMessages.push(eslint.verify(block, config, {
259+
unprocessedMessages.push(linter.verify(block, config, {
260260
filename,
261261
allowInlineConfig
262262
}));
@@ -272,10 +272,10 @@ function processText(text, configHelper, filename, fix, allowInlineConfig) {
272272
fixedResult = multipassFix(text, config, {
273273
filename,
274274
allowInlineConfig
275-
});
275+
}, linter);
276276
messages = fixedResult.messages;
277277
} else {
278-
messages = eslint.verify(text, config, {
278+
messages = linter.verify(text, config, {
279279
filename,
280280
allowInlineConfig
281281
});
@@ -310,13 +310,14 @@ function processText(text, configHelper, filename, fix, allowInlineConfig) {
310310
* @param {string} filename The filename of the file being checked.
311311
* @param {Object} configHelper The configuration options for ESLint.
312312
* @param {Object} options The CLIEngine options object.
313+
* @param {Linter} linter Linter context
313314
* @returns {LintResult} The results for linting on this file.
314315
* @private
315316
*/
316-
function processFile(filename, configHelper, options) {
317+
function processFile(filename, configHelper, options, linter) {
317318

318319
const text = fs.readFileSync(path.resolve(filename), "utf8"),
319-
result = processText(text, configHelper, filename, options.fix, options.allowInlineConfig);
320+
result = processText(text, configHelper, filename, options.fix, options.allowInlineConfig, linter);
320321

321322
return result;
322323

@@ -471,6 +472,7 @@ class CLIEngine {
471472
* @type {Object}
472473
*/
473474
this.options = options;
475+
this.linter = new Linter();
474476

475477
const cacheFile = getCacheFile(this.options.cacheLocation || this.options.cacheFile, this.options.cwd);
476478

@@ -488,13 +490,15 @@ class CLIEngine {
488490

489491
this.options.rulePaths.forEach(rulesdir => {
490492
debug(`Loading rules from ${rulesdir}`);
491-
rules.load(rulesdir, cwd);
493+
this.linter.rules.load(rulesdir, cwd);
492494
});
493495
}
494496

495497
Object.keys(this.options.rules || {}).forEach(name => {
496-
validator.validateRuleOptions(name, this.options.rules[name], "CLI");
498+
validator.validateRuleOptions(name, this.options.rules[name], "CLI", this.linter.rules);
497499
});
500+
501+
this.config = new Config(this.options, this.linter);
498502
}
499503

500504
/**
@@ -542,8 +546,8 @@ class CLIEngine {
542546
* @param {Object} pluginobject Plugin configuration object.
543547
* @returns {void}
544548
*/
545-
addPlugin(name, pluginobject) { // eslint-disable-line class-methods-use-this
546-
Plugins.define(name, pluginobject);
549+
addPlugin(name, pluginobject) {
550+
this.config.plugins.define(name, pluginobject);
547551
}
548552

549553
/**
@@ -565,7 +569,7 @@ class CLIEngine {
565569
const results = [],
566570
options = this.options,
567571
fileCache = this._fileCache,
568-
configHelper = new Config(options);
572+
configHelper = this.config;
569573
let prevConfig; // the previous configuration used
570574

571575
/**
@@ -602,9 +606,10 @@ class CLIEngine {
602606
* unsupported file extensions and any files that are already linted.
603607
* @param {string} filename The resolved filename of the file to be linted
604608
* @param {boolean} warnIgnored always warn when a file is ignored
609+
* @param {Linter} linter Linter context
605610
* @returns {void}
606611
*/
607-
function executeOnFile(filename, warnIgnored) {
612+
function executeOnFile(filename, warnIgnored, linter) {
608613
let hashOfConfig,
609614
descriptor;
610615

@@ -647,7 +652,7 @@ class CLIEngine {
647652

648653
debug(`Processing ${filename}`);
649654

650-
const res = processFile(filename, configHelper, options);
655+
const res = processFile(filename, configHelper, options, linter);
651656

652657
if (options.cache) {
653658

@@ -685,7 +690,7 @@ class CLIEngine {
685690
const fileList = globUtil.listFilesToProcess(patterns, options);
686691

687692
fileList.forEach(fileInfo => {
688-
executeOnFile(fileInfo.filename, fileInfo.ignored);
693+
executeOnFile(fileInfo.filename, fileInfo.ignored, this.linter);
689694
});
690695

691696
const stats = calculateStatsPerRun(results);
@@ -718,7 +723,7 @@ class CLIEngine {
718723

719724
const results = [],
720725
options = this.options,
721-
configHelper = new Config(options),
726+
configHelper = this.config,
722727
ignoredPaths = new IgnoredPaths(options);
723728

724729
// resolve filename based on options.cwd (for reporting, ignoredPaths also resolves)
@@ -731,7 +736,7 @@ class CLIEngine {
731736
results.push(createIgnoreResult(filename, options.cwd));
732737
}
733738
} else {
734-
results.push(processText(text, configHelper, filename, options.fix, options.allowInlineConfig));
739+
results.push(processText(text, configHelper, filename, options.fix, options.allowInlineConfig, this.linter));
735740
}
736741

737742
const stats = calculateStatsPerRun(results);
@@ -753,7 +758,7 @@ class CLIEngine {
753758
* @returns {Object} A configuration object for the file.
754759
*/
755760
getConfigForFile(filePath) {
756-
const configHelper = new Config(this.options);
761+
const configHelper = this.config;
757762

758763
return configHelper.getConfig(filePath);
759764
}

0 commit comments

Comments
 (0)