Skip to content

Commit 1120b9b

Browse files
nzakasmdjermanovic
andauthored
feat: Add loadESLint() API method for v8 (#18098)
* feat: Add loadESLint() API method for v8 refs #18075 * Update docs * Add tests for loadESLint() to return ESLint * Move static property out of constructor for older Node.js versions * Add more tests * Update tests/lib/api.js Co-authored-by: Milos Djermanovic <[email protected]> * Update tests/lib/api.js Co-authored-by: Milos Djermanovic <[email protected]> --------- Co-authored-by: Milos Djermanovic <[email protected]>
1 parent 5b8c363 commit 1120b9b

7 files changed

Lines changed: 151 additions & 4 deletions

File tree

docs/src/integrate/nodejs-api.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,49 @@ The `LoadedFormatter` value is the object to convert the [LintResult] objects to
457457

458458
---
459459

460+
## loadESLint()
461+
462+
The `loadESLint()` function is used for integrations that wish to support both the current configuration system (flat config) and the old configuration system (eslintrc). This function returns the correct `ESLint` class implementation based on the arguments provided:
463+
464+
```js
465+
const { loadESLint } = require("eslint");
466+
467+
// loads the default ESLint that the CLI would use based on process.cwd()
468+
const DefaultESLint = await loadESLint();
469+
470+
// loads the default ESLint that the CLI would use based on the provided cwd
471+
const CwdDefaultESLint = await loadESLint({ cwd: "/foo/bar" });
472+
473+
// loads the flat config version specifically
474+
const FlatESLint = await loadESLint({ useFlatConfig: true });
475+
476+
// loads the legacy version specifically
477+
const LegacyESLint = await loadESLint({ useFlatConfig: false });
478+
```
479+
480+
You can then use the returned constructor to instantiate a new `ESLint` instance, like this:
481+
482+
```js
483+
// loads the default ESLint that the CLI would use based on process.cwd()
484+
const DefaultESLint = await loadESLint();
485+
const eslint = new DefaultESLint();
486+
```
487+
488+
If you're ever unsure which config system the returned constructor uses, check the `configType` property, which is either `"flat"` or `"eslintrc"`:
489+
490+
```js
491+
// loads the default ESLint that the CLI would use based on process.cwd()
492+
const DefaultESLint = await loadESLint();
493+
494+
if (DefaultESLint.configType === "flat") {
495+
// do something specific to flat config
496+
}
497+
```
498+
499+
If you don't need to support both the old and new configuration systems, then it's recommended to just use the `ESLint` constructor directly.
500+
501+
---
502+
460503
## SourceCode
461504

462505
The `SourceCode` type represents the parsed source code that ESLint executes on. It's used internally in ESLint and is also available so that already-parsed code can be used. You can create a new instance of `SourceCode` by passing in the text string representing the code and an abstract syntax tree (AST) in [ESTree](https://github.com/estree/estree) format (including location information, range information, comments, and tokens):

lib/api.js

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,45 @@
99
// Requirements
1010
//-----------------------------------------------------------------------------
1111

12-
const { ESLint } = require("./eslint");
12+
const { ESLint, FlatESLint } = require("./eslint");
13+
const { shouldUseFlatConfig } = require("./eslint/flat-eslint");
1314
const { Linter } = require("./linter");
1415
const { RuleTester } = require("./rule-tester");
1516
const { SourceCode } = require("./source-code");
1617

18+
//-----------------------------------------------------------------------------
19+
// Functions
20+
//-----------------------------------------------------------------------------
21+
22+
/**
23+
* Loads the correct ESLint constructor given the options.
24+
* @param {Object} [options] The options object
25+
* @param {boolean} [options.useFlatConfig] Whether or not to use a flat config
26+
* @param {string} [options.cwd] The current working directory
27+
* @returns {Promise<ESLint|LegacyESLint>} The ESLint constructor
28+
*/
29+
async function loadESLint({ useFlatConfig, cwd = process.cwd() } = {}) {
30+
31+
/*
32+
* Note: The v9.x version of this function doesn't have a cwd option
33+
* because it's not used. It's only used in the v8.x version of this
34+
* function.
35+
*/
36+
37+
const shouldESLintUseFlatConfig = typeof useFlatConfig === "boolean"
38+
? useFlatConfig
39+
: await shouldUseFlatConfig({ cwd });
40+
41+
return shouldESLintUseFlatConfig ? FlatESLint : ESLint;
42+
}
43+
1744
//-----------------------------------------------------------------------------
1845
// Exports
1946
//-----------------------------------------------------------------------------
2047

2148
module.exports = {
2249
Linter,
50+
loadESLint,
2351
ESLint,
2452
RuleTester,
2553
SourceCode

lib/eslint/eslint.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,13 @@ class ESLint {
682682
}
683683
}
684684

685+
/**
686+
* The type of configuration used by this class.
687+
* @type {string}
688+
* @static
689+
*/
690+
ESLint.configType = "eslintrc";
691+
685692
//------------------------------------------------------------------------------
686693
// Public Interface
687694
//------------------------------------------------------------------------------

lib/eslint/flat-eslint.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,11 +1116,20 @@ class FlatESLint {
11161116
}
11171117
}
11181118

1119+
/**
1120+
* The type of configuration used by this class.
1121+
* @type {string}
1122+
* @static
1123+
*/
1124+
FlatESLint.configType = "flat";
1125+
11191126
/**
11201127
* Returns whether flat config should be used.
1128+
* @param {Object} [options] The options for this function.
1129+
* @param {string} [options.cwd] The current working directory.
11211130
* @returns {Promise<boolean>} Whether flat config should be used.
11221131
*/
1123-
async function shouldUseFlatConfig() {
1132+
async function shouldUseFlatConfig({ cwd = process.cwd() } = {}) {
11241133
switch (process.env.ESLINT_USE_FLAT_CONFIG) {
11251134
case "true":
11261135
return true;
@@ -1132,7 +1141,7 @@ async function shouldUseFlatConfig() {
11321141
* If neither explicitly enabled nor disabled, then use the presence
11331142
* of a flat config file to determine enablement.
11341143
*/
1135-
return !!(await findFlatConfigFile(process.cwd()));
1144+
return !!(await findFlatConfigFile(cwd));
11361145
}
11371146
}
11381147

tests/lib/api.js

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,20 @@
1010
//-----------------------------------------------------------------------------
1111

1212
const assert = require("chai").assert,
13-
api = require("../../lib/api");
13+
api = require("../../lib/api"),
14+
{ FlatESLint } = require("../../lib/eslint"),
15+
os = require("os");
1416

1517
//-----------------------------------------------------------------------------
1618
// Tests
1719
//-----------------------------------------------------------------------------
1820

1921
describe("api", () => {
2022

23+
it("should have ESLint exposed", () => {
24+
assert.isFunction(api.ESLint);
25+
});
26+
2127
it("should have RuleTester exposed", () => {
2228
assert.isFunction(api.RuleTester);
2329
});
@@ -37,4 +43,49 @@ describe("api", () => {
3743
it("should have SourceCode exposed", () => {
3844
assert.isFunction(api.SourceCode);
3945
});
46+
47+
describe("loadESLint", () => {
48+
49+
afterEach(() => {
50+
delete process.env.ESLINT_USE_FLAT_CONFIG;
51+
});
52+
53+
it("should be a function", () => {
54+
assert.isFunction(api.loadESLint);
55+
});
56+
57+
it("should return a Promise", () => {
58+
assert.instanceOf(api.loadESLint(), Promise);
59+
});
60+
61+
it("should return FlatESLint when useFlatConfig is true", async () => {
62+
assert.strictEqual(await api.loadESLint({ useFlatConfig: true }), FlatESLint);
63+
});
64+
65+
it("should return ESLint when useFlatConfig is false", async () => {
66+
assert.strictEqual(await api.loadESLint({ useFlatConfig: false }), api.ESLint);
67+
});
68+
69+
it("should return FlatESLint when useFlatConfig is not provided because we have eslint.config.js", async () => {
70+
assert.strictEqual(await api.loadESLint(), FlatESLint);
71+
});
72+
73+
it("should return ESLint when useFlatConfig is not provided and there is no eslint.config.js", async () => {
74+
assert.strictEqual(await api.loadESLint({
75+
cwd: os.tmpdir()
76+
}), api.ESLint);
77+
});
78+
79+
it("should return ESLint when useFlatConfig is not provided and ESLINT_USE_FLAT_CONFIG is false", async () => {
80+
process.env.ESLINT_USE_FLAT_CONFIG = "false";
81+
assert.strictEqual(await api.loadESLint(), api.ESLint);
82+
});
83+
84+
it("should return FlatESLint when useFlatConfig is not provided and ESLINT_USE_FLAT_CONFIG is true", async () => {
85+
process.env.ESLINT_USE_FLAT_CONFIG = "true";
86+
assert.strictEqual(await api.loadESLint(), FlatESLint);
87+
});
88+
89+
});
90+
4091
});

tests/lib/eslint/eslint.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ describe("ESLint", () => {
114114
});
115115

116116
describe("ESLint constructor function", () => {
117+
118+
it("should have a static property indicating the configType being used", () => {
119+
assert.strictEqual(ESLint.configType, "eslintrc");
120+
});
121+
117122
it("the default value of 'options.cwd' should be the current working directory.", async () => {
118123
process.chdir(__dirname);
119124
try {

tests/lib/eslint/flat-eslint.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,10 @@ describe("FlatESLint", () => {
128128
});
129129

130130
describe("ESLint constructor function", () => {
131+
it("should have a static property indicating the configType being used", () => {
132+
assert.strictEqual(FlatESLint.configType, "flat");
133+
});
134+
131135
it("the default value of 'options.cwd' should be the current working directory.", async () => {
132136
process.chdir(__dirname);
133137
try {

0 commit comments

Comments
 (0)