-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathissue-content-parser.ts
85 lines (68 loc) · 3.21 KB
/
issue-content-parser.ts
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
import { GitHubIssue, GitHubIssueReference, GitHubRepoReference } from "./models";
import { parseIssuesUrls, parseIssueUrl } from "./utils";
export class IssueContentParser {
public extractIssueTasklist(issue: GitHubIssue): GitHubIssueReference[] {
const contentLines = issue.body?.split("\n") ?? [];
return contentLines
.filter(x => this.isTaskListLine(x))
.map(x => x.substring(6))
.map(x => parseIssueUrl(x))
.filter((x): x is GitHubIssueReference => x !== null);
}
public extractIssueDependencies(issue: GitHubIssue, repoRef: GitHubRepoReference): GitHubIssueReference[] {
const contentLines = issue.body?.split("\n") ?? [];
return contentLines
.filter(x => this.isDependencyLine(x))
.map(x => parseIssuesUrls(x, repoRef))
.flat()
.filter((x): x is GitHubIssueReference => x !== null);
}
public replaceIssueContent(issue: GitHubIssue, sectionTitle: string, newSectionContent: string): string {
const contentLines = issue.body?.split("\n") ?? [];
const sectionStartIndex = contentLines.findIndex(x => this.isMarkdownHeaderLine(x, sectionTitle));
if (sectionStartIndex === -1) {
throw new Error(`Markdown header '${sectionTitle}' is not found in issue body.`);
}
const sectionEndIndex = contentLines.findIndex(
(x, index) => index > sectionStartIndex && this.isMarkdownHeaderLine(x)
);
return [
...contentLines.slice(0, sectionStartIndex + 1),
newSectionContent,
"",
...contentLines.slice(sectionEndIndex !== -1 ? sectionEndIndex : contentLines.length),
].join("\n");
}
public isIssueClosed(issue: GitHubIssue): boolean {
return issue.state === "closed";
}
public isIssueContentIdentical(issue: GitHubIssue, newIssueContent: string) {
// GitHub automatically replace "\n" to "\r\n" line endings when issue body is modified through GitHub UI.
// Replace "\r\n" to "\n" before comparing content to avoid unnecessary issue updates.
const rawIssueBody = issue.body ?? "";
const formattedIssueBody = rawIssueBody.replaceAll("\r\n", "\n");
const formattedNewIssueContent = newIssueContent.replaceAll("\r\n", "\n");
return formattedIssueBody === formattedNewIssueContent;
}
public isMarkdownHeaderLine(str: string, sectionTitle?: string): boolean {
if (!str.startsWith("#")) {
return false;
}
const trimmedLine = str.replace(/^#+/, "").trim();
if (!trimmedLine) {
return false;
}
if (!sectionTitle) {
return true;
}
return trimmedLine.toLowerCase() === sectionTitle.toLocaleLowerCase();
}
public isTaskListLine(str: string): boolean {
return str.startsWith("- [ ] ") || str.startsWith("- [x] ");
}
public isDependencyLine(str: string): boolean {
const dependencyLinePrefixes = ["Dependencies: ", "Depends on ", "Depends on: "];
const formattedLine = str.toLowerCase();
return dependencyLinePrefixes.some(x => formattedLine.startsWith(x.toLowerCase()));
}
}