mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 08:02:28 +00:00
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Orca <help@stably.ai> Co-authored-by: gsxdsm <gsxdsm@users.noreply.github.com>
47 lines
1.5 KiB
TypeScript
47 lines
1.5 KiB
TypeScript
// Parses a GitHub PR/issue reference from user input — a bare number, "#42", or a
|
|
// full GitHub URL — mirroring the desktop parseGitHubIssueOrPRNumber
|
|
// (src/renderer/src/lib/github-links.ts). Ported (not imported) so the mobile bundle
|
|
// stays free of renderer modules. Returns null for anything unparseable; guards
|
|
// number > 0 so the link flow never persists PR #0.
|
|
const GH_ITEM_PATH_RE = /^\/([^/]+)\/([^/]+)\/(issues|pull)\/(\d+)(?:\/.*)?$/i
|
|
|
|
// Why: this parser is GitHub-specific (the link flow writes the worktree's
|
|
// GitHub linkedPR key), so only github.com / its enterprise subdomains may parse —
|
|
// otherwise `https://example.com/o/r/pull/7` would be mistaken for a GitHub PR.
|
|
function isGitHubHost(hostname: string): boolean {
|
|
const host = hostname.toLowerCase()
|
|
return host === 'github.com' || host.endsWith('.github.com')
|
|
}
|
|
|
|
export function parseGitHubPrReference(input: string): number | null {
|
|
const trimmed = input.trim()
|
|
if (!trimmed) {
|
|
return null
|
|
}
|
|
|
|
const numeric = trimmed.startsWith('#') ? trimmed.slice(1) : trimmed
|
|
if (/^\d+$/.test(numeric)) {
|
|
const n = Number.parseInt(numeric, 10)
|
|
return n > 0 ? n : null
|
|
}
|
|
|
|
let url: URL
|
|
try {
|
|
url = new URL(trimmed)
|
|
} catch {
|
|
return null
|
|
}
|
|
if (url.protocol !== 'https:' && url.protocol !== 'http:') {
|
|
return null
|
|
}
|
|
if (!isGitHubHost(url.hostname)) {
|
|
return null
|
|
}
|
|
const match = GH_ITEM_PATH_RE.exec(url.pathname.replace(/\/+$/, ''))
|
|
if (!match) {
|
|
return null
|
|
}
|
|
const n = Number.parseInt(match[4], 10)
|
|
return n > 0 ? n : null
|
|
}
|