-
Notifications
You must be signed in to change notification settings - Fork 226
Expand file tree
/
Copy pathqlpack-generator.ts
More file actions
118 lines (95 loc) · 3.46 KB
/
qlpack-generator.ts
File metadata and controls
118 lines (95 loc) · 3.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import { mkdir, writeFile } from "fs-extra";
import { dump } from "js-yaml";
import { dirname, join } from "path";
import { Uri } from "vscode";
import { CodeQLCliServer } from "../codeql-cli/cli";
import { QueryLanguage } from "../common/query-language";
import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
import { basename } from "../common/path";
export class QlPackGenerator {
private qlpackName: string | undefined;
private readonly qlpackVersion: string;
private readonly header: string;
private readonly qlpackFileName: string;
private readonly folderUri: Uri;
constructor(
private readonly queryLanguage: QueryLanguage,
private readonly cliServer: CodeQLCliServer,
private readonly storagePath: string,
private readonly queryStoragePath: string,
private readonly includeFolderNameInQlpackName: boolean = false,
) {
this.qlpackVersion = "1.0.0";
this.header = "# This is an automatically generated file.\n\n";
this.qlpackFileName = "codeql-pack.yml";
this.folderUri = Uri.file(this.storagePath);
}
public async generate() {
this.qlpackName = await this.determineQlpackName();
// create QL pack folder and add to workspace
await this.createWorkspaceFolder();
// create codeql-pack.yml
await this.createQlPackYaml();
// create example.ql
await this.createExampleQlFile();
// create codeql-pack.lock.yml
await this.createCodeqlPackLockYaml();
}
private async determineQlpackName(): Promise<string> {
let qlpackBaseName = `getting-started/codeql-extra-queries-${this.queryLanguage}`;
if (this.includeFolderNameInQlpackName) {
const folderBasename = basename(dirname(this.folderUri.fsPath));
if (
folderBasename.includes("codeql") ||
folderBasename.includes("queries")
) {
// If the user has already included "codeql" or "queries" in the folder name, don't include it twice
qlpackBaseName = `getting-started/${folderBasename}-${this.queryLanguage}`;
} else {
qlpackBaseName = `getting-started/codeql-extra-queries-${folderBasename}-${this.queryLanguage}`;
}
}
const existingQlPacks = await this.cliServer.resolveQlpacks(
getOnDiskWorkspaceFolders(),
);
const existingQlPackNames = Object.keys(existingQlPacks);
let qlpackName = qlpackBaseName;
let i = 0;
while (existingQlPackNames.includes(qlpackName)) {
i++;
qlpackName = `${qlpackBaseName}-${i}`;
}
return qlpackName;
}
private async createWorkspaceFolder() {
await mkdir(this.folderUri.fsPath);
}
private async createQlPackYaml() {
const qlPackFilePath = join(this.folderUri.fsPath, this.qlpackFileName);
const qlPackYml = {
name: this.qlpackName,
version: this.qlpackVersion,
dependencies: {},
};
await writeFile(qlPackFilePath, this.header + dump(qlPackYml), "utf8");
}
public async createExampleQlFile(fileName = "example.ql") {
const exampleQlFilePath = join(this.queryStoragePath, fileName);
const exampleQl = `
/**
* This is an automatically generated file
* @name Hello world
* @kind problem
* @problem.severity warning
* @id ${this.queryLanguage}/example/hello-world
*/
import ${this.queryLanguage}
from File f
select f, "Hello, world!"
`.trim();
await writeFile(exampleQlFilePath, exampleQl, "utf8");
}
private async createCodeqlPackLockYaml() {
await this.cliServer.packAdd(this.folderUri.fsPath, this.queryLanguage);
}
}