Skip to content

Commit d8aa8b9

Browse files
committed
Refactor by claude.
1 parent f5415ce commit d8aa8b9

File tree

4 files changed

+117
-63
lines changed

4 files changed

+117
-63
lines changed

src/lib/enhancers/github/GitHubEditEnhancer.tsx

Lines changed: 23 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@ import type {
77
} from "@/lib/enhancer"
88
import { logger } from "@/lib/logger"
99
import { fixupOvertype, modifyDOM } from "../overtype-misc"
10-
import { commonGitHubOptions, prepareGitHubHighlighter } from "./github-common"
10+
import {
11+
commonGitHubOptions,
12+
isGitHubProjectUrl,
13+
isInProjectCommentBox,
14+
parseProjectIssueParam,
15+
prepareGitHubHighlighter,
16+
} from "./github-common"
1117

1218
const GH_EDIT = "GH_EDIT" as const
1319

@@ -30,21 +36,14 @@ export class GitHubEditEnhancer implements CommentEnhancer<GitHubEditSpot> {
3036
}
3137

3238
// Check for project draft edit first
33-
const isProjectDraftEdit = location.pathname.match(
34-
/^\/(?:orgs|users)\/[^/]+\/projects\/\d+(?:\/views\/\d+)?/
35-
)
36-
if (isProjectDraftEdit) {
39+
if (isGitHubProjectUrl(location.pathname)) {
3740
const params = new URLSearchParams(location.search)
3841
const itemId = params.get("itemId")
39-
const issueParam = params.get("issue")
4042

4143
// Handle draft editing (itemId parameter)
4244
if (itemId) {
4345
// Exclude textareas within Shared-module__CommentBox (those are for adding new comments, not editing)
44-
const isInCommentBox = textarea.closest(
45-
'[class*="Shared-module__CommentBox"]'
46-
)
47-
if (!isInCommentBox) {
46+
if (!isInProjectCommentBox(textarea)) {
4847
const unique_key = `github.com:project-draft:${itemId}:edit-body`
4948
logger.debug(
5049
`${this.constructor.name} enhanced project draft body textarea`,
@@ -59,27 +58,20 @@ export class GitHubEditEnhancer implements CommentEnhancer<GitHubEditSpot> {
5958
}
6059

6160
// Handle existing issue comment editing (issue parameter)
62-
if (issueParam) {
63-
// Parse issue parameter: "owner|repo|number"
64-
const parts = issueParam.split("|")
65-
if (parts.length === 3) {
66-
const [owner, repo, numberStr] = parts
67-
const slug = `${owner}/${repo}`
68-
const number = parseInt(numberStr!, 10)
69-
70-
// Edit mode: empty placeholder
71-
// Add new comment mode: has placeholder "Add your comment here..." or similar
72-
if (!textarea.placeholder || textarea.placeholder.trim() === "") {
73-
const unique_key = `github.com:${slug}:${number}:edit-comment`
74-
logger.debug(
75-
`${this.constructor.name} enhanced project issue comment edit textarea`,
76-
unique_key
77-
)
78-
return {
79-
isIssue: true,
80-
type: GH_EDIT,
81-
unique_key,
82-
}
61+
const issueInfo = parseProjectIssueParam(params)
62+
if (issueInfo) {
63+
// Edit mode: empty placeholder
64+
// Add new comment mode: has placeholder "Add your comment here..." or similar
65+
if (!textarea.placeholder || textarea.placeholder.trim() === "") {
66+
const unique_key = `github.com:${issueInfo.slug}:${issueInfo.number}:edit-comment`
67+
logger.debug(
68+
`${this.constructor.name} enhanced project issue comment edit textarea`,
69+
unique_key
70+
)
71+
return {
72+
isIssue: true,
73+
type: GH_EDIT,
74+
unique_key,
8375
}
8476
}
8577
}

src/lib/enhancers/github/GitHubIssueAppendEnhancer.tsx

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,14 @@ import type {
99
} from "@/lib/enhancer"
1010
import { logger } from "@/lib/logger"
1111
import { fixupOvertype, modifyDOM } from "../overtype-misc"
12-
import { commonGitHubOptions, prepareGitHubHighlighter } from "./github-common"
12+
import {
13+
commonGitHubOptions,
14+
extractProjectIssueTitle,
15+
isGitHubProjectUrl,
16+
isInProjectCommentBox,
17+
parseProjectIssueParam,
18+
prepareGitHubHighlighter,
19+
} from "./github-common"
1320

1421
const GH_ISSUE_APPEND = "GH_ISSUE_APPEND" as const
1522

@@ -46,33 +53,19 @@ export class GitHubIssueAppendEnhancer
4653
}
4754

4855
// Check for project URLs with issue parameter first
49-
const isProjectView = location.pathname.match(
50-
/^\/(?:orgs|users)\/[^/]+\/projects\/\d+(?:\/views\/\d+)?/
51-
)
52-
if (isProjectView) {
56+
if (isGitHubProjectUrl(location.pathname)) {
5357
const params = new URLSearchParams(location.search)
54-
const issueParam = params.get("issue")
5558
// Only match textareas within Shared-module__CommentBox (those are for adding new comments)
56-
const isInCommentBox = textarea.closest(
57-
'[class*="Shared-module__CommentBox"]'
58-
)
59-
if (issueParam && isInCommentBox) {
60-
// Parse issue parameter: "owner|repo|number" (URL encoded as owner%7Crepo%7Cnumber)
61-
const parts = issueParam.split("|")
62-
if (parts.length === 3) {
63-
const [owner, repo, numberStr] = parts
64-
const slug = `${owner}/${repo}`
65-
const number = parseInt(numberStr!, 10)
66-
const unique_key = `github.com:${slug}:${number}`
59+
if (isInProjectCommentBox(textarea)) {
60+
const issueInfo = parseProjectIssueParam(params)
61+
if (issueInfo) {
62+
const unique_key = `github.com:${issueInfo.slug}:${issueInfo.number}`
6763
// For project views, the title is in the side panel dialog
68-
const title =
69-
document
70-
.querySelector('[data-testid="issue-title"]')
71-
?.textContent?.trim() || ""
64+
const title = extractProjectIssueTitle()
7265
return {
7366
domain: location.host,
74-
number,
75-
slug,
67+
number: issueInfo.number,
68+
slug: issueInfo.slug,
7669
title,
7770
type: GH_ISSUE_APPEND,
7871
unique_key,

src/lib/enhancers/github/GitHubIssueCreateEnhancer.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ import type {
88
} from "../../enhancer"
99
import { logger } from "../../logger"
1010
import { fixupOvertype, modifyDOM } from "../overtype-misc"
11-
import { commonGitHubOptions, prepareGitHubHighlighter } from "./github-common"
11+
import {
12+
commonGitHubOptions,
13+
extractDialogSlug,
14+
isGitHubProjectUrl,
15+
prepareGitHubHighlighter,
16+
} from "./github-common"
1217

1318
const GH_ISSUE_CREATE = "GH_ISSUE_CREATE" as const
1419

@@ -38,17 +43,12 @@ export class GitHubIssueCreateEnhancer
3843
}
3944

4045
// Check for project board URLs first
41-
const isProjectView = location.pathname.match(
42-
/^\/(?:orgs|users)\/[^/]+\/projects\/\d+(?:\/views\/\d+)?/
43-
)
44-
if (isProjectView) {
46+
if (isGitHubProjectUrl(location.pathname)) {
4547
// Check if we're in a "Create new issue" dialog
4648
const dialog = textarea.closest('[role="dialog"]')
4749
if (dialog) {
48-
const dialogHeading = dialog.querySelector("h1")?.textContent
49-
const slugMatch = dialogHeading?.match(/Create new issue in (.+)/)
50-
if (slugMatch) {
51-
const slug = slugMatch[1]!
50+
const slug = extractDialogSlug(dialog)
51+
if (slug) {
5252
const unique_key = `github.com:${slug}:new`
5353
const titleInput = document.querySelector(
5454
'input[placeholder="Title"]'

src/lib/enhancers/github/github-common.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,72 @@ function githubHighlighter(code: string, language?: string) {
6161
return escapeHtml(code)
6262
}
6363
}
64+
65+
// Project-related helper functions
66+
67+
/**
68+
* Check if the pathname matches a GitHub project URL pattern.
69+
* Matches: /orgs/{org}/projects/{id} or /users/{user}/projects/{id}
70+
* Optional: /views/{viewId} suffix
71+
*/
72+
export function isGitHubProjectUrl(pathname: string): boolean {
73+
return /^\/(?:orgs|users)\/[^/]+\/projects\/\d+(?:\/views\/\d+)?/.test(
74+
pathname
75+
)
76+
}
77+
78+
/**
79+
* Parse the issue parameter from project URLs.
80+
* Format: ?issue=owner|repo|number
81+
* Returns: { slug: "owner/repo", number: 123 } or null if invalid
82+
*/
83+
export function parseProjectIssueParam(
84+
searchParams: URLSearchParams
85+
): { slug: string; number: number } | null {
86+
const issueParam = searchParams.get("issue")
87+
if (!issueParam) return null
88+
89+
const parts = issueParam.split("|")
90+
if (parts.length !== 3) return null
91+
92+
const [owner, repo, numberStr] = parts
93+
const number = parseInt(numberStr!, 10)
94+
95+
if (Number.isNaN(number)) return null
96+
97+
return {
98+
slug: `${owner}/${repo}`,
99+
number,
100+
}
101+
}
102+
103+
/**
104+
* Check if an element is within a project CommentBox container.
105+
* CommentBox containers are used for adding new comments (not editing).
106+
*/
107+
export function isInProjectCommentBox(element: HTMLElement): boolean {
108+
return !!element.closest('[class*="Shared-module__CommentBox"]')
109+
}
110+
111+
/**
112+
* Extract the issue title from a project view.
113+
* Used when viewing issues within a project board.
114+
*/
115+
export function extractProjectIssueTitle(): string {
116+
return (
117+
document
118+
.querySelector('[data-testid="issue-title"]')
119+
?.textContent?.trim() || ""
120+
)
121+
}
122+
123+
/**
124+
* Extract the repository slug from a "Create new issue" dialog heading.
125+
* Heading format: "Create new issue in owner/repo"
126+
* Returns: "owner/repo" or null if not found
127+
*/
128+
export function extractDialogSlug(dialog: Element): string | null {
129+
const dialogHeading = dialog.querySelector("h1")?.textContent
130+
const slugMatch = dialogHeading?.match(/Create new issue in (.+)/)
131+
return slugMatch ? slugMatch[1]! : null
132+
}

0 commit comments

Comments
 (0)