"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const got = require("got");
const git = require("graceful-git");
const HostedGit = require("hosted-git-info");
const url = require("url");
const gitProtocols = new Set([
    'git',
    'git+http',
    'git+https',
    'git+rsync',
    'git+ftp',
    'git+file',
    'git+ssh',
]);
function parsePref(pref) {
    return __awaiter(this, void 0, void 0, function* () {
        const hosted = HostedGit.fromUrl(pref);
        if (hosted) {
            return yield fromHostedGit(hosted);
        }
        const colonsPos = pref.indexOf(':');
        if (colonsPos === -1)
            return null;
        const protocol = pref.substr(0, colonsPos);
        if (protocol && gitProtocols.has(protocol.toLocaleLowerCase())) {
            const urlparse = url.parse(pref);
            if (!urlparse || !urlparse.protocol)
                return null;
            const match = urlparse.protocol === 'git+ssh:' && matchGitScp(pref);
            if (match) {
                return Object.assign({}, match, { normalizedPref: pref });
            }
            return Object.assign({ fetchSpec: urlToFetchSpec(urlparse), normalizedPref: pref }, setGitCommittish(urlparse.hash != null ? urlparse.hash.slice(1) : ''));
        }
        return null;
    });
}
exports.default = parsePref;
function urlToFetchSpec(urlparse) {
    if (urlparse.protocol) {
        urlparse.protocol = urlparse.protocol.replace(/^git[+]/, '');
    }
    delete urlparse.hash;
    return url.format(urlparse);
}
function fromHostedGit(hosted) {
    return __awaiter(this, void 0, void 0, function* () {
        let fetchSpec = null;
        // try git/https url before fallback to ssh url
        const gitUrl = hosted.git({ noCommittish: true });
        if (gitUrl) {
            try {
                yield git(['ls-remote', '--exit-code', gitUrl, 'HEAD'], { retries: 0 });
                fetchSpec = gitUrl;
            }
            catch (e) {
                // ignore
            }
        }
        if (!fetchSpec) {
            const httpsUrl = hosted.https({ noGitPlus: true, noCommittish: true });
            if (httpsUrl) {
                try {
                    // when git ls-remote private repo, it askes for login credentials.
                    // use HTTP HEAD request to test whether this is a private repo.
                    // this is very similar to yarn's behaviour.
                    // npm instead tries git ls-remote directly which prompts user for login credentails.
                    // HTTP HEAD on https://domain/user/repo, strip out ".git"
                    const response = yield got(httpsUrl.substr(0, httpsUrl.length - 4), { method: 'HEAD', followRedirect: false });
                    if (response.statusCode === 200) {
                        fetchSpec = httpsUrl;
                    }
                }
                catch (e) {
                    // ignore
                }
            }
        }
        if (!fetchSpec) {
            // use ssh url for likely private repo
            fetchSpec = hosted.sshurl({ noCommittish: true });
        }
        return Object.assign({ fetchSpec: fetchSpec, hosted, normalizedPref: hosted.shortcut() }, setGitCommittish(hosted.committish));
    });
}
function setGitCommittish(committish) {
    if (committish != null && committish.length >= 7 && committish.slice(0, 7) === 'semver:') {
        return {
            gitCommittish: null,
            gitRange: decodeURIComponent(committish.slice(7)),
        };
    }
    return {
        gitCommittish: committish === '' ? null : committish,
    };
}
function matchGitScp(spec) {
    // git ssh specifiers are overloaded to also use scp-style git
    // specifiers, so we have to parse those out and treat them special.
    // They are NOT true URIs, so we can't hand them to `url.parse`.
    //
    // This regex looks for things that look like:
    // git+ssh://git@my.custom.git.com:username/project.git#deadbeef
    //
    // ...and various combinations. The username in the beginning is *required*.
    const matched = spec.match(/^git\+ssh:\/\/([^:#]+:[^#]+(?:\.git)?)(?:#(.*))?$/i);
    return matched && !matched[1].match(/:[0-9]+\/?.*$/i) && {
        fetchSpec: matched[1],
        gitCommittish: matched[2] == null ? null : matched[2],
    };
}
//# sourceMappingURL=parsePref.js.map