import type { GitHubOwnerRepo } from '../../shared/types' export type GitHubRemoteIdentity = GitHubOwnerRepo & { host: string } function normalizeGitHubRemoteHost(host: string): string { const normalizedHost = host.toLowerCase() // Why: GitHub documents ssh.github.com:443 as SSH-over-HTTPS for github.com repos. return normalizedHost === 'ssh.github.com' ? 'github.com' : normalizedHost } function parseGitHubRemotePath(path: string): Pick | null { const parts = path.replace(/^\/+/, '').replace(/\/+$/, '').split('/') if (parts.length !== 2) { return null } const [owner, repoWithSuffix] = parts const repo = repoWithSuffix.replace(/\.git$/i, '') if (!owner || !repo) { return null } return { owner, repo } } export function parseGitHubRemoteIdentity(remoteUrl: string): GitHubRemoteIdentity | null { const trimmed = remoteUrl.trim() const sshMatch = trimmed.match(/^git@([^:]+):([^/]+)\/([^/]+?)(?:\.git)?$/i) if (sshMatch) { return { host: normalizeGitHubRemoteHost(sshMatch[1]), owner: sshMatch[2], repo: sshMatch[3] } } try { const url = new URL(trimmed) if (!['git:', 'git+ssh:', 'http:', 'https:', 'ssh:'].includes(url.protocol.toLowerCase())) { return null } const path = parseGitHubRemotePath(url.pathname) return path ? { host: normalizeGitHubRemoteHost(url.hostname), ...path } : null } catch { return null } } export function parseGitHubOwnerRepo(remoteUrl: string): GitHubOwnerRepo | null { const identity = parseGitHubRemoteIdentity(remoteUrl) if (!identity || identity.host.toLowerCase() !== 'github.com') { return null } return { owner: identity.owner, repo: identity.repo } }