Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use eslint-compat-utils to support eslint v9 #62

Merged
merged 2 commits into from
Mar 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/nine-pans-press.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"eslint-plugin-import-x": patch
---

feat: use eslint-compat-utils to support eslint v9 (not flat config yet)
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,13 @@
"watch": "yarn test --watch"
},
"peerDependencies": {
"eslint": "^7.2.0 || ^8"
"eslint": "^7.2.0 || ^8 || ^9.0.0-0"
},
"dependencies": {
"@typescript-eslint/utils": "^5.62.0",
"debug": "^4.3.4",
"doctrine": "^3.0.0",
"eslint-compat-utils": "^0.5.0",
"eslint-import-resolver-node": "^0.3.9",
"get-tsconfig": "^4.7.3",
"is-glob": "^4.0.3",
Expand Down
40 changes: 40 additions & 0 deletions patches/eslint-compat-utils+0.5.0.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
diff --git a/node_modules/eslint-compat-utils/dist/index.d.ts b/node_modules/eslint-compat-utils/dist/index.d.ts
index 993098a..ccb61ad 100644
--- a/node_modules/eslint-compat-utils/dist/index.d.ts
+++ b/node_modules/eslint-compat-utils/dist/index.d.ts
@@ -1,21 +1,23 @@
-import { Rule, SourceCode } from 'eslint';
+import { TSESLint } from '@typescript-eslint/utils'
+
+type RuleContext = TSESLint.RuleContext<string, readonly unknown[]>

/**
* Returns an extended instance of `context.sourceCode` or the result of `context.getSourceCode()`.
* Extended instances can use new APIs such as `getScope(node)` even with old ESLint.
*/
-declare function getSourceCode(context: Rule.RuleContext): SourceCode;
+declare function getSourceCode(context: RuleContext): TSESLint.SourceCode;

/**
* Gets the value of `context.cwd`, but for older ESLint it returns the result of `context.getCwd()`.
* Versions older than v6.6.0 return a value from the result of `process.cwd()`.
*/
-declare function getCwd(context: Rule.RuleContext): string;
+declare function getCwd(context: RuleContext): string;

/**
* Gets the value of `context.filename`, but for older ESLint it returns the result of `context.getFilename()`.
*/
-declare function getFilename(context: Rule.RuleContext): string;
+declare function getFilename(context: RuleContext): string;

/**
* Gets the value of `context.physicalFilename`,
@@ -23,6 +25,6 @@ declare function getFilename(context: Rule.RuleContext): string;
* Versions older than v7.28.0 return a value guessed from the result of `context.getFilename()`,
* but it may be incorrect.
*/
-declare function getPhysicalFilename(context: Rule.RuleContext): string;
+declare function getPhysicalFilename(context: RuleContext): string;

export { getCwd, getFilename, getPhysicalFilename, getSourceCode };
3 changes: 2 additions & 1 deletion src/rules/consistent-type-specifier-style.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { TSESLint, TSESTree } from '@typescript-eslint/utils'
import { getSourceCode } from 'eslint-compat-utils'

import { createRule } from '../utils'

Expand Down Expand Up @@ -73,7 +74,7 @@ export = createRule<[Options?], MessageId>({
},
defaultOptions: [],
create(context) {
const sourceCode = context.getSourceCode()
const sourceCode = getSourceCode(context)

if (context.options[0] === 'prefer-inline') {
return {
Expand Down
3 changes: 2 additions & 1 deletion src/rules/dynamic-import-chunkname.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import vm from 'node:vm'

import type { TSESTree } from '@typescript-eslint/utils'
import { getSourceCode } from 'eslint-compat-utils'

import { createRule } from '../utils'

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

function run(node: TSESTree.Node, arg: TSESTree.Node) {
const sourceCode = context.getSourceCode()
const sourceCode = getSourceCode(context)
const leadingComments = sourceCode.getCommentsBefore(arg)

if ((!leadingComments || leadingComments.length === 0) && !allowEmpty) {
Expand Down
11 changes: 9 additions & 2 deletions src/rules/first.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { TSESLint, TSESTree } from '@typescript-eslint/utils'
import { getSourceCode } from 'eslint-compat-utils'

import type { RuleContext } from '../types'
import { createRule } from '../utils'

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

const absoluteFirst = context.options[0] === 'absolute-first'
const sourceCode = context.getSourceCode()
const sourceCode = getSourceCode(context)
const originSourceCode = sourceCode.getText()

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

if (nonImportCount > 0) {
for (const variable of context.getDeclaredVariables(node)) {
/**
* @see https://eslint.org/docs/next/use/migrate-to-9.0.0#-removed-multiple-context-methods
*/
for (const variable of (
sourceCode as unknown as RuleContext
).getDeclaredVariables(node)) {
if (!shouldSort) {
break
}
Expand Down
9 changes: 3 additions & 6 deletions src/rules/named.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import path from 'node:path'

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

import { ExportMap, createRule } from '../utils'
import type { ModuleOptions } from '../utils'
Expand Down Expand Up @@ -97,11 +98,7 @@ export = createRule<[ModuleOptions?], MessageId>({
const deepPath = deepLookup.path
.map(i =>
path.relative(
path.dirname(
context.getPhysicalFilename
? context.getPhysicalFilename()
: context.getFilename(),
),
path.dirname(getPhysicalFilename(context)),
i.path,
),
)
Expand Down Expand Up @@ -200,7 +197,7 @@ export = createRule<[ModuleOptions?], MessageId>({
if (deepLookup.path.length > 1) {
const deepPath = deepLookup.path
.map(i =>
path.relative(path.dirname(context.getFilename()), i.path),
path.relative(path.dirname(getFilename(context)), i.path),
)
.join(' -> ')

Expand Down
13 changes: 9 additions & 4 deletions src/rules/namespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ export = createRule<[Options], MessageId>({

// same as above, but does not add names to local map
ExportNamespaceSpecifier(namespace) {
const declaration = importDeclaration(context)
const declaration = importDeclaration(context, namespace)

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

if (declaredScope(context, dereference.object.name) !== 'module') {
if (
declaredScope(context, dereference, dereference.object.name) !==
'module'
) {
return
}

Expand Down Expand Up @@ -249,7 +252,9 @@ export = createRule<[Options], MessageId>({
}
},

VariableDeclarator({ id, init }) {
VariableDeclarator(node) {
const { id, init } = node

if (init == null) {
return
}
Expand All @@ -261,7 +266,7 @@ export = createRule<[Options], MessageId>({
}

// check for redefinition in intermediate scopes
if (declaredScope(context, init.name) !== 'module') {
if (declaredScope(context, node, init.name) !== 'module') {
return
}

Expand Down
14 changes: 5 additions & 9 deletions src/rules/newline-after-import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@

import type { TSESLint, TSESTree } from '@typescript-eslint/utils'
import debug from 'debug'
import { getPhysicalFilename } from 'eslint-compat-utils'

import { isStaticRequire, createRule } from '../utils'
import { isStaticRequire, createRule, getScope } from '../utils'

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

Expand Down Expand Up @@ -267,14 +268,9 @@ export = createRule<[Options?], MessageId>({
requireCalls.push(node)
}
},
'Program:exit'() {
log(
'exit processing for',
context.getPhysicalFilename
? context.getPhysicalFilename()
: context.getFilename(),
)
const scopeBody = getScopeBody(context.getScope())
'Program:exit'(node) {
log('exit processing for', getPhysicalFilename(context))
const scopeBody = getScopeBody(getScope(context, node))

log('got scope:', scopeBody)

Expand Down
6 changes: 3 additions & 3 deletions src/rules/no-absolute-path.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import path from 'node:path'

import { getPhysicalFilename } from 'eslint-compat-utils'

import {
isAbsolute,
createRule,
Expand Down Expand Up @@ -35,9 +37,7 @@ export = createRule<[ModuleOptions?], MessageId>({
node: source,
messageId: 'absolute',
fix(fixer) {
const resolvedContext = context.getPhysicalFilename
? context.getPhysicalFilename()
: context.getFilename()
const resolvedContext = getPhysicalFilename(context)
// node.js and web imports work with posix style paths ("/")
let relativePath = path.posix.relative(
path.dirname(resolvedContext),
Expand Down
4 changes: 2 additions & 2 deletions src/rules/no-amd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Rule to prefer imports to AMD
*/

import { createRule } from '../utils'
import { createRule, getScope } from '../utils'

type MessageId = 'amd'

Expand All @@ -23,7 +23,7 @@ export = createRule<[], MessageId>({
create(context) {
return {
CallExpression(node) {
if (context.getScope().type !== 'module') {
if (getScope(context, node).type !== 'module') {
return
}

Expand Down
10 changes: 5 additions & 5 deletions src/rules/no-commonjs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import type { TSESLint, TSESTree } from '@typescript-eslint/utils'

import { createRule } from '../utils'
import { createRule, getScope } from '../utils'

type NormalizedOptions = {
allowPrimitiveModules?: boolean
Expand Down Expand Up @@ -122,16 +122,16 @@ export = createRule<[Options?], MessageId>({

// exports.
if ('name' in node.object && node.object.name === 'exports') {
const isInScope = context
.getScope()
.variables.some(variable => variable.name === 'exports')
const isInScope = getScope(context, node).variables.some(
variable => variable.name === 'exports',
)
if (!isInScope) {
context.report({ node, messageId: 'export' })
}
}
},
CallExpression(call) {
if (!validateScope(context.getScope())) {
if (!validateScope(getScope(context, call))) {
return
}

Expand Down
6 changes: 3 additions & 3 deletions src/rules/no-cycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
* Ensures that no imported module imports the linted module.
*/

import { getPhysicalFilename } from 'eslint-compat-utils'

import type { DeclarationMetadata, ModuleOptions } from '../utils'
import {
ExportMap,
Expand Down Expand Up @@ -70,9 +72,7 @@ export = createRule<[Options?], MessageId>({
},
defaultOptions: [],
create(context) {
const filename = context.getPhysicalFilename
? context.getPhysicalFilename()
: context.getFilename()
const filename = getPhysicalFilename(context)

if (filename === '<text>') {
return {}
Expand Down
6 changes: 4 additions & 2 deletions src/rules/no-default-export.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { getSourceCode } from 'eslint-compat-utils'

import { createRule } from '../utils'

export = createRule({
Expand All @@ -24,7 +26,7 @@ export = createRule({

return {
ExportDefaultDeclaration(node) {
const { loc } = context.getSourceCode().getFirstTokens(node)[1] || {}
const { loc } = getSourceCode(context).getFirstTokens(node)[1] || {}
context.report({
node,
messageId: 'preferNamed',
Expand All @@ -39,7 +41,7 @@ export = createRule({
('value' in specifier.exported && specifier.exported.value)) ===
'default',
)) {
const { loc } = context.getSourceCode().getFirstTokens(node)[1] || {}
const { loc } = getSourceCode(context).getFirstTokens(node)[1] || {}
// @ts-expect-error - legacy parser type
if (specifier.type === 'ExportDefaultSpecifier') {
context.report({
Expand Down
7 changes: 5 additions & 2 deletions src/rules/no-deprecated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export = createRule({
return
}

if (declaredScope(context, node.name) !== 'module') {
if (declaredScope(context, node, node.name) !== 'module') {
return
}
context.report({
Expand All @@ -165,7 +165,10 @@ export = createRule({
return
}

if (declaredScope(context, dereference.object.name) !== 'module') {
if (
declaredScope(context, dereference, dereference.object.name) !==
'module'
) {
return
}

Expand Down
3 changes: 2 additions & 1 deletion src/rules/no-duplicates.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { TSESLint, TSESTree } from '@typescript-eslint/utils'
import { getSourceCode } from 'eslint-compat-utils'
import semver from 'semver'
import type { PackageJson } from 'type-fest'

Expand Down Expand Up @@ -28,7 +29,7 @@ function checkImports(
for (const [module, nodes] of imported.entries()) {
if (nodes.length > 1) {
const [first, ...rest] = nodes
const sourceCode = context.getSourceCode()
const sourceCode = getSourceCode(context)
const fix = getFix(first, rest, sourceCode, context)

context.report({
Expand Down
3 changes: 2 additions & 1 deletion src/rules/no-empty-named-blocks.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { TSESTree } from '@typescript-eslint/utils'
import { getSourceCode } from 'eslint-compat-utils'

import { createRule } from '../utils'

Expand Down Expand Up @@ -103,7 +104,7 @@ export = createRule({
fix(fixer) {
// Remove the empty block and the 'from' token, leaving the import only for its side
// effects, e.g. `import 'mod'`
const sourceCode = context.getSourceCode()
const sourceCode = getSourceCode(context)
const fromToken = pTokens.find(t => t.value === 'from')!
const importToken = pTokens.find(
t => t.value === 'import',
Expand Down
Loading
Loading