Skip to content

Commit 1dbb323

Browse files
authored
feat: use eslint-compat-utils to support eslint v9 (#62)
not flat config yet
1 parent e6774db commit 1dbb323

39 files changed

+198
-107
lines changed

.changeset/nine-pans-press.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"eslint-plugin-import-x": patch
3+
---
4+
5+
feat: use eslint-compat-utils to support eslint v9 (not flat config yet)

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,13 @@
4545
"watch": "yarn test --watch"
4646
},
4747
"peerDependencies": {
48-
"eslint": "^7.2.0 || ^8"
48+
"eslint": "^7.2.0 || ^8 || ^9.0.0-0"
4949
},
5050
"dependencies": {
5151
"@typescript-eslint/utils": "^5.62.0",
5252
"debug": "^4.3.4",
5353
"doctrine": "^3.0.0",
54+
"eslint-compat-utils": "^0.5.0",
5455
"eslint-import-resolver-node": "^0.3.9",
5556
"get-tsconfig": "^4.7.3",
5657
"is-glob": "^4.0.3",
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
diff --git a/node_modules/eslint-compat-utils/dist/index.d.ts b/node_modules/eslint-compat-utils/dist/index.d.ts
2+
index 993098a..ccb61ad 100644
3+
--- a/node_modules/eslint-compat-utils/dist/index.d.ts
4+
+++ b/node_modules/eslint-compat-utils/dist/index.d.ts
5+
@@ -1,21 +1,23 @@
6+
-import { Rule, SourceCode } from 'eslint';
7+
+import { TSESLint } from '@typescript-eslint/utils'
8+
+
9+
+type RuleContext = TSESLint.RuleContext<string, readonly unknown[]>
10+
11+
/**
12+
* Returns an extended instance of `context.sourceCode` or the result of `context.getSourceCode()`.
13+
* Extended instances can use new APIs such as `getScope(node)` even with old ESLint.
14+
*/
15+
-declare function getSourceCode(context: Rule.RuleContext): SourceCode;
16+
+declare function getSourceCode(context: RuleContext): TSESLint.SourceCode;
17+
18+
/**
19+
* Gets the value of `context.cwd`, but for older ESLint it returns the result of `context.getCwd()`.
20+
* Versions older than v6.6.0 return a value from the result of `process.cwd()`.
21+
*/
22+
-declare function getCwd(context: Rule.RuleContext): string;
23+
+declare function getCwd(context: RuleContext): string;
24+
25+
/**
26+
* Gets the value of `context.filename`, but for older ESLint it returns the result of `context.getFilename()`.
27+
*/
28+
-declare function getFilename(context: Rule.RuleContext): string;
29+
+declare function getFilename(context: RuleContext): string;
30+
31+
/**
32+
* Gets the value of `context.physicalFilename`,
33+
@@ -23,6 +25,6 @@ declare function getFilename(context: Rule.RuleContext): string;
34+
* Versions older than v7.28.0 return a value guessed from the result of `context.getFilename()`,
35+
* but it may be incorrect.
36+
*/
37+
-declare function getPhysicalFilename(context: Rule.RuleContext): string;
38+
+declare function getPhysicalFilename(context: RuleContext): string;
39+
40+
export { getCwd, getFilename, getPhysicalFilename, getSourceCode };

src/rules/consistent-type-specifier-style.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { TSESLint, TSESTree } from '@typescript-eslint/utils'
2+
import { getSourceCode } from 'eslint-compat-utils'
23

34
import { createRule } from '../utils'
45

@@ -73,7 +74,7 @@ export = createRule<[Options?], MessageId>({
7374
},
7475
defaultOptions: [],
7576
create(context) {
76-
const sourceCode = context.getSourceCode()
77+
const sourceCode = getSourceCode(context)
7778

7879
if (context.options[0] === 'prefer-inline') {
7980
return {

src/rules/dynamic-import-chunkname.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import vm from 'node:vm'
22

33
import type { TSESTree } from '@typescript-eslint/utils'
4+
import { getSourceCode } from 'eslint-compat-utils'
45

56
import { createRule } from '../utils'
67

@@ -74,7 +75,7 @@ export = createRule<[Options?], MessageId>({
7475
const chunkSubstrRegex = new RegExp(chunkSubstrFormat)
7576

7677
function run(node: TSESTree.Node, arg: TSESTree.Node) {
77-
const sourceCode = context.getSourceCode()
78+
const sourceCode = getSourceCode(context)
7879
const leadingComments = sourceCode.getCommentsBefore(arg)
7980

8081
if ((!leadingComments || leadingComments.length === 0) && !allowEmpty) {

src/rules/first.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import type { TSESLint, TSESTree } from '@typescript-eslint/utils'
2+
import { getSourceCode } from 'eslint-compat-utils'
23

4+
import type { RuleContext } from '../types'
35
import { createRule } from '../utils'
46

57
function getImportValue(node: TSESTree.ProgramStatement) {
@@ -51,7 +53,7 @@ export = createRule<['absolute-first'?], MessageId>({
5153
}
5254

5355
const absoluteFirst = context.options[0] === 'absolute-first'
54-
const sourceCode = context.getSourceCode()
56+
const sourceCode = getSourceCode(context)
5557
const originSourceCode = sourceCode.getText()
5658

5759
let nonImportCount = 0
@@ -95,7 +97,12 @@ export = createRule<['absolute-first'?], MessageId>({
9597
}
9698

9799
if (nonImportCount > 0) {
98-
for (const variable of context.getDeclaredVariables(node)) {
100+
/**
101+
* @see https://eslint.org/docs/next/use/migrate-to-9.0.0#-removed-multiple-context-methods
102+
*/
103+
for (const variable of (
104+
sourceCode as unknown as RuleContext
105+
).getDeclaredVariables(node)) {
99106
if (!shouldSort) {
100107
break
101108
}

src/rules/named.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import path from 'node:path'
22

33
import type { TSESTree } from '@typescript-eslint/utils'
4+
import { getFilename, getPhysicalFilename } from 'eslint-compat-utils'
45

56
import { ExportMap, createRule } from '../utils'
67
import type { ModuleOptions } from '../utils'
@@ -97,11 +98,7 @@ export = createRule<[ModuleOptions?], MessageId>({
9798
const deepPath = deepLookup.path
9899
.map(i =>
99100
path.relative(
100-
path.dirname(
101-
context.getPhysicalFilename
102-
? context.getPhysicalFilename()
103-
: context.getFilename(),
104-
),
101+
path.dirname(getPhysicalFilename(context)),
105102
i.path,
106103
),
107104
)
@@ -200,7 +197,7 @@ export = createRule<[ModuleOptions?], MessageId>({
200197
if (deepLookup.path.length > 1) {
201198
const deepPath = deepLookup.path
202199
.map(i =>
203-
path.relative(path.dirname(context.getFilename()), i.path),
200+
path.relative(path.dirname(getFilename(context)), i.path),
204201
)
205202
.join(' -> ')
206203

src/rules/namespace.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ export = createRule<[Options], MessageId>({
152152

153153
// same as above, but does not add names to local map
154154
ExportNamespaceSpecifier(namespace) {
155-
const declaration = importDeclaration(context)
155+
const declaration = importDeclaration(context, namespace)
156156

157157
const imports = ExportMap.get(declaration.source.value, context)
158158
if (imports == null) {
@@ -186,7 +186,10 @@ export = createRule<[Options], MessageId>({
186186
return
187187
}
188188

189-
if (declaredScope(context, dereference.object.name) !== 'module') {
189+
if (
190+
declaredScope(context, dereference, dereference.object.name) !==
191+
'module'
192+
) {
190193
return
191194
}
192195

@@ -249,7 +252,9 @@ export = createRule<[Options], MessageId>({
249252
}
250253
},
251254

252-
VariableDeclarator({ id, init }) {
255+
VariableDeclarator(node) {
256+
const { id, init } = node
257+
253258
if (init == null) {
254259
return
255260
}
@@ -261,7 +266,7 @@ export = createRule<[Options], MessageId>({
261266
}
262267

263268
// check for redefinition in intermediate scopes
264-
if (declaredScope(context, init.name) !== 'module') {
269+
if (declaredScope(context, node, init.name) !== 'module') {
265270
return
266271
}
267272

src/rules/newline-after-import.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44

55
import type { TSESLint, TSESTree } from '@typescript-eslint/utils'
66
import debug from 'debug'
7+
import { getPhysicalFilename } from 'eslint-compat-utils'
78

8-
import { isStaticRequire, createRule } from '../utils'
9+
import { isStaticRequire, createRule, getScope } from '../utils'
910

1011
const log = debug('eslint-plugin-import-x:rules:newline-after-import')
1112

@@ -267,14 +268,9 @@ export = createRule<[Options?], MessageId>({
267268
requireCalls.push(node)
268269
}
269270
},
270-
'Program:exit'() {
271-
log(
272-
'exit processing for',
273-
context.getPhysicalFilename
274-
? context.getPhysicalFilename()
275-
: context.getFilename(),
276-
)
277-
const scopeBody = getScopeBody(context.getScope())
271+
'Program:exit'(node) {
272+
log('exit processing for', getPhysicalFilename(context))
273+
const scopeBody = getScopeBody(getScope(context, node))
278274

279275
log('got scope:', scopeBody)
280276

src/rules/no-absolute-path.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import path from 'node:path'
22

3+
import { getPhysicalFilename } from 'eslint-compat-utils'
4+
35
import {
46
isAbsolute,
57
createRule,
@@ -35,9 +37,7 @@ export = createRule<[ModuleOptions?], MessageId>({
3537
node: source,
3638
messageId: 'absolute',
3739
fix(fixer) {
38-
const resolvedContext = context.getPhysicalFilename
39-
? context.getPhysicalFilename()
40-
: context.getFilename()
40+
const resolvedContext = getPhysicalFilename(context)
4141
// node.js and web imports work with posix style paths ("/")
4242
let relativePath = path.posix.relative(
4343
path.dirname(resolvedContext),

0 commit comments

Comments
 (0)