/**
 * Git URL parser for package source resolution.
 *
 * Parses SSH, HTTPS, SCP-like, and shorthand git URLs (with optional @ref suffixes)
 * into a normalized GitSource structure. Uses `hosted-git-info` for GitHub/GitLab/Bitbucket
 * shorthand, with a generic fallback for self-hosted repos.
 */
import hostedGitInfo from 'hosted-git-info';
function splitRef(url) {
    const scpLikeMatch = url.match(/^git@([^:]+):(.+)$/);
    if (scpLikeMatch) {
        const pathWithMaybeRef = scpLikeMatch[2] ?? '';
        const refSeparator = pathWithMaybeRef.indexOf('@');
        if (refSeparator < 0)
            return { repo: url };
        const repoPath = pathWithMaybeRef.slice(0, refSeparator);
        const ref = pathWithMaybeRef.slice(refSeparator + 1);
        if (!repoPath || !ref)
            return { repo: url };
        return {
            repo: `git@${scpLikeMatch[1] ?? ''}:${repoPath}`,
            ref
        };
    }
    if (url.includes('://')) {
        try {
            const parsed = new URL(url);
            const pathWithMaybeRef = parsed.pathname.replace(/^\/+/, '');
            const refSeparator = pathWithMaybeRef.indexOf('@');
            if (refSeparator < 0)
                return { repo: url };
            const repoPath = pathWithMaybeRef.slice(0, refSeparator);
            const ref = pathWithMaybeRef.slice(refSeparator + 1);
            if (!repoPath || !ref)
                return { repo: url };
            parsed.pathname = `/${repoPath}`;
            return {
                repo: parsed.toString().replace(/\/$/, ''),
                ref
            };
        }
        catch {
            return { repo: url };
        }
    }
    const slashIndex = url.indexOf('/');
    if (slashIndex < 0) {
        return { repo: url };
    }
    const host = url.slice(0, slashIndex);
    const pathWithMaybeRef = url.slice(slashIndex + 1);
    const refSeparator = pathWithMaybeRef.indexOf('@');
    if (refSeparator < 0) {
        return { repo: url };
    }
    const repoPath = pathWithMaybeRef.slice(0, refSeparator);
    const ref = pathWithMaybeRef.slice(refSeparator + 1);
    if (!repoPath || !ref) {
        return { repo: url };
    }
    return {
        repo: `${host}/${repoPath}`,
        ref
    };
}
function parseGenericGitUrl(url) {
    const { repo: repoWithoutRef, ref } = splitRef(url);
    let repo = repoWithoutRef;
    let host = '';
    let path = '';
    const scpLikeMatch = repoWithoutRef.match(/^git@([^:]+):(.+)$/);
    if (scpLikeMatch) {
        host = scpLikeMatch[1] ?? '';
        path = scpLikeMatch[2] ?? '';
    }
    else if (repoWithoutRef.startsWith('https://') ||
        repoWithoutRef.startsWith('http://') ||
        repoWithoutRef.startsWith('ssh://') ||
        repoWithoutRef.startsWith('git://')) {
        try {
            const parsed = new URL(repoWithoutRef);
            host = parsed.hostname;
            path = parsed.pathname.replace(/^\/+/, '');
        }
        catch {
            return null;
        }
    }
    else {
        const slashIndex = repoWithoutRef.indexOf('/');
        if (slashIndex < 0) {
            return null;
        }
        host = repoWithoutRef.slice(0, slashIndex);
        path = repoWithoutRef.slice(slashIndex + 1);
        if (!host.includes('.') && host !== 'localhost') {
            return null;
        }
        repo = `https://${repoWithoutRef}`;
    }
    const normalizedPath = path.replace(/\.git$/, '').replace(/^\/+/, '');
    if (!host || !normalizedPath || normalizedPath.split('/').length < 2) {
        return null;
    }
    return {
        type: 'git',
        repo,
        host,
        path: normalizedPath,
        ref,
        pinned: Boolean(ref)
    };
}
/**
 * Parse git source into a GitSource.
 *
 * Rules:
 * - With git: prefix, accept all historical shorthand forms.
 * - Without git: prefix, only accept explicit protocol URLs.
 */
export function parseGitUrl(source) {
    const trimmed = source.trim();
    const hasGitPrefix = trimmed.startsWith('git:');
    const url = hasGitPrefix ? trimmed.slice(4).trim() : trimmed;
    if (!hasGitPrefix && !/^(https?|ssh|git):\/\//i.test(url)) {
        return null;
    }
    const split = splitRef(url);
    const hostedCandidates = [split.ref ? `${split.repo}#${split.ref}` : undefined, url].filter((value) => Boolean(value));
    for (const candidate of hostedCandidates) {
        const info = hostedGitInfo.fromUrl(candidate);
        if (info) {
            if (split.ref && info.project?.includes('@')) {
                continue;
            }
            const useHttpsPrefix = !split.repo.startsWith('http://') &&
                !split.repo.startsWith('https://') &&
                !split.repo.startsWith('ssh://') &&
                !split.repo.startsWith('git://') &&
                !split.repo.startsWith('git@');
            return {
                type: 'git',
                repo: useHttpsPrefix ? `https://${split.repo}` : split.repo,
                host: info.domain || '',
                path: `${info.user}/${info.project}`.replace(/\.git$/, ''),
                ref: info.committish || split.ref || undefined,
                pinned: Boolean(info.committish || split.ref)
            };
        }
    }
    const httpsCandidates = [
        split.ref ? `https://${split.repo}#${split.ref}` : undefined,
        `https://${url}`
    ].filter((value) => Boolean(value));
    for (const candidate of httpsCandidates) {
        const info = hostedGitInfo.fromUrl(candidate);
        if (info) {
            if (split.ref && info.project?.includes('@')) {
                continue;
            }
            return {
                type: 'git',
                repo: `https://${split.repo}`,
                host: info.domain || '',
                path: `${info.user}/${info.project}`.replace(/\.git$/, ''),
                ref: info.committish || split.ref || undefined,
                pinned: Boolean(info.committish || split.ref)
            };
        }
    }
    return parseGenericGitUrl(url);
}
//# sourceMappingURL=git.js.map