(input: string)
| 289 | } |
| 290 | |
| 291 | export function parseRepoUrl(input: string): RepoRef | null { |
| 292 | const normalized = normalizeGitUrl(input) |
| 293 | if (!normalized) return null |
| 294 | |
| 295 | try { |
| 296 | const url = new URL(normalized) |
| 297 | const host = url.hostname.toLowerCase() |
| 298 | const parts = url.pathname.split('/').filter(Boolean) |
| 299 | |
| 300 | for (const provider of providers) { |
| 301 | if (!provider.matchHost(host)) continue |
| 302 | const parsed = provider.parsePath(parts) |
| 303 | if (parsed) { |
| 304 | const needsHost = ['gitlab', 'gitea', 'forgejo', 'radicle'].includes(provider.id) |
| 305 | return { |
| 306 | provider: provider.id, |
| 307 | owner: parsed.owner, |
| 308 | repo: parsed.repo, |
| 309 | host: needsHost ? host : undefined, |
| 310 | } |
| 311 | } |
| 312 | } |
| 313 | return null |
| 314 | } catch { |
| 315 | return null |
| 316 | } |
| 317 | } |
| 318 | |
| 319 | /** |
| 320 | * Parse repository field from package.json into repository info. |
no test coverage detected