Skip to content

Commit 0d3848e

Browse files
committed
feat: You can now ctrl+click on event name of methods like addListener, on for jumping into event-related listeners or triggers like emit
1 parent 16743dd commit 0d3848e

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed

typescript/src/definitions.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { join } from 'path-browserify'
22
import { GetConfig } from './types'
33
import { findChildContainingExactPosition } from './utils'
4+
import { eventDefinitions } from './eventsReferences'
45

56
export default (proxy: ts.LanguageService, languageService: ts.LanguageService, languageServiceHost: ts.LanguageServiceHost, c: GetConfig) => {
67
proxy.getDefinitionAndBoundSpan = (fileName, position, ...props) => {
@@ -26,6 +27,9 @@ export default (proxy: ts.LanguageService, languageService: ts.LanguageService,
2627
const noDefs = !prior?.definitions || prior.definitions.length === 0
2728
const tryFileResolve = noDefs || ['?', '#'].some(x => prior.definitions?.[0]?.fileName?.includes(x))
2829

30+
const eventDefs = eventDefinitions(languageService, fileName, position)
31+
if (eventDefs) return eventDefs
32+
2933
// Definition fallbacks
3034
if (noDefs || tryFileResolve) {
3135
const node = getNode()

typescript/src/eventsReferences.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import ts from 'typescript'
2+
import { findChildContainingExactPosition, matchParents } from './utils'
3+
4+
export const eventDefinitions = (languageService: ts.LanguageService, fileName: string, position: number): ts.DefinitionInfoAndBoundSpan | undefined => {
5+
const program = languageService.getProgram()!
6+
const sourceFile = program.getSourceFile(fileName)!
7+
const node = findChildContainingExactPosition(sourceFile, position)
8+
if (!node || !ts.isStringLiteral(node)) return
9+
const eventName = node.text
10+
const expr = matchParents(node, ['StringLiteral', 'CallExpression'])
11+
if (!expr) return
12+
if (!ts.isPropertyAccessExpression(expr.expression)) return
13+
const parentAccessEndPos = expr.expression.expression.getEnd()
14+
const method = expr.expression.name.text
15+
let lookForMethods: string[] | undefined
16+
const onMethods = ['on', 'once', 'off', 'addEventListener', 'removeEventListener', 'addListener', 'removeListener']
17+
const triggerMethods = ['trigger', 'emit', 'dispatchEvent']
18+
if (onMethods.includes(method)) {
19+
lookForMethods = triggerMethods
20+
}
21+
if (triggerMethods.includes(method)) {
22+
lookForMethods = onMethods
23+
}
24+
if (!lookForMethods) return
25+
const references = languageService.findReferences(fileName, parentAccessEndPos) ?? []
26+
const defs: ts.DefinitionInfo[] = references
27+
.flatMap(({ references }) => references)
28+
.map(({ fileName, textSpan }): ts.DefinitionInfo | undefined => {
29+
const sourceFile = program.getSourceFile(fileName)!
30+
const node = findChildContainingExactPosition(sourceFile, textSpan.start)
31+
if (!node) return
32+
if (!ts.isPropertyAccessExpression(node.parent)) return
33+
let upNode = node as ts.PropertyAccessExpression
34+
while (ts.isPropertyAccessExpression(upNode.parent)) {
35+
upNode = upNode.parent
36+
}
37+
if (!ts.isCallExpression(upNode.parent)) return
38+
if (!ts.isPropertyAccessExpression(upNode.parent.expression)) return
39+
const method = upNode.parent.expression.name.text
40+
if (!lookForMethods!.includes(method)) return
41+
const arg = upNode.parent.arguments[0]
42+
if (!arg || !ts.isStringLiteral(arg)) return
43+
const lastArgEnd = upNode.parent.arguments.at(-1)!.end
44+
const span = ts.createTextSpanFromBounds(arg.pos, lastArgEnd)
45+
if (arg.text !== eventName) return
46+
47+
return {
48+
kind: ts.ScriptElementKind.memberVariableElement,
49+
name: method,
50+
containerKind: ts.ScriptElementKind.variableElement,
51+
containerName: method,
52+
textSpan: span,
53+
fileName,
54+
}
55+
})
56+
.filter(a => a !== undefined)
57+
.map(a => a!)
58+
return {
59+
textSpan: ts.createTextSpanFromBounds(node.pos, node.end),
60+
definitions: defs,
61+
}
62+
}

0 commit comments

Comments
 (0)