Skip to content

Commit bb88c01

Browse files
authored
Fix wrong scope reference type for <script setup lang=ts> (#181)
* Fix wrong scope reference type for `<script setup lang=ts>` * update * update
1 parent 5c3558c commit bb88c01

File tree

10 files changed

+277
-64
lines changed

10 files changed

+277
-64
lines changed

Diff for: src/ast/nodes.ts

+4
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,10 @@ export interface Reference {
753753
id: ESLintIdentifier
754754
mode: "rw" | "r" | "w"
755755
variable: Variable | null
756+
757+
// For typescript-eslint
758+
isValueReference?: boolean
759+
isTypeReference?: boolean
756760
}
757761

758762
/**

Diff for: src/script-setup/scope-analyzer.ts

+16-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type * as escopeTypes from "eslint-scope"
22
import type { ParserOptions } from "../common/parser-options"
33
import type {
4+
Reference,
45
VAttribute,
56
VDirective,
67
VDocumentFragment,
@@ -169,7 +170,17 @@ function analyzeUsedInTemplateVariables(
169170
return false
170171
}
171172

172-
function markVariableAsUsed(name: string) {
173+
function markVariableAsUsed(nameOrRef: string | Reference) {
174+
let name: string
175+
let isValueReference: boolean | undefined
176+
let isTypeReference: boolean | undefined
177+
if (typeof nameOrRef === "string") {
178+
name = nameOrRef
179+
} else {
180+
name = nameOrRef.id.name
181+
isValueReference = nameOrRef.isValueReference
182+
isTypeReference = nameOrRef.isTypeReference
183+
}
173184
const variable = scriptVariables.get(name)
174185
if (!variable || variable.identifiers.length === 0) {
175186
return
@@ -188,7 +199,9 @@ function analyzeUsedInTemplateVariables(
188199
reference.isRead = () => true
189200
reference.isReadOnly = () => true
190201
reference.isReadWrite = () => false
191-
reference.isValueReference = true // For typescript-eslint
202+
// For typescript-eslint
203+
reference.isValueReference = isValueReference
204+
reference.isTypeReference = isTypeReference
192205

193206
variable.references.push(reference)
194207
reference.resolved = variable
@@ -198,7 +211,7 @@ function analyzeUsedInTemplateVariables(
198211
for (const reference of node.references.filter(
199212
(ref) => ref.variable == null,
200213
)) {
201-
markVariableAsUsed(reference.id.name)
214+
markVariableAsUsed(reference)
202215
}
203216
}
204217

Diff for: src/script/index.ts

+33-20
Original file line numberDiff line numberDiff line change
@@ -340,14 +340,15 @@ function parseExpressionBody(
340340
debug('[script] parse expression: "0(%s)"', code)
341341

342342
try {
343-
const ast = parseScriptFragment(
343+
const result = parseScriptFragment(
344344
`0(${code})`,
345345
locationCalculator.getSubCalculatorShift(-2),
346346
parserOptions,
347-
).ast
347+
)
348+
const { ast } = result
348349
const tokens = ast.tokens || []
349350
const comments = ast.comments || []
350-
const references = analyzeExternalReferences(ast, parserOptions)
351+
const references = analyzeExternalReferences(result, parserOptions)
351352
const statement = ast.body[0] as ESLintExpressionStatement
352353
const callExpression = statement.expression as ESLintCallExpression
353354
const expression = callExpression.arguments[0]
@@ -461,13 +462,14 @@ function parseFilter(
461462

462463
// Parse the arguments.
463464
if (argsCode != null) {
464-
const { ast } = parseScriptFragment(
465+
const result = parseScriptFragment(
465466
`0${argsCode}`,
466467
locationCalculator
467468
.getSubCalculatorAfter(paren)
468469
.getSubCalculatorShift(-1),
469470
parserOptions,
470471
)
472+
const { ast } = result
471473
const statement = ast.body[0] as ESLintExpressionStatement
472474
const callExpression = statement.expression
473475

@@ -501,7 +503,7 @@ function parseFilter(
501503
}
502504
tokens.push(...ast.tokens!)
503505
comments.push(...ast.comments!)
504-
references.push(...analyzeExternalReferences(ast, parserOptions))
506+
references.push(...analyzeExternalReferences(result, parserOptions))
505507
}
506508

507509
// Update range.
@@ -755,16 +757,20 @@ export function parseVForExpression(
755757
processed.iterator,
756758
)
757759

758-
const ast = parseScriptFragment(
760+
const result = parseScriptFragment(
759761
`for(let ${processed.aliasesWithBrackets}${processed.delimiter}${processed.iterator});`,
760762
locationCalculator.getSubCalculatorShift(
761763
processed.hasParens ? -8 : -9,
762764
),
763765
parserOptions,
764-
).ast
766+
)
767+
const { ast } = result
765768
const tokens = ast.tokens || []
766769
const comments = ast.comments || []
767-
const scope = analyzeVariablesAndExternalReferences(ast, parserOptions)
770+
const scope = analyzeVariablesAndExternalReferences(
771+
result,
772+
parserOptions,
773+
)
768774
const references = scope.references
769775
const variables = scope.variables
770776
const statement = ast.body[0] as
@@ -934,14 +940,15 @@ function parseVForAliasesForEcmaVersion5(
934940
locationCalculator: LocationCalculatorForHtml,
935941
parserOptions: ParserOptions,
936942
) {
937-
const ast = parseScriptFragment(
943+
const result = parseScriptFragment(
938944
`0(${code})`,
939945
locationCalculator.getSubCalculatorShift(-2),
940946
parserOptions,
941-
).ast
947+
)
948+
const { ast } = result
942949
const tokens = ast.tokens || []
943950
const comments = ast.comments || []
944-
const variables = analyzeExternalReferences(ast, parserOptions).map(
951+
const variables = analyzeExternalReferences(result, parserOptions).map(
945952
transformVariable,
946953
)
947954

@@ -984,14 +991,15 @@ function parseVForIteratorForEcmaVersion5(
984991
locationCalculator: LocationCalculatorForHtml,
985992
parserOptions: ParserOptions,
986993
) {
987-
const ast = parseScriptFragment(
994+
const result = parseScriptFragment(
988995
`0(${code})`,
989996
locationCalculator.getSubCalculatorShift(-2),
990997
parserOptions,
991-
).ast
998+
)
999+
const { ast } = result
9921000
const tokens = ast.tokens || []
9931001
const comments = ast.comments || []
994-
const references = analyzeExternalReferences(ast, parserOptions)
1002+
const references = analyzeExternalReferences(result, parserOptions)
9951003

9961004
const statement = ast.body[0] as ESLintExpressionStatement
9971005
const callExpression = statement.expression as ESLintCallExpression
@@ -1049,12 +1057,13 @@ function parseVOnExpressionBody(
10491057
}
10501058

10511059
try {
1052-
const ast = parseScriptFragment(
1060+
const result = parseScriptFragment(
10531061
`void function($event){${code}}`,
10541062
locationCalculator.getSubCalculatorShift(-22),
10551063
parserOptions,
1056-
).ast
1057-
const references = analyzeExternalReferences(ast, parserOptions)
1064+
)
1065+
const { ast } = result
1066+
const references = analyzeExternalReferences(result, parserOptions)
10581067
const outermostStatement = ast.body[0] as ESLintExpressionStatement
10591068
const functionDecl = (
10601069
outermostStatement.expression as ESLintUnaryExpression
@@ -1126,11 +1135,12 @@ export function parseSlotScopeExpression(
11261135
}
11271136

11281137
try {
1129-
const ast = parseScriptFragment(
1138+
const result = parseScriptFragment(
11301139
`void function(${code}) {}`,
11311140
locationCalculator.getSubCalculatorShift(-14),
11321141
parserOptions,
1133-
).ast
1142+
)
1143+
const { ast } = result
11341144
const statement = ast.body[0] as ESLintExpressionStatement
11351145
const rawExpression = statement.expression as ESLintUnaryExpression
11361146
const functionDecl = rawExpression.argument as ESLintFunctionExpression
@@ -1148,7 +1158,10 @@ export function parseSlotScopeExpression(
11481158

11491159
const tokens = ast.tokens || []
11501160
const comments = ast.comments || []
1151-
const scope = analyzeVariablesAndExternalReferences(ast, parserOptions)
1161+
const scope = analyzeVariablesAndExternalReferences(
1162+
result,
1163+
parserOptions,
1164+
)
11521165
const references = scope.references
11531166
const variables = scope.variables
11541167
const firstParam = first(params)!

Diff for: src/script/scope-analyzer.ts

+20-10
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ import { getFallbackKeys } from "../ast"
1515
import { getEslintScope } from "../common/eslint-scope"
1616
import { getEcmaVersionIfUseEspree } from "../common/espree"
1717

18+
type ParserResult = {
19+
ast: ESLintProgram
20+
scopeManager?: escopeTypes.ScopeManager
21+
}
22+
1823
/**
1924
* Check whether the given reference is unique in the belonging array.
2025
* @param reference The current reference to check.
@@ -54,6 +59,8 @@ function transformReference(reference: escopeTypes.Reference): Reference {
5459
? "w"
5560
: /* otherwise */ "rw",
5661
variable: null,
62+
isValueReference: reference.isValueReference,
63+
isTypeReference: reference.isTypeReference,
5764
}
5865
Object.defineProperty(ret, "variable", { enumerable: false })
5966

@@ -106,40 +113,43 @@ export function analyzeScope(
106113
}
107114

108115
/**
109-
*
110-
* @param ast
116+
* Analyze the scope of the given AST.
117+
* @param {ParserResult} parserResult The parser result to analyze.
111118
* @param parserOptions
112119
*/
113120
function analyze(
114-
ast: ESLintProgram,
121+
parserResult: ParserResult,
115122
parserOptions: ParserOptions,
116123
): escopeTypes.Scope {
117-
return analyzeScope(ast, parserOptions).globalScope
124+
const scopeManager =
125+
parserResult.scopeManager ||
126+
analyzeScope(parserResult.ast, parserOptions)
127+
return scopeManager.globalScope
118128
}
119129

120130
/**
121131
* Analyze the external references of the given AST.
122-
* @param {ASTNode} ast The root node to analyze.
132+
* @param {ParserResult} parserResult The parser result to analyze.
123133
* @returns {Reference[]} The reference objects of external references.
124134
*/
125135
export function analyzeExternalReferences(
126-
ast: ESLintProgram,
136+
parserResult: ParserResult,
127137
parserOptions: ParserOptions,
128138
): Reference[] {
129-
const scope = analyze(ast, parserOptions)
139+
const scope = analyze(parserResult, parserOptions)
130140
return scope.through.filter(isUnique).map(transformReference)
131141
}
132142

133143
/**
134144
* Analyze the external references of the given AST.
135-
* @param {ASTNode} ast The root node to analyze.
145+
* @param {ParserResult} parserResult The parser result to analyze.
136146
* @returns {Reference[]} The reference objects of external references.
137147
*/
138148
export function analyzeVariablesAndExternalReferences(
139-
ast: ESLintProgram,
149+
parserResult: ParserResult,
140150
parserOptions: ParserOptions,
141151
): { variables: Variable[]; references: Reference[] } {
142-
const scope = analyze(ast, parserOptions)
152+
const scope = analyze(parserResult, parserOptions)
143153
return {
144154
variables: getForScope(scope)
145155
.variables.filter(hasDefinition)

Diff for: test/fixtures/ast/parser-option-multiple-parsers-1/ast.json

+52-2
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,9 @@
656656
}
657657
}
658658
},
659-
"mode": "r"
659+
"mode": "r",
660+
"isValueReference": true,
661+
"isTypeReference": false
660662
},
661663
{
662664
"id": {
@@ -677,7 +679,55 @@
677679
}
678680
}
679681
},
680-
"mode": "r"
682+
"mode": "r",
683+
"isValueReference": true,
684+
"isTypeReference": false
685+
},
686+
{
687+
"id": {
688+
"type": "Identifier",
689+
"name": "b",
690+
"range": [
691+
17,
692+
18
693+
],
694+
"loc": {
695+
"start": {
696+
"line": 2,
697+
"column": 6
698+
},
699+
"end": {
700+
"line": 2,
701+
"column": 7
702+
}
703+
}
704+
},
705+
"mode": "r",
706+
"isValueReference": false,
707+
"isTypeReference": true
708+
},
709+
{
710+
"id": {
711+
"type": "Identifier",
712+
"name": "c",
713+
"range": [
714+
19,
715+
20
716+
],
717+
"loc": {
718+
"start": {
719+
"line": 2,
720+
"column": 8
721+
},
722+
"end": {
723+
"line": 2,
724+
"column": 9
725+
}
726+
}
727+
},
728+
"mode": "r",
729+
"isValueReference": false,
730+
"isTypeReference": true
681731
}
682732
]
683733
},

0 commit comments

Comments
 (0)