Skip to content

Commit c2cd7b4

Browse files
nzakasbtmills
andauthored
New: Add ESLint#getRulesMetaForResults() (refs #13654) (#14716)
* New: Add ESLint#getRulesMetaForResults() (refs #13654) * Update docs * Update docs/developer-guide/nodejs-api.md Co-authored-by: Brandon Mills <btmills@users.noreply.github.com> Co-authored-by: Brandon Mills <btmills@users.noreply.github.com>
1 parent eea7e0d commit c2cd7b4

3 files changed

Lines changed: 129 additions & 0 deletions

File tree

docs/developer-guide/nodejs-api.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ While ESLint is designed to be run on the command line, it's possible to use ESL
1010
* [constructor()][eslint-constructor]
1111
* [lintFiles()][eslint-lintfiles]
1212
* [lintText()][eslint-linttext]
13+
* [getRulesMetaForResults()](eslint-getrulesmetaforresults)
1314
* [calculateConfigForFile()][eslint-calculateconfigforfile]
1415
* [isPathIgnored()][eslint-ispathignored]
1516
* [loadFormatter()][eslint-loadformatter]
@@ -205,6 +206,25 @@ The second parameter `options` is omittable.
205206
* (`Promise<LintResult[]>`)<br>
206207
The promise that will be fulfilled with an array of [LintResult] objects. This is an array (despite there being only one lint result) in order to keep the interfaces between this and the [`eslint.lintFiles()`][eslint-lintfiles] method similar.
207208

209+
### ◆ eslint.getRulesMetaForResults(results)
210+
211+
```js
212+
const results = await eslint.lintFiles(patterns);
213+
const rulesMeta = eslint.getRulesMetaForResults(results);
214+
```
215+
216+
This method returns an object containing meta information for each rule that triggered a lint error in the given `results`.
217+
218+
#### Parameters
219+
220+
* `results` (`LintResult[]`)<br>
221+
An array of [LintResult] objects returned from a call to `ESLint#lintFiles()` or `ESLint#lintText()`.
222+
223+
#### Return Value
224+
225+
* (`Object`)<br>
226+
An object whose property names are the rule IDs from the `results` and whose property values are the rule's meta information (if available).
227+
208228
### ◆ eslint.calculateConfigForFile(filePath)
209229

210230
```js
@@ -1389,6 +1409,7 @@ ruleTester.run("my-rule", myRule, {
13891409
[eslint-constructor]: #-new-eslintoptions
13901410
[eslint-lintfiles]: #-eslintlintfilespatterns
13911411
[eslint-linttext]: #-eslintlinttextcode-options
1412+
[eslint-getrulesmetaforresults]: #-eslintgetrulesmetaforresultsresults
13921413
[eslint-calculateconfigforfile]: #-eslintcalculateconfigforfilefilepath
13931414
[eslint-ispathignored]: #-eslintispathignoredfilepath
13941415
[eslint-loadformatter]: #-eslintloadformatternameorpath

lib/eslint/eslint.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,39 @@ class ESLint {
514514
return CLIEngine.getErrorResults(results);
515515
}
516516

517+
/**
518+
* Returns meta objects for each rule represented in the lint results.
519+
* @param {LintResult[]} results The results to fetch rules meta for.
520+
* @returns {Object} A mapping of ruleIds to rule meta objects.
521+
*/
522+
getRulesMetaForResults(results) {
523+
524+
const resultRuleIds = new Set();
525+
526+
// first gather all ruleIds from all results
527+
528+
for (const result of results) {
529+
for (const { ruleId } of result.messages) {
530+
resultRuleIds.add(ruleId);
531+
}
532+
}
533+
534+
// create a map of all rules in the results
535+
536+
const { cliEngine } = privateMembersMap.get(this);
537+
const rules = cliEngine.getRules();
538+
const resultRules = new Map();
539+
540+
for (const [ruleId, rule] of rules) {
541+
if (resultRuleIds.has(ruleId)) {
542+
resultRules.set(ruleId, rule);
543+
}
544+
}
545+
546+
return createRulesMeta(resultRules);
547+
548+
}
549+
517550
/**
518551
* Executes the current configuration on an array of file and directory names.
519552
* @param {string[]} patterns An array of file and directory names.

tests/lib/eslint/eslint.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const shell = require("shelljs");
2222
const { CascadingConfigArrayFactory } = require("@eslint/eslintrc/lib/cascading-config-array-factory");
2323
const hash = require("../../../lib/cli-engine/hash");
2424
const { unIndent, createCustomTeardown } = require("../../_utils");
25+
const coreRules = require("../../../lib/rules");
2526

2627
//------------------------------------------------------------------------------
2728
// Tests
@@ -4790,6 +4791,80 @@ describe("ESLint", () => {
47904791
});
47914792
});
47924793

4794+
describe("getRulesMetaForResults()", () => {
4795+
it("should return empty object when there are no linting errors", async () => {
4796+
const engine = new ESLint({
4797+
useEslintrc: false
4798+
});
4799+
4800+
const rulesMeta = engine.getRulesMetaForResults([]);
4801+
4802+
assert.strictEqual(Object.keys(rulesMeta).length, 0);
4803+
});
4804+
4805+
it("should return one rule meta when there is a linting error", async () => {
4806+
const engine = new ESLint({
4807+
useEslintrc: false,
4808+
overrideConfig: {
4809+
rules: {
4810+
semi: 2
4811+
}
4812+
}
4813+
});
4814+
4815+
const results = await engine.lintText("a");
4816+
const rulesMeta = engine.getRulesMetaForResults(results);
4817+
4818+
assert.strictEqual(rulesMeta.semi, coreRules.get("semi").meta);
4819+
});
4820+
4821+
it("should return multiple rule meta when there are multiple linting errors", async () => {
4822+
const engine = new ESLint({
4823+
useEslintrc: false,
4824+
overrideConfig: {
4825+
rules: {
4826+
semi: 2,
4827+
quotes: [2, "double"]
4828+
}
4829+
}
4830+
});
4831+
4832+
const results = await engine.lintText("'a'");
4833+
const rulesMeta = engine.getRulesMetaForResults(results);
4834+
4835+
assert.strictEqual(rulesMeta.semi, coreRules.get("semi").meta);
4836+
assert.strictEqual(rulesMeta.quotes, coreRules.get("quotes").meta);
4837+
});
4838+
4839+
it("should return multiple rule meta when there are multiple linting errors from a plugin", async () => {
4840+
const nodePlugin = require("eslint-plugin-node");
4841+
const engine = new ESLint({
4842+
useEslintrc: false,
4843+
plugins: {
4844+
node: nodePlugin
4845+
},
4846+
overrideConfig: {
4847+
plugins: ["node"],
4848+
rules: {
4849+
"node/no-new-require": 2,
4850+
semi: 2,
4851+
quotes: [2, "double"]
4852+
}
4853+
}
4854+
});
4855+
4856+
const results = await engine.lintText("new require('hi')");
4857+
const rulesMeta = engine.getRulesMetaForResults(results);
4858+
4859+
assert.strictEqual(rulesMeta.semi, coreRules.get("semi").meta);
4860+
assert.strictEqual(rulesMeta.quotes, coreRules.get("quotes").meta);
4861+
assert.strictEqual(
4862+
rulesMeta["node/no-new-require"],
4863+
nodePlugin.rules["no-new-require"].meta
4864+
);
4865+
});
4866+
});
4867+
47934868
describe("outputFixes()", () => {
47944869
afterEach(() => {
47954870
sinon.verifyAndRestore();

0 commit comments

Comments
 (0)