diff --git a/src/core/url.ts b/src/core/url.ts index 0ef82eff..2de817bc 100644 --- a/src/core/url.ts +++ b/src/core/url.ts @@ -1,6 +1,5 @@ import { GIT_PLUS_PREFIX_RE, GIT_PROTOCOL_PREFIX_RE, GIT_SUFFIX_RE, GITHUB_SSH_URL_PREFIX_RE } from './regex.ts' -const STATIC_REGEX_1 = /github\.com\/([^/]+)\/([^/]+?)(?:\.git)?(?:[/#]|$)/ const STATIC_REGEX_3 = /#.*$/ const STATIC_REGEX_7 = /^git@github\.com:/ const STATIC_REGEX_8 = /^(?:127\.|10\.|172\.(?:1[6-9]|2\d|3[01])\.|192\.168\.|169\.254\.)/ @@ -17,10 +16,19 @@ const STATIC_REGEX_9 = /^\[(?:f[cd]|fe[89ab]|::ffff:)/i * Parse owner/repo from GitHub URL */ export function parseGitHubUrl(url: string): { owner: string, repo: string } | null { - const match = url.match(STATIC_REGEX_1) - if (!match) + try { + const parsed = new URL(url) + if (parsed.hostname !== 'github.com' && parsed.hostname !== 'www.github.com') + return null + const [, owner, repoWithSuffix] = parsed.pathname.split('/') + const repo = repoWithSuffix?.replace(GIT_SUFFIX_RE, '') + if (!owner || !repo) + return null + return { owner, repo } + } + catch { return null - return { owner: match[1]!, repo: match[2]! } + } } /** Parse owner/repo slug from GitHub URL */ diff --git a/test/unit/sources-utils.test.ts b/test/unit/sources-utils.test.ts index 66cebeac..42896e1d 100644 --- a/test/unit/sources-utils.test.ts +++ b/test/unit/sources-utils.test.ts @@ -36,6 +36,10 @@ describe('sources/utils', () => { owner: 'owner', repo: 'repo', }) + expect(parseGitHubUrl('https://github.com/owner/repo.git/tree/main')).toEqual({ + owner: 'owner', + repo: 'repo', + }) }) it('strips .git suffix from repo name', () => { @@ -52,6 +56,9 @@ describe('sources/utils', () => { it('returns null for invalid URLs', () => { expect(parseGitHubUrl('https://gitlab.com/owner/repo')).toBeNull() expect(parseGitHubUrl('not-a-url')).toBeNull() + expect(parseGitHubUrl('https://notgithub.com/owner/repo')).toBeNull() + expect(parseGitHubUrl('https://example.com/github.com/owner/repo')).toBeNull() + expect(parseGitHubUrl('https://github.com/owner/.git')).toBeNull() }) })