Skip to content

Commit 77af4b4

Browse files
authored
Improve compatibility with ESLint v9 (take2) (#2338)
1 parent 0b2edb7 commit 77af4b4

File tree

6 files changed

+113
-26
lines changed

6 files changed

+113
-26
lines changed

lib/rules/jsx-uses-vars.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ SOFTWARE.
3030
*/
3131
'use strict'
3232

33+
const utils = require('../utils')
34+
3335
module.exports = {
3436
// eslint-disable-next-line eslint-plugin/prefer-message-ids
3537
meta: {
@@ -63,7 +65,7 @@ module.exports = {
6365
return
6466
}
6567

66-
context.markVariableAsUsed(name)
68+
utils.markVariableAsUsed(context, name, node)
6769
}
6870
}
6971
}

lib/rules/script-setup-uses-vars.js

+13-7
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,10 @@ module.exports = {
3939
if (!utils.isScriptSetup(context)) {
4040
return {}
4141
}
42+
const sourceCode = context.getSourceCode()
4243
/** @type {Set<string>} */
4344
const scriptVariableNames = new Set()
44-
const globalScope = context.getSourceCode().scopeManager.globalScope
45+
const globalScope = sourceCode.scopeManager.globalScope
4546
if (globalScope) {
4647
for (const variable of globalScope.variables) {
4748
scriptVariableNames.add(variable.name)
@@ -54,23 +55,28 @@ module.exports = {
5455
}
5556
}
5657

58+
/** @param {string} name */
59+
function markVariableAsUsed(name) {
60+
utils.markVariableAsUsed(context, name, sourceCode.ast)
61+
}
62+
5763
/**
5864
* @see https://github.com/vuejs/vue-next/blob/2749c15170ad4913e6530a257db485d4e7ed2283/packages/compiler-core/src/transforms/transformElement.ts#L333
5965
* @param {string} name
6066
*/
6167
function markSetupReferenceVariableAsUsed(name) {
6268
if (scriptVariableNames.has(name)) {
63-
context.markVariableAsUsed(name)
69+
markVariableAsUsed(name)
6470
return true
6571
}
6672
const camelName = camelize(name)
6773
if (scriptVariableNames.has(camelName)) {
68-
context.markVariableAsUsed(camelName)
74+
markVariableAsUsed(camelName)
6975
return true
7076
}
7177
const pascalName = casing.capitalize(camelName)
7278
if (scriptVariableNames.has(pascalName)) {
73-
context.markVariableAsUsed(pascalName)
79+
markVariableAsUsed(pascalName)
7480
return true
7581
}
7682
return false
@@ -83,7 +89,7 @@ module.exports = {
8389
for (const ref of node.references.filter(
8490
(ref) => ref.variable == null
8591
)) {
86-
context.markVariableAsUsed(ref.id.name)
92+
markVariableAsUsed(ref.id.name)
8793
}
8894
},
8995
VElement(node) {
@@ -115,7 +121,7 @@ module.exports = {
115121
/** @param {VAttribute} node */
116122
'VAttribute[directive=false]'(node) {
117123
if (node.key.name === 'ref' && node.value) {
118-
context.markVariableAsUsed(node.value.value)
124+
markVariableAsUsed(node.value.value)
119125
}
120126
}
121127
},
@@ -124,7 +130,7 @@ module.exports = {
124130
const styleVars = getStyleVariablesContext(context)
125131
if (styleVars) {
126132
for (const ref of styleVars.references) {
127-
context.markVariableAsUsed(ref.id.name)
133+
markVariableAsUsed(ref.id.name)
128134
}
129135
}
130136
}

lib/utils/index.js

+35-8
Original file line numberDiff line numberDiff line change
@@ -245,10 +245,12 @@ function wrapContextToOverrideTokenMethods(context, tokenStore, options) {
245245
tokenStore
246246
)
247247

248+
/** @type {WeakMap<ASTNode, import('eslint').Scope.ScopeManager>} */
248249
const containerScopes = new WeakMap()
249250

250251
/**
251252
* @param {ASTNode} node
253+
* @returns {import('eslint').Scope.ScopeManager|null}
252254
*/
253255
function getContainerScope(node) {
254256
const exprContainer = getVExpressionContainer(node)
@@ -260,9 +262,11 @@ function wrapContextToOverrideTokenMethods(context, tokenStore, options) {
260262
return cache
261263
}
262264
const programNode = eslintSourceCode.ast
263-
const parserOptions = context.parserOptions || {}
265+
const parserOptions =
266+
context.languageOptions?.parserOptions ?? context.parserOptions ?? {}
264267
const ecmaFeatures = parserOptions.ecmaFeatures || {}
265-
const ecmaVersion = parserOptions.ecmaVersion || 2020
268+
const ecmaVersion =
269+
context.languageOptions?.ecmaVersion ?? parserOptions.ecmaVersion ?? 2020
266270
const sourceType = programNode.sourceType
267271
try {
268272
const eslintScope = createRequire(require.resolve('eslint'))(
@@ -297,7 +301,6 @@ function wrapContextToOverrideTokenMethods(context, tokenStore, options) {
297301
getSourceCode() {
298302
return sourceCode
299303
},
300-
// @ts-expect-error -- Added in ESLint v8.40
301304
get sourceCode() {
302305
return sourceCode
303306
},
@@ -310,11 +313,11 @@ function wrapContextToOverrideTokenMethods(context, tokenStore, options) {
310313
*/
311314
function getDeclaredVariables(node) {
312315
const scope = getContainerScope(node)
313-
if (scope) {
314-
return scope.getDeclaredVariables(node)
315-
}
316-
317-
return context.getDeclaredVariables(node)
316+
return (
317+
scope?.getDeclaredVariables?.(node) ??
318+
context.getDeclaredVariables?.(node) ??
319+
[]
320+
)
318321
}
319322
}
320323

@@ -1939,6 +1942,10 @@ module.exports = {
19391942
withinTypeNode,
19401943
findVariableByIdentifier,
19411944
getScope,
1945+
/**
1946+
* Marks a variable with the given name in the current scope as used. This affects the no-unused-vars rule.
1947+
*/
1948+
markVariableAsUsed,
19421949
/**
19431950
* Checks whether the given node is in export default.
19441951
* @param {ASTNode} node
@@ -2562,6 +2569,26 @@ function isTypeScriptFile(path) {
25622569
return path.endsWith('.ts') || path.endsWith('.tsx') || path.endsWith('.mts')
25632570
}
25642571

2572+
// ------------------------------------------------------------------------------
2573+
// ESLint Helpers
2574+
// ------------------------------------------------------------------------------
2575+
/**
2576+
* Marks a variable with the given name in the current scope as used. This affects the no-unused-vars rule.
2577+
* @param {RuleContext} context
2578+
* @param {string} name
2579+
* @param {ASTNode} node The node to get the current scope.
2580+
*/
2581+
function markVariableAsUsed(context, name, node) {
2582+
const sourceCode = context.getSourceCode()
2583+
if (sourceCode.markVariableAsUsed) {
2584+
sourceCode.markVariableAsUsed(name, node)
2585+
} else {
2586+
// This function does not use the given node, but the currently visited node.
2587+
// If we need to determine the scope of a given node, we need to implement it yourself.
2588+
context.markVariableAsUsed?.(name)
2589+
}
2590+
}
2591+
25652592
// ------------------------------------------------------------------------------
25662593
// Vue Helpers
25672594
// ------------------------------------------------------------------------------

tests/lib/rules/jsx-uses-vars.js

+17
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,23 @@ const ruleTester = new RuleTester({
2424
const linter = ruleTester.linter || eslint.linter
2525
linter.defineRule('jsx-uses-vars', rule)
2626

27+
ruleTester.run('jsx-uses-vars', rule, {
28+
// Visually check that there are no warnings in the console.
29+
valid: [
30+
`
31+
import SomeComponent from './SomeComponent.jsx';
32+
export default {
33+
render () {
34+
return (
35+
<SomeComponent msg="Hello world"></SomeComponent>
36+
)
37+
},
38+
};
39+
`
40+
],
41+
invalid: []
42+
})
43+
2744
describe('jsx-uses-vars', () => {
2845
ruleTester.run('no-unused-vars', ruleNoUnusedVars, {
2946
valid: [

tests/lib/rules/script-setup-uses-vars.js

+15
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,21 @@ const ruleTester = new RuleTester({
2323
const linter = ruleTester.linter || eslint.linter
2424
linter.defineRule('script-setup-uses-vars', rule)
2525

26+
ruleTester.run('script-setup-uses-vars', rule, {
27+
// Visually check that there are no warnings in the console.
28+
valid: [
29+
`
30+
<script setup>
31+
import Foo from './Foo.vue'
32+
</script>
33+
34+
<template>
35+
<Foo />
36+
</template>
37+
`
38+
],
39+
invalid: []
40+
})
2641
describe('script-setup-uses-vars', () => {
2742
ruleTester.run('no-unused-vars', ruleNoUnusedVars, {
2843
valid: [

typings/eslint/index.d.ts

+30-10
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ export namespace Scope {
1818
scopes: Scope[]
1919
globalScope: Scope | null
2020
acquire(node: VAST.ESNode | VAST.Program, inner?: boolean): Scope | null
21-
getDeclaredVariables(node: VAST.ESNode): Variable[]
21+
/** @since ESLint v8.38.0 */
22+
getDeclaredVariables?(node: VAST.ESNode): Variable[]
2223
}
2324
interface Scope {
2425
type:
@@ -230,6 +231,11 @@ export class SourceCode /*extends ESLintSourceCode*/ {
230231
getCommentsBefore(nodeOrToken: VNODE.HasLocation): VNODE.Comment[]
231232
getCommentsAfter(nodeOrToken: VNODE.HasLocation): VNODE.Comment[]
232233
getCommentsInside(node: VNODE.HasLocation): VNODE.Comment[]
234+
235+
/** @since ESLint v8.39.0 */
236+
markVariableAsUsed?(name: string, node?: VNODE.HasLocation): void
237+
/** @since ESLint v8.37.0 */
238+
getScope?(node: VNODE.HasLocation): Scope.Scope
233239
}
234240
export namespace SourceCode {
235241
interface Config {
@@ -317,21 +323,35 @@ export namespace Rule {
317323
id: string
318324
options: ESLintRule.RuleContext['options']
319325
settings: { [name: string]: any }
320-
parserPath: string
321-
parserOptions: any
322-
parserServices: parserServices.ParserServices
323-
324-
getAncestors(): VAST.ESNode[]
325-
326-
getDeclaredVariables(node: VAST.ESNode): Scope.Variable[]
326+
/** @deprecated removed in ESLint v10? */
327+
parserPath?: string
328+
/** @deprecated removed in ESLint v10? */
329+
parserOptions?: ESLintLinter.ParserOptions
330+
/** For flat config */
331+
languageOptions?: ESLintLinter.FlatConfig['languageOptions']
332+
/** @deprecated removed in ESLint v9 */
333+
parserServices?: parserServices.ParserServices
334+
335+
/** @deprecated removed in ESLint v9 */
336+
getAncestors?(): VAST.ESNode[]
337+
/** @deprecated removed in ESLint v9 */
338+
getDeclaredVariables?(node: VAST.ESNode): Scope.Variable[]
327339
getFilename(): string
328-
getScope(): Scope.Scope
340+
/** @since ESLint v8.40.0 */
341+
filename?: string
342+
/** @deprecated removed in ESLint v9 */
343+
getScope?(): Scope.Scope
329344
getSourceCode(): SourceCode
330-
markVariableAsUsed(name: string): boolean
345+
/** @since ESLint v8.40.0 */
346+
sourceCode?: SourceCode
347+
/** @deprecated removed in ESLint v9 */
348+
markVariableAsUsed?(name: string): boolean
331349
report(descriptor: ReportDescriptor): void
332350

333351
// eslint@6 does not have this method.
334352
getCwd?: () => string
353+
/** @since ESLint v8.40.0 */
354+
cwd?: string
335355
}
336356

337357
type ReportDescriptor =

0 commit comments

Comments
 (0)