Skip to content

Commit 40a4001

Browse files
authored
Fix typescript plugin with typescript 5 (#78)
* Fix typescript plugin in vscode This is done by tweaking the logic slightly (typescript 5 returns a slightly different AST tree) and also use the typescript util functions that are passed into the plugin. This is important because the vscode extension currently bundles a typescript version which might be different from the one that the project is using. And given that typescript relies on enums with numbers, we can run into issues where the value 357 for SyntaxKind might mean one thing in one version and something completely different in another typescript version. * Update changelog * Bump version to 0.5.3
1 parent b86c099 commit 40a4001

File tree

5 files changed

+61
-26
lines changed

5 files changed

+61
-26
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## [v0.5.3] - 2023-06-26
4+
5+
### Changed
6+
7+
- Fixed issue with running the typescript plugin in combination with typescript 5 (and also fix issues when the vscode extension is bundled with a different version of typescript compared to what vscode is using)
8+
39
## [v0.5.2] - 2023-06-16
410

511
### Added

packages/typescript-plugin/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@autometrics/typescript-plugin",
3-
"version": "0.5.2",
3+
"version": "0.5.3",
44
"description": "Language service plugin for Autometrics",
55
"author": "Fiberplane<[email protected]>",
66
"contributors": [

packages/typescript-plugin/src/astHelpers.ts

+42-19
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1-
import ts from "typescript/lib/tsserverlibrary";
2-
1+
import tsserver from "typescript/lib/tsserverlibrary";
2+
import type {
3+
Node,
4+
SourceFile,
5+
TypeChecker,
6+
} from "typescript/lib/tsserverlibrary";
7+
import { Tsserver } from "./types";
38
import type { NodeType } from "./types";
49

510
/**
@@ -9,8 +14,9 @@ import type { NodeType } from "./types";
914
* @param typechecker The helper utility typechecker
1015
*/
1116
export function isAutometricsWrappedOrDecorated(
12-
node: ts.Node,
13-
typechecker: ts.TypeChecker,
17+
node: Node,
18+
typechecker: TypeChecker,
19+
ts: Tsserver,
1420
) {
1521
// Checks if the user is hovering over the autometrics wrapper itself in which
1622
// case we should not show the queries
@@ -25,7 +31,7 @@ export function isAutometricsWrappedOrDecorated(
2531
// Checks if the function the user is hovering over has a type
2632
// AutometricsWrapper or is wrapped by a function that has a type
2733
// AutometricsWrapper
28-
const checkWrapperType = (node: ts.Node) => {
34+
const checkWrapperType = (node: Node) => {
2935
if (ts.isSourceFile(node)) {
3036
return;
3137
}
@@ -50,11 +56,12 @@ export function isAutometricsWrappedOrDecorated(
5056
}
5157

5258
const isDecorated =
53-
hasAutometricsDecorator(method) || hasAutometricsDecorator(method.parent);
59+
hasAutometricsDecorator(method, ts) ||
60+
hasAutometricsDecorator(method.parent, ts);
5461
return isDecorated;
5562
}
5663

57-
export function hasAutometricsDecorator(node: ts.Node) {
64+
export function hasAutometricsDecorator(node: Node, ts: Tsserver) {
5865
const decorators = ts.canHaveDecorators(node) && ts.getDecorators(node);
5966
if (!decorators) {
6067
return false;
@@ -69,14 +76,15 @@ export function hasAutometricsDecorator(node: ts.Node) {
6976

7077
/**
7178
* Gets the node identifier
72-
* @param node {ts.Node} - the node itself
79+
* @param node {Node} - the node itself
7380
* @param nodeType {NodeType} - so we know what kind of check to run
7481
* @param typechecker {ts.TypeChecker} - helper util
7582
*/
7683
export function getNodeIdentifier(
77-
node: ts.Node,
84+
node: Node,
7885
nodeType: NodeType,
79-
typechecker: ts.TypeChecker,
86+
typechecker: TypeChecker,
87+
ts: Tsserver,
8088
): string {
8189
if (nodeType === "method" && ts.isIdentifier(node)) {
8290
return node.escapedText.toString();
@@ -118,13 +126,17 @@ export function getNodeIdentifier(
118126
* Gets the type of the node (we care only about functions or methods)
119127
* @param node The node itself
120128
* @param typechecker The helper utility
121-
* @returns {NodeType}
129+
* @returns {NodeType | undefined}
122130
*/
123-
export function getNodeType(node: ts.Node, typechecker: ts.TypeChecker) {
131+
export function getNodeType(
132+
node: Node,
133+
typechecker: TypeChecker,
134+
ts: Tsserver,
135+
): "method" | "function" | undefined {
124136
const declaration = typechecker.getSymbolAtLocation(node);
125137

126-
if (!declaration?.valueDeclaration || !node?.parent) {
127-
return;
138+
if (!declaration?.valueDeclaration) {
139+
return undefined;
128140
}
129141

130142
const { valueDeclaration } = declaration;
@@ -158,6 +170,8 @@ export function getNodeType(node: ts.Node, typechecker: ts.TypeChecker) {
158170
) {
159171
return "function";
160172
}
173+
174+
return undefined;
161175
}
162176

163177
/**
@@ -166,14 +180,23 @@ export function getNodeType(node: ts.Node, typechecker: ts.TypeChecker) {
166180
* @param position Current cursor/mouse position
167181
*/
168182
export function getNodeAtCursor(
169-
sourceFile: ts.SourceFile,
183+
sourceFile: SourceFile,
170184
position: number,
171-
): ts.Node | undefined {
172-
function find(node: ts.Node): ts.Node | undefined {
185+
ts: Tsserver,
186+
): Node | undefined {
187+
const find = (node: Node): Node | undefined => {
173188
if (position >= node.getStart() && position < node.getEnd()) {
174-
return ts.forEachChild(node, find) || node;
189+
const children = node.getChildren();
190+
for (const child of children) {
191+
const result = find(child);
192+
if (result) {
193+
return result;
194+
}
195+
}
196+
197+
return node;
175198
}
176-
}
199+
};
177200

178201
return find(sourceFile);
179202
}

packages/typescript-plugin/src/index.ts

+9-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import tsserver from "typescript/lib/tsserverlibrary";
1+
import type { QuickInfo, server } from "typescript/lib/tsserverlibrary";
22

33
import {
44
getNodeAtCursor,
@@ -13,21 +13,22 @@ import {
1313
makePrometheusUrl,
1414
} from "./queryHelpers";
1515
import { createLogger, getProxy } from "./utils";
16+
import { Tsserver } from "./types";
1617

1718
type Config = {
1819
prometheusUrl?: string;
1920
docsOutputFormat?: "prometheus" | "vscode";
2021
};
2122

22-
function init(modules: { typescript: typeof tsserver }) {
23+
function init(modules: { typescript: Tsserver }) {
2324
let pluginConfig: Config;
2425
const ts = modules.typescript;
2526

2627
function create({
2728
config,
2829
languageService,
2930
project,
30-
}: ts.server.PluginCreateInfo) {
31+
}: server.PluginCreateInfo) {
3132
const log = createLogger(project);
3233
log("started");
3334

@@ -49,11 +50,12 @@ function init(modules: { typescript: typeof tsserver }) {
4950
const docsOutputFormat = pluginConfig.docsOutputFormat || "prometheus";
5051

5152
const sourceFile = languageService.getProgram().getSourceFile(filename);
52-
const nodeAtCursor = getNodeAtCursor(sourceFile, position);
53-
const nodeType = getNodeType(nodeAtCursor, typechecker);
53+
const nodeAtCursor = getNodeAtCursor(sourceFile, position, ts);
54+
const nodeType = getNodeType(nodeAtCursor, typechecker, ts);
5455
const autometrics = isAutometricsWrappedOrDecorated(
5556
nodeAtCursor,
5657
typechecker,
58+
ts,
5759
);
5860

5961
// If either autometrics checker or node type is undefined return early
@@ -65,6 +67,7 @@ function init(modules: { typescript: typeof tsserver }) {
6567
nodeAtCursor,
6668
nodeType,
6769
typechecker,
70+
ts,
6871
);
6972

7073
// The output of this plugin will
@@ -184,7 +187,7 @@ function init(modules: { typescript: typeof tsserver }) {
184187
queries,
185188
);
186189

187-
return <ts.QuickInfo>{
190+
return <QuickInfo>{
188191
...prior,
189192
documentation: enrichedDocumentation,
190193
};
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1+
import type tsserver from "typescript/lib/tsserverlibrary";
2+
3+
export type Tsserver = typeof tsserver;
14
export * from "./nodeType";

0 commit comments

Comments
 (0)