Skip to content

Commit d51ff42

Browse files
committed
Extract external API usage from BQRS in the extension
1 parent 8741ba9 commit d51ff42

File tree

4 files changed

+89
-78
lines changed

4 files changed

+89
-78
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { DecodedBqrsChunk } from "../pure/bqrs-cli-types";
2+
import { Call, ExternalApiUsage } from "./external-api-usage";
3+
4+
export function decodeBqrsToExternalApiUsages(
5+
chunk: DecodedBqrsChunk,
6+
): ExternalApiUsage[] {
7+
const methodsByApiName = new Map<string, ExternalApiUsage>();
8+
9+
chunk?.tuples.forEach((tuple) => {
10+
const signature = tuple[0] as string;
11+
const supported = tuple[1] as boolean;
12+
const usage = tuple[2] as Call;
13+
14+
const [packageWithType, methodDeclaration] = signature.split("#");
15+
16+
const packageName = packageWithType.substring(
17+
0,
18+
packageWithType.lastIndexOf("."),
19+
);
20+
const typeName = packageWithType.substring(
21+
packageWithType.lastIndexOf(".") + 1,
22+
);
23+
24+
const methodName = methodDeclaration.substring(
25+
0,
26+
methodDeclaration.indexOf("("),
27+
);
28+
const methodParameters = methodDeclaration.substring(
29+
methodDeclaration.indexOf("("),
30+
);
31+
32+
if (!methodsByApiName.has(signature)) {
33+
methodsByApiName.set(signature, {
34+
signature,
35+
packageName,
36+
typeName,
37+
methodName,
38+
methodParameters,
39+
supported,
40+
usages: [],
41+
});
42+
}
43+
44+
const method = methodsByApiName.get(signature)!;
45+
method.usages.push(usage);
46+
});
47+
48+
const externalApiUsages = Array.from(methodsByApiName.values());
49+
externalApiUsages.sort((a, b) => {
50+
// Sort by number of usages descending
51+
return b.usages.length - a.usages.length;
52+
});
53+
return externalApiUsages;
54+
}

extensions/ql-vscode/src/data-extensions-editor/data-extensions-editor-view.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { dump } from "js-yaml";
1414
import { getOnDiskWorkspaceFolders } from "../helpers";
1515
import { DatabaseItem } from "../local-databases";
1616
import { CodeQLCliServer } from "../cli";
17+
import { decodeBqrsToExternalApiUsages } from "./bqrs";
1718

1819
export class DataExtensionsEditorView extends AbstractWebview<
1920
ToDataExtensionsEditorMessage,
@@ -84,8 +85,8 @@ export class DataExtensionsEditorView extends AbstractWebview<
8485

8586
const bqrsPath = queryResult.outputDir.bqrsPath;
8687

87-
const results = await this.getResults(bqrsPath);
88-
if (!results) {
88+
const bqrsChunk = await this.getResults(bqrsPath);
89+
if (!bqrsChunk) {
8990
await this.clearProgress();
9091
return;
9192
}
@@ -96,9 +97,11 @@ export class DataExtensionsEditorView extends AbstractWebview<
9697
maxStep: 1500,
9798
});
9899

100+
const externalApiUsages = decodeBqrsToExternalApiUsages(bqrsChunk);
101+
99102
await this.postMessage({
100-
t: "setExternalApiRepoResults",
101-
results,
103+
t: "setExternalApiUsages",
104+
externalApiUsages,
102105
});
103106

104107
await this.clearProgress();

extensions/ql-vscode/src/pure/interface-types.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import {
55
ResultSetSchema,
66
Column,
77
ResolvableLocationValue,
8-
DecodedBqrsChunk,
98
} from "./bqrs-cli-types";
109
import {
1110
VariantAnalysis,
@@ -15,6 +14,7 @@ import {
1514
import { RepositoriesFilterSortStateWithIds } from "./variant-analysis-filter-sort";
1615
import { ErrorLike } from "./errors";
1716
import { DataFlowPaths } from "../variant-analysis/shared/data-flow-paths";
17+
import { ExternalApiUsage } from "../data-extensions-editor/external-api-usage";
1818

1919
/**
2020
* This module contains types and code that are shared between
@@ -480,9 +480,9 @@ export type ToDataFlowPathsMessage = SetDataFlowPathsMessage;
480480

481481
export type FromDataFlowPathsMessage = CommonFromViewMessages;
482482

483-
export interface SetExternalApiResultsMessage {
484-
t: "setExternalApiRepoResults";
485-
results: DecodedBqrsChunk;
483+
export interface SetExternalApiUsagesMessage {
484+
t: "setExternalApiUsages";
485+
externalApiUsages: ExternalApiUsage[];
486486
}
487487

488488
export interface ShowProgressMessage {
@@ -493,7 +493,7 @@ export interface ShowProgressMessage {
493493
}
494494

495495
export type ToDataExtensionsEditorMessage =
496-
| SetExternalApiResultsMessage
496+
| SetExternalApiUsagesMessage
497497
| ShowProgressMessage;
498498

499499
export type FromDataExtensionsEditorMessage = ViewLoadedMsg;

extensions/ql-vscode/src/view/data-extensions-editor/DataExtensionsEditor.tsx

Lines changed: 23 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import * as React from "react";
22
import { useCallback, useEffect, useMemo, useState } from "react";
3-
import { DecodedBqrsChunk } from "../../pure/bqrs-cli-types";
43
import {
54
ShowProgressMessage,
65
ToDataExtensionsEditorMessage,
@@ -11,10 +10,7 @@ import {
1110
VSCodeDataGridRow,
1211
} from "@vscode/webview-ui-toolkit/react";
1312
import styled from "styled-components";
14-
import {
15-
Call,
16-
ExternalApiUsage,
17-
} from "../../data-extensions-editor/external-api-usage";
13+
import { ExternalApiUsage } from "../../data-extensions-editor/external-api-usage";
1814
import { ModeledMethod } from "../../data-extensions-editor/modeled-method";
1915
import { MethodRow } from "./MethodRow";
2016
import { assertNever } from "../../pure/helpers-pure";
@@ -35,9 +31,9 @@ const ProgressBar = styled.div<ProgressBarProps>`
3531
`;
3632

3733
export function DataExtensionsEditor(): JSX.Element {
38-
const [results, setResults] = useState<DecodedBqrsChunk | undefined>(
39-
undefined,
40-
);
34+
const [externalApiUsages, setExternalApiUsages] = useState<
35+
ExternalApiUsage[]
36+
>([]);
4137
const [modeledMethods, setModeledMethods] = useState<
4238
Record<string, ModeledMethod>
4339
>({});
@@ -52,8 +48,8 @@ export function DataExtensionsEditor(): JSX.Element {
5248
if (evt.origin === window.origin) {
5349
const msg: ToDataExtensionsEditorMessage = evt.data;
5450
switch (msg.t) {
55-
case "setExternalApiRepoResults":
56-
setResults(msg.results);
51+
case "setExternalApiUsages":
52+
setExternalApiUsages(msg.externalApiUsages);
5753
break;
5854
case "showProgress":
5955
setProgress(msg);
@@ -74,63 +70,21 @@ export function DataExtensionsEditor(): JSX.Element {
7470
};
7571
}, []);
7672

77-
const methods = useMemo(() => {
78-
const methodsByApiName = new Map<string, ExternalApiUsage>();
79-
80-
results?.tuples.forEach((tuple) => {
81-
const signature = tuple[0] as string;
82-
const supported = tuple[1] as boolean;
83-
const usage = tuple[2] as Call;
84-
85-
const [packageWithType, methodDeclaration] = signature.split("#");
86-
87-
const packageName = packageWithType.substring(
88-
0,
89-
packageWithType.lastIndexOf("."),
90-
);
91-
const typeName = packageWithType.substring(
92-
packageWithType.lastIndexOf(".") + 1,
93-
);
94-
95-
const methodName = methodDeclaration.substring(
96-
0,
97-
methodDeclaration.indexOf("("),
98-
);
99-
const methodParameters = methodDeclaration.substring(
100-
methodDeclaration.indexOf("("),
101-
);
102-
103-
if (!methodsByApiName.has(signature)) {
104-
methodsByApiName.set(signature, {
105-
signature,
106-
packageName,
107-
typeName,
108-
methodName,
109-
methodParameters,
110-
supported,
111-
usages: [],
112-
});
113-
}
114-
115-
const method = methodsByApiName.get(signature)!;
116-
method.usages.push(usage);
117-
});
118-
119-
const externalApiUsages = Array.from(methodsByApiName.values());
120-
externalApiUsages.sort((a, b) => {
121-
// Sort by number of usages descending
122-
return b.usages.length - a.usages.length;
123-
});
124-
return externalApiUsages;
125-
}, [results]);
126-
12773
const supportedPercentage = useMemo(() => {
128-
return (methods.filter((m) => m.supported).length / methods.length) * 100;
129-
}, [methods]);
74+
return (
75+
(externalApiUsages.filter((m) => m.supported).length /
76+
externalApiUsages.length) *
77+
100
78+
);
79+
}, [externalApiUsages]);
13080

13181
const unsupportedPercentage = useMemo(() => {
132-
return (methods.filter((m) => !m.supported).length / methods.length) * 100;
133-
}, [methods]);
82+
return (
83+
(externalApiUsages.filter((m) => !m.supported).length /
84+
externalApiUsages.length) *
85+
100
86+
);
87+
}, [externalApiUsages]);
13488

13589
const onChange = useCallback(
13690
(method: ExternalApiUsage, model: ModeledMethod) => {
@@ -151,7 +105,7 @@ export function DataExtensionsEditor(): JSX.Element {
151105
</p>
152106
)}
153107

154-
{methods.length > 0 && (
108+
{externalApiUsages.length > 0 && (
155109
<>
156110
<div>
157111
<h3>External API support stats</h3>
@@ -186,11 +140,11 @@ export function DataExtensionsEditor(): JSX.Element {
186140
Kind
187141
</VSCodeDataGridCell>
188142
</VSCodeDataGridRow>
189-
{methods.map((method) => (
143+
{externalApiUsages.map((externalApiUsage) => (
190144
<MethodRow
191-
key={method.signature}
192-
method={method}
193-
model={modeledMethods[method.signature]}
145+
key={externalApiUsage.signature}
146+
method={externalApiUsage}
147+
model={modeledMethods[externalApiUsage.signature]}
194148
onChange={onChange}
195149
/>
196150
))}

0 commit comments

Comments
 (0)