Skip to content

Commit b20a65a

Browse files
committed
Use QueryLanguage type for representing query languages
This will make both the `askForLanguage` and `findLanguage` functions return a `QueryLanguage` instead of a `string`. This will make it harder to make mistakes when using these functions. There are also some other changes with regards to `QueryLanguage` such that we never need to use `as QueryLanguage` explicitly anymore, except for the new `isQueryLanguage` function. The only remaining place that I know of where we're using a `string` to represent the `QueryLanguage` is in a database item's language, but this is harder to change and may be relied upon by language authors.
1 parent bf9eb24 commit b20a65a

File tree

5 files changed

+53
-12
lines changed

5 files changed

+53
-12
lines changed

extensions/ql-vscode/src/data-extensions-editor/external-api-usage-query.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { writeFile } from "fs-extra";
44
import { dump as dumpYaml } from "js-yaml";
55
import {
66
getOnDiskWorkspaceFolders,
7+
isQueryLanguage,
78
showAndLogExceptionWithTelemetry,
89
} from "../helpers";
910
import { TeeLogger } from "../common";
@@ -15,7 +16,6 @@ import { fetchExternalApiQueries } from "./queries";
1516
import { QueryResultType } from "../pure/new-messages";
1617
import { join } from "path";
1718
import { redactableError } from "../pure/errors";
18-
import { QueryLanguage } from "../common/query-language";
1919

2020
export type RunQueryOptions = {
2121
cliServer: Pick<CodeQLCliServer, "resolveQlpacks">;
@@ -41,7 +41,14 @@ export async function runQuery({
4141
// For a reference of what this should do in the future, see the previous implementation in
4242
// https://github.com/github/vscode-codeql/blob/089d3566ef0bc67d9b7cc66e8fd6740b31c1c0b0/extensions/ql-vscode/src/data-extensions-editor/external-api-usage-query.ts#L33-L72
4343

44-
const query = fetchExternalApiQueries[databaseItem.language as QueryLanguage];
44+
if (!isQueryLanguage(databaseItem.language)) {
45+
void showAndLogExceptionWithTelemetry(
46+
redactableError`Unsupported database language ${databaseItem.language}`,
47+
);
48+
return;
49+
}
50+
51+
const query = fetchExternalApiQueries[databaseItem.language];
4552
if (!query) {
4653
void showAndLogExceptionWithTelemetry(
4754
redactableError`No external API usage query found for language ${databaseItem.language}`,

extensions/ql-vscode/src/databases/local-databases.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
isFolderAlreadyInWorkspace,
1313
getFirstWorkspaceFolder,
1414
showNeverAskAgainDialog,
15+
isQueryLanguage,
1516
} from "../helpers";
1617
import { ProgressCallback, withProgress } from "../common/vscode/progress";
1718
import {
@@ -32,7 +33,6 @@ import {
3233
setAutogenerateQlPacks,
3334
} from "../config";
3435
import { QlPackGenerator } from "../qlpack-generator";
35-
import { QueryLanguage } from "../common/query-language";
3636
import { App } from "../common/app";
3737
import { existsSync } from "fs";
3838

@@ -739,6 +739,13 @@ export class DatabaseManager extends DisposableObject {
739739
return;
740740
}
741741

742+
if (!isQueryLanguage(databaseItem.language)) {
743+
void this.logger.log(
744+
"Could not create skeleton QL pack because the selected database's language is not supported.",
745+
);
746+
return;
747+
}
748+
742749
const firstWorkspaceFolder = getFirstWorkspaceFolder();
743750
const folderName = `codeql-custom-queries-${databaseItem.language}`;
744751

@@ -769,7 +776,7 @@ export class DatabaseManager extends DisposableObject {
769776
try {
770777
const qlPackGenerator = new QlPackGenerator(
771778
folderName,
772-
databaseItem.language as QueryLanguage,
779+
databaseItem.language,
773780
this.cli,
774781
firstWorkspaceFolder,
775782
);

extensions/ql-vscode/src/helpers.ts

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import { QueryMetadata } from "./pure/interface-types";
2525
import { telemetryListener } from "./telemetry";
2626
import { RedactableError } from "./pure/errors";
2727
import { getQlPackPath } from "./pure/ql";
28-
import { dbSchemeToLanguage } from "./common/query-language";
28+
import { dbSchemeToLanguage, QueryLanguage } from "./common/query-language";
2929
import { isCodespacesTemplate } from "./config";
3030
import { AppCommandManager } from "./common/commands";
3131

@@ -726,14 +726,18 @@ export async function isLikelyDbLanguageFolder(dbPath: string) {
726726
);
727727
}
728728

729+
export function isQueryLanguage(language: string): language is QueryLanguage {
730+
return Object.values(QueryLanguage).includes(language as QueryLanguage);
731+
}
732+
729733
/**
730734
* Finds the language that a query targets.
731735
* If it can't be autodetected, prompt the user to specify the language manually.
732736
*/
733737
export async function findLanguage(
734738
cliServer: CodeQLCliServer,
735739
queryUri: Uri | undefined,
736-
): Promise<string | undefined> {
740+
): Promise<QueryLanguage | undefined> {
737741
const uri = queryUri || Window.activeTextEditor?.document.uri;
738742
if (uri !== undefined) {
739743
try {
@@ -743,7 +747,14 @@ export async function findLanguage(
743747
);
744748
const language = Object.keys(queryInfo.byLanguage)[0];
745749
void extLogger.log(`Detected query language: ${language}`);
746-
return language;
750+
751+
if (isQueryLanguage(language)) {
752+
return language;
753+
}
754+
755+
void extLogger.log(
756+
"Query language is unsupported. Select language manually.",
757+
);
747758
} catch (e) {
748759
void extLogger.log(
749760
"Could not autodetect query language. Select language manually.",
@@ -758,7 +769,7 @@ export async function findLanguage(
758769
export async function askForLanguage(
759770
cliServer: CodeQLCliServer,
760771
throwOnEmpty = true,
761-
): Promise<string | undefined> {
772+
): Promise<QueryLanguage | undefined> {
762773
const language = await Window.showQuickPick(
763774
await cliServer.getSupportedLanguages(),
764775
{
@@ -775,7 +786,16 @@ export async function askForLanguage(
775786
"Language not found. Language must be specified manually.",
776787
);
777788
}
789+
return undefined;
778790
}
791+
792+
if (!isQueryLanguage(language)) {
793+
void showAndLogErrorMessage(
794+
`Language '${language}' is not supported. Language must be specified manually.`,
795+
);
796+
return undefined;
797+
}
798+
779799
return language;
780800
}
781801

extensions/ql-vscode/src/skeleton-query-wizard.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export const QUERY_LANGUAGE_TO_DATABASE_REPO: QueryLanguagesToDatabaseMap = {
4141
};
4242

4343
export class SkeletonQueryWizard {
44-
private language: string | undefined;
44+
private language: QueryLanguage | undefined;
4545
private fileName = "example.ql";
4646
private qlPackStoragePath: string | undefined;
4747

@@ -154,6 +154,9 @@ export class SkeletonQueryWizard {
154154
if (this.folderName === undefined) {
155155
throw new Error("Folder name is undefined");
156156
}
157+
if (this.language === undefined) {
158+
throw new Error("Language is undefined");
159+
}
157160

158161
this.progress({
159162
message: "Creating skeleton QL pack around query",
@@ -164,7 +167,7 @@ export class SkeletonQueryWizard {
164167
try {
165168
const qlPackGenerator = new QlPackGenerator(
166169
this.folderName,
167-
this.language as QueryLanguage,
170+
this.language,
168171
this.cliServer,
169172
this.qlPackStoragePath,
170173
);
@@ -181,6 +184,9 @@ export class SkeletonQueryWizard {
181184
if (this.folderName === undefined) {
182185
throw new Error("Folder name is undefined");
183186
}
187+
if (this.language === undefined) {
188+
throw new Error("Language is undefined");
189+
}
184190

185191
this.progress({
186192
message:
@@ -192,7 +198,7 @@ export class SkeletonQueryWizard {
192198
try {
193199
const qlPackGenerator = new QlPackGenerator(
194200
this.folderName,
195-
this.language as QueryLanguage,
201+
this.language,
196202
this.cliServer,
197203
this.qlPackStoragePath,
198204
);

extensions/ql-vscode/src/variant-analysis/run-remote-query.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import {
3939
QLPACK_FILENAMES,
4040
QLPACK_LOCK_FILENAMES,
4141
} from "../pure/ql";
42+
import { QueryLanguage } from "../common/query-language";
4243

4344
export interface QlPack {
4445
name: string;
@@ -76,7 +77,7 @@ async function generateQueryPack(
7677
const targetQueryFileName = join(queryPackDir, packRelativePath);
7778
const workspaceFolders = getOnDiskWorkspaceFolders();
7879

79-
let language: string | undefined;
80+
let language: QueryLanguage | undefined;
8081

8182
// Check if the query is already in a query pack.
8283
// If so, copy the entire query pack to the temporary directory.

0 commit comments

Comments
 (0)