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

Fix wrong scope reference type for <script setup lang=ts> #181

Merged
merged 3 commits into from
Mar 30, 2023
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
4 changes: 4 additions & 0 deletions src/ast/nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,10 @@ export interface Reference {
id: ESLintIdentifier
mode: "rw" | "r" | "w"
variable: Variable | null

// For typescript-eslint
isValueReference?: boolean
isTypeReference?: boolean
}

/**
Expand Down
19 changes: 16 additions & 3 deletions src/script-setup/scope-analyzer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type * as escopeTypes from "eslint-scope"
import type { ParserOptions } from "../common/parser-options"
import type {
Reference,
VAttribute,
VDirective,
VDocumentFragment,
Expand Down Expand Up @@ -169,7 +170,17 @@ function analyzeUsedInTemplateVariables(
return false
}

function markVariableAsUsed(name: string) {
function markVariableAsUsed(nameOrRef: string | Reference) {
let name: string
let isValueReference: boolean | undefined
let isTypeReference: boolean | undefined
if (typeof nameOrRef === "string") {
name = nameOrRef
} else {
name = nameOrRef.id.name
isValueReference = nameOrRef.isValueReference
isTypeReference = nameOrRef.isTypeReference
}
const variable = scriptVariables.get(name)
if (!variable || variable.identifiers.length === 0) {
return
Expand All @@ -188,7 +199,9 @@ function analyzeUsedInTemplateVariables(
reference.isRead = () => true
reference.isReadOnly = () => true
reference.isReadWrite = () => false
reference.isValueReference = true // For typescript-eslint
// For typescript-eslint
reference.isValueReference = isValueReference
reference.isTypeReference = isTypeReference

variable.references.push(reference)
reference.resolved = variable
Expand All @@ -198,7 +211,7 @@ function analyzeUsedInTemplateVariables(
for (const reference of node.references.filter(
(ref) => ref.variable == null,
)) {
markVariableAsUsed(reference.id.name)
markVariableAsUsed(reference)
}
}

Expand Down
53 changes: 33 additions & 20 deletions src/script/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -340,14 +340,15 @@ function parseExpressionBody(
debug('[script] parse expression: "0(%s)"', code)

try {
const ast = parseScriptFragment(
const result = parseScriptFragment(
`0(${code})`,
locationCalculator.getSubCalculatorShift(-2),
parserOptions,
).ast
)
const { ast } = result
const tokens = ast.tokens || []
const comments = ast.comments || []
const references = analyzeExternalReferences(ast, parserOptions)
const references = analyzeExternalReferences(result, parserOptions)
const statement = ast.body[0] as ESLintExpressionStatement
const callExpression = statement.expression as ESLintCallExpression
const expression = callExpression.arguments[0]
Expand Down Expand Up @@ -461,13 +462,14 @@ function parseFilter(

// Parse the arguments.
if (argsCode != null) {
const { ast } = parseScriptFragment(
const result = parseScriptFragment(
`0${argsCode}`,
locationCalculator
.getSubCalculatorAfter(paren)
.getSubCalculatorShift(-1),
parserOptions,
)
const { ast } = result
const statement = ast.body[0] as ESLintExpressionStatement
const callExpression = statement.expression

Expand Down Expand Up @@ -501,7 +503,7 @@ function parseFilter(
}
tokens.push(...ast.tokens!)
comments.push(...ast.comments!)
references.push(...analyzeExternalReferences(ast, parserOptions))
references.push(...analyzeExternalReferences(result, parserOptions))
}

// Update range.
Expand Down Expand Up @@ -755,16 +757,20 @@ export function parseVForExpression(
processed.iterator,
)

const ast = parseScriptFragment(
const result = parseScriptFragment(
`for(let ${processed.aliasesWithBrackets}${processed.delimiter}${processed.iterator});`,
locationCalculator.getSubCalculatorShift(
processed.hasParens ? -8 : -9,
),
parserOptions,
).ast
)
const { ast } = result
const tokens = ast.tokens || []
const comments = ast.comments || []
const scope = analyzeVariablesAndExternalReferences(ast, parserOptions)
const scope = analyzeVariablesAndExternalReferences(
result,
parserOptions,
)
const references = scope.references
const variables = scope.variables
const statement = ast.body[0] as
Expand Down Expand Up @@ -934,14 +940,15 @@ function parseVForAliasesForEcmaVersion5(
locationCalculator: LocationCalculatorForHtml,
parserOptions: ParserOptions,
) {
const ast = parseScriptFragment(
const result = parseScriptFragment(
`0(${code})`,
locationCalculator.getSubCalculatorShift(-2),
parserOptions,
).ast
)
const { ast } = result
const tokens = ast.tokens || []
const comments = ast.comments || []
const variables = analyzeExternalReferences(ast, parserOptions).map(
const variables = analyzeExternalReferences(result, parserOptions).map(
transformVariable,
)

Expand Down Expand Up @@ -984,14 +991,15 @@ function parseVForIteratorForEcmaVersion5(
locationCalculator: LocationCalculatorForHtml,
parserOptions: ParserOptions,
) {
const ast = parseScriptFragment(
const result = parseScriptFragment(
`0(${code})`,
locationCalculator.getSubCalculatorShift(-2),
parserOptions,
).ast
)
const { ast } = result
const tokens = ast.tokens || []
const comments = ast.comments || []
const references = analyzeExternalReferences(ast, parserOptions)
const references = analyzeExternalReferences(result, parserOptions)

const statement = ast.body[0] as ESLintExpressionStatement
const callExpression = statement.expression as ESLintCallExpression
Expand Down Expand Up @@ -1049,12 +1057,13 @@ function parseVOnExpressionBody(
}

try {
const ast = parseScriptFragment(
const result = parseScriptFragment(
`void function($event){${code}}`,
locationCalculator.getSubCalculatorShift(-22),
parserOptions,
).ast
const references = analyzeExternalReferences(ast, parserOptions)
)
const { ast } = result
const references = analyzeExternalReferences(result, parserOptions)
const outermostStatement = ast.body[0] as ESLintExpressionStatement
const functionDecl = (
outermostStatement.expression as ESLintUnaryExpression
Expand Down Expand Up @@ -1126,11 +1135,12 @@ export function parseSlotScopeExpression(
}

try {
const ast = parseScriptFragment(
const result = parseScriptFragment(
`void function(${code}) {}`,
locationCalculator.getSubCalculatorShift(-14),
parserOptions,
).ast
)
const { ast } = result
const statement = ast.body[0] as ESLintExpressionStatement
const rawExpression = statement.expression as ESLintUnaryExpression
const functionDecl = rawExpression.argument as ESLintFunctionExpression
Expand All @@ -1148,7 +1158,10 @@ export function parseSlotScopeExpression(

const tokens = ast.tokens || []
const comments = ast.comments || []
const scope = analyzeVariablesAndExternalReferences(ast, parserOptions)
const scope = analyzeVariablesAndExternalReferences(
result,
parserOptions,
)
const references = scope.references
const variables = scope.variables
const firstParam = first(params)!
Expand Down
30 changes: 20 additions & 10 deletions src/script/scope-analyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ import { getFallbackKeys } from "../ast"
import { getEslintScope } from "../common/eslint-scope"
import { getEcmaVersionIfUseEspree } from "../common/espree"

type ParserResult = {
ast: ESLintProgram
scopeManager?: escopeTypes.ScopeManager
}

/**
* Check whether the given reference is unique in the belonging array.
* @param reference The current reference to check.
Expand Down Expand Up @@ -54,6 +59,8 @@ function transformReference(reference: escopeTypes.Reference): Reference {
? "w"
: /* otherwise */ "rw",
variable: null,
isValueReference: reference.isValueReference,
isTypeReference: reference.isTypeReference,
}
Object.defineProperty(ret, "variable", { enumerable: false })

Expand Down Expand Up @@ -106,40 +113,43 @@ export function analyzeScope(
}

/**
*
* @param ast
* Analyze the scope of the given AST.
* @param {ParserResult} parserResult The parser result to analyze.
* @param parserOptions
*/
function analyze(
ast: ESLintProgram,
parserResult: ParserResult,
parserOptions: ParserOptions,
): escopeTypes.Scope {
return analyzeScope(ast, parserOptions).globalScope
const scopeManager =
parserResult.scopeManager ||
analyzeScope(parserResult.ast, parserOptions)
return scopeManager.globalScope
}

/**
* Analyze the external references of the given AST.
* @param {ASTNode} ast The root node to analyze.
* @param {ParserResult} parserResult The parser result to analyze.
* @returns {Reference[]} The reference objects of external references.
*/
export function analyzeExternalReferences(
ast: ESLintProgram,
parserResult: ParserResult,
parserOptions: ParserOptions,
): Reference[] {
const scope = analyze(ast, parserOptions)
const scope = analyze(parserResult, parserOptions)
return scope.through.filter(isUnique).map(transformReference)
}

/**
* Analyze the external references of the given AST.
* @param {ASTNode} ast The root node to analyze.
* @param {ParserResult} parserResult The parser result to analyze.
* @returns {Reference[]} The reference objects of external references.
*/
export function analyzeVariablesAndExternalReferences(
ast: ESLintProgram,
parserResult: ParserResult,
parserOptions: ParserOptions,
): { variables: Variable[]; references: Reference[] } {
const scope = analyze(ast, parserOptions)
const scope = analyze(parserResult, parserOptions)
return {
variables: getForScope(scope)
.variables.filter(hasDefinition)
Expand Down
54 changes: 52 additions & 2 deletions test/fixtures/ast/parser-option-multiple-parsers-1/ast.json
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,9 @@
}
}
},
"mode": "r"
"mode": "r",
"isValueReference": true,
"isTypeReference": false
},
{
"id": {
Expand All @@ -677,7 +679,55 @@
}
}
},
"mode": "r"
"mode": "r",
"isValueReference": true,
"isTypeReference": false
},
{
"id": {
"type": "Identifier",
"name": "b",
"range": [
17,
18
],
"loc": {
"start": {
"line": 2,
"column": 6
},
"end": {
"line": 2,
"column": 7
}
}
},
"mode": "r",
"isValueReference": false,
"isTypeReference": true
},
{
"id": {
"type": "Identifier",
"name": "c",
"range": [
19,
20
],
"loc": {
"start": {
"line": 2,
"column": 8
},
"end": {
"line": 2,
"column": 9
}
}
},
"mode": "r",
"isValueReference": false,
"isTypeReference": true
}
]
},
Expand Down
Loading