{
  "version": 3,
  "sources": ["../../../../src/packages/git-resolver/parsePref.ts"],
  "sourcesContent": ["// cspell:ignore sshurl\nimport urlLib, { URL } from 'node:url';\nimport { fetchWithAgent } from '../fetch/index.ts';\nimport type { AgentOptions } from '../network.agent/index.ts';\n\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport git from 'graceful-git';\nimport HostedGit from 'hosted-git-info';\n\nexport type HostedPackageSpec = {\n  fetchSpec: string;\n  hosted?:\n    | {\n        type: string;\n        user: string;\n        project: string;\n        committish: string;\n        tarball?: (() => string | undefined) | undefined;\n      }\n    | undefined;\n  normalizedPref: string;\n  gitCommittish: string | null;\n  gitRange?: string | undefined;\n  path?: string | undefined;\n};\n\nconst gitProtocols = new Set([\n  'git',\n  'git+http',\n  'git+https',\n  'git+rsync',\n  'git+ftp',\n  'git+file',\n  'git+ssh',\n  'ssh',\n]);\n\nexport async function parsePref(\n  pref: string,\n  opts: AgentOptions\n): Promise<HostedPackageSpec | null> {\n  const hosted = HostedGit.fromUrl(pref);\n\n  if (hosted != null) {\n    return fromHostedGit(hosted, opts);\n  }\n\n  const colonsPos = pref.indexOf(':');\n\n  if (colonsPos === -1) {\n    return null;\n  }\n\n  const protocol = pref.slice(0, colonsPos);\n\n  if (protocol && gitProtocols.has(protocol.toLocaleLowerCase())) {\n    const correctPref = correctUrl(pref);\n\n    const url = new URL(correctPref);\n\n    if (!url.protocol) {\n      return null;\n    }\n\n    const hash =\n      url.hash.length > 1 ? decodeURIComponent(url.hash.slice(1)) : null;\n\n    return {\n      fetchSpec: urlToFetchSpec(url),\n      normalizedPref: pref,\n      ...parseGitParams(hash),\n    };\n  }\n\n  return null;\n}\n\nfunction urlToFetchSpec(url: URL): string {\n  url.hash = '';\n  const fetchSpec = urlLib.format(url);\n  if (fetchSpec.startsWith('git+')) {\n    return fetchSpec.slice(4);\n  }\n  return fetchSpec;\n}\n\nasync function fromHostedGit(\n  hosted: HostedGit,\n  agentOptions: AgentOptions\n): Promise<HostedPackageSpec> {\n  let fetchSpec: string | null = null;\n\n  // try git/https url before fallback to ssh url\n  const gitHttpsUrl = hosted.https({ noCommittish: true, noGitPlus: true });\n\n  if (\n    typeof gitHttpsUrl === 'string' &&\n    (await isRepoPublic(gitHttpsUrl, agentOptions)) &&\n    (await accessRepository(gitHttpsUrl))\n  ) {\n    fetchSpec = gitHttpsUrl;\n  } else {\n    const gitSshUrl = hosted.ssh({ noCommittish: true });\n\n    if (typeof gitSshUrl === 'string' && (await accessRepository(gitSshUrl))) {\n      fetchSpec = gitSshUrl;\n    }\n  }\n\n  if (fetchSpec === null || fetchSpec === '') {\n    const httpsUrl: string | null = hosted.https({\n      noGitPlus: true,\n      noCommittish: true,\n    });\n\n    if (httpsUrl !== '') {\n      if (\n        (typeof hosted.auth === 'string' ||\n          !(await isRepoPublic(httpsUrl, agentOptions))) &&\n        (await accessRepository(httpsUrl))\n      ) {\n        return {\n          fetchSpec: httpsUrl,\n          hosted: {\n            ...hosted,\n            // TODO: _fill is not typed\n            // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n            // @ts-ignore\n            _fill: hosted._fill,\n            tarball: undefined,\n          },\n          normalizedPref: `git+${httpsUrl}`,\n          ...parseGitParams(hosted.committish ?? null),\n        };\n      }\n\n      try {\n        // when git ls-remote private repo, it asks for login credentials.\n        // use HTTP HEAD request to test whether this is a private repo, to avoid login prompt.\n        // this is very similar to yarn classic's behavior.\n        // npm instead tries git ls-remote directly which prompts user for login credentials.\n\n        // HTTP HEAD on https://domain/user/repo, strip out \".git\"\n        const response = await fetchWithAgent(httpsUrl.replace(/\\.git$/, ''), {\n          method: 'HEAD',\n          follow: 0,\n          retry: { retries: 0 },\n          agentOptions,\n        });\n        if (response.ok) {\n          fetchSpec = httpsUrl;\n        }\n      } catch {\n        // ignore\n      }\n    }\n  }\n\n  if (fetchSpec === null || fetchSpec === '') {\n    // use ssh url for likely private repo\n    fetchSpec = hosted.sshurl({ noCommittish: true });\n  }\n\n  return {\n    fetchSpec,\n    hosted: {\n      ...hosted,\n      // TODO: _fill is not typed\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore\n      _fill: hosted._fill,\n      tarball: hosted.tarball,\n    },\n    normalizedPref: hosted.shortcut(),\n    ...parseGitParams(hosted.committish ?? null),\n  };\n}\n\nasync function isRepoPublic(\n  httpsUrl: string,\n  agentOptions: AgentOptions\n): Promise<boolean> {\n  try {\n    const response = await fetchWithAgent(httpsUrl.replace(/\\.git$/, ''), {\n      method: 'HEAD',\n      follow: 0,\n      retry: { retries: 0 },\n      agentOptions,\n    });\n    return response.ok;\n  } catch {\n    return false;\n  }\n}\n\nasync function accessRepository(repository: string): Promise<boolean> {\n  try {\n    await git(['ls-remote', '--exit-code', repository, 'HEAD'], { retries: 0 });\n    return true;\n  } catch {\n    return false;\n  }\n}\n\ntype GitParsedParams = Pick<\n  HostedPackageSpec,\n  'gitCommittish' | 'gitRange' | 'path'\n>;\n\nfunction parseGitParams(committish: string | null): GitParsedParams {\n  const result: GitParsedParams = { gitCommittish: null };\n\n  if (committish === null || committish === '') {\n    return result;\n  }\n\n  const params = committish.split('&');\n\n  for (const param of params) {\n    if (param.length >= 7 && param.slice(0, 7) === 'semver:') {\n      result.gitRange = param.slice(7);\n    } else if (param.slice(0, 5) === 'path:') {\n      result.path = param.slice(5);\n    } else {\n      result.gitCommittish = param;\n    }\n  }\n\n  return result;\n}\n\n// handle SCP-like URLs\n// see https://github.com/yarnpkg/yarn/blob/5682d55/src/util/git.js#L103\nfunction correctUrl(gitUrl: string): string {\n  const parsed = urlLib.parse(gitUrl.replace(/^git\\+/, '')); // eslint-disable-line n/no-deprecated-api\n\n  if (\n    parsed.protocol === 'ssh:' &&\n    typeof parsed.hostname === 'string' &&\n    parsed.hostname !== '' &&\n    typeof parsed.pathname === 'string' &&\n    parsed.pathname !== '' &&\n    parsed.pathname.startsWith('/:') &&\n    parsed.port === null\n  ) {\n    parsed.pathname = parsed.pathname.replace(/^\\/:/, '');\n    return urlLib.format(parsed);\n  }\n\n  return gitUrl;\n}\n"],
  "mappings": "AACA,OAAO,UAAU,WAAW;AAC5B,SAAS,sBAAsB;AAK/B,OAAO,SAAS;AAChB,OAAO,eAAe;AAmBtB,MAAM,eAAe,oBAAI,IAAI;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,eAAsB,UACpB,MACA,MACmC;AACnC,QAAM,SAAS,UAAU,QAAQ,IAAI;AAErC,MAAI,UAAU,MAAM;AAClB,WAAO,cAAc,QAAQ,IAAI;AAAA,EACnC;AAEA,QAAM,YAAY,KAAK,QAAQ,GAAG;AAElC,MAAI,cAAc,IAAI;AACpB,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,KAAK,MAAM,GAAG,SAAS;AAExC,MAAI,YAAY,aAAa,IAAI,SAAS,kBAAkB,CAAC,GAAG;AAC9D,UAAM,cAAc,WAAW,IAAI;AAEnC,UAAM,MAAM,IAAI,IAAI,WAAW;AAE/B,QAAI,CAAC,IAAI,UAAU;AACjB,aAAO;AAAA,IACT;AAEA,UAAM,OACJ,IAAI,KAAK,SAAS,IAAI,mBAAmB,IAAI,KAAK,MAAM,CAAC,CAAC,IAAI;AAEhE,WAAO;AAAA,MACL,WAAW,eAAe,GAAG;AAAA,MAC7B,gBAAgB;AAAA,MAChB,GAAG,eAAe,IAAI;AAAA,IACxB;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,eAAe,KAAkB;AACxC,MAAI,OAAO;AACX,QAAM,YAAY,OAAO,OAAO,GAAG;AACnC,MAAI,UAAU,WAAW,MAAM,GAAG;AAChC,WAAO,UAAU,MAAM,CAAC;AAAA,EAC1B;AACA,SAAO;AACT;AAEA,eAAe,cACb,QACA,cAC4B;AAC5B,MAAI,YAA2B;AAG/B,QAAM,cAAc,OAAO,MAAM,EAAE,cAAc,MAAM,WAAW,KAAK,CAAC;AAExE,MACE,OAAO,gBAAgB,YACtB,MAAM,aAAa,aAAa,YAAY,KAC5C,MAAM,iBAAiB,WAAW,GACnC;AACA,gBAAY;AAAA,EACd,OAAO;AACL,UAAM,YAAY,OAAO,IAAI,EAAE,cAAc,KAAK,CAAC;AAEnD,QAAI,OAAO,cAAc,YAAa,MAAM,iBAAiB,SAAS,GAAI;AACxE,kBAAY;AAAA,IACd;AAAA,EACF;AAEA,MAAI,cAAc,QAAQ,cAAc,IAAI;AAC1C,UAAM,WAA0B,OAAO,MAAM;AAAA,MAC3C,WAAW;AAAA,MACX,cAAc;AAAA,IAChB,CAAC;AAED,QAAI,aAAa,IAAI;AACnB,WACG,OAAO,OAAO,SAAS,YACtB,CAAE,MAAM,aAAa,UAAU,YAAY,MAC5C,MAAM,iBAAiB,QAAQ,GAChC;AACA,eAAO;AAAA,UACL,WAAW;AAAA,UACX,QAAQ;AAAA,YACN,GAAG;AAAA;AAAA;AAAA;AAAA,YAIH,OAAO,OAAO;AAAA,YACd,SAAS;AAAA,UACX;AAAA,UACA,gBAAgB,OAAO,QAAQ;AAAA,UAC/B,GAAG,eAAe,OAAO,cAAc,IAAI;AAAA,QAC7C;AAAA,MACF;AAEA,UAAI;AAOF,cAAM,WAAW,MAAM,eAAe,SAAS,QAAQ,UAAU,EAAE,GAAG;AAAA,UACpE,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,OAAO,EAAE,SAAS,EAAE;AAAA,UACpB;AAAA,QACF,CAAC;AACD,YAAI,SAAS,IAAI;AACf,sBAAY;AAAA,QACd;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAEA,MAAI,cAAc,QAAQ,cAAc,IAAI;AAE1C,gBAAY,OAAO,OAAO,EAAE,cAAc,KAAK,CAAC;AAAA,EAClD;AAEA,SAAO;AAAA,IACL;AAAA,IACA,QAAQ;AAAA,MACN,GAAG;AAAA;AAAA;AAAA;AAAA,MAIH,OAAO,OAAO;AAAA,MACd,SAAS,OAAO;AAAA,IAClB;AAAA,IACA,gBAAgB,OAAO,SAAS;AAAA,IAChC,GAAG,eAAe,OAAO,cAAc,IAAI;AAAA,EAC7C;AACF;AAEA,eAAe,aACb,UACA,cACkB;AAClB,MAAI;AACF,UAAM,WAAW,MAAM,eAAe,SAAS,QAAQ,UAAU,EAAE,GAAG;AAAA,MACpE,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,OAAO,EAAE,SAAS,EAAE;AAAA,MACpB;AAAA,IACF,CAAC;AACD,WAAO,SAAS;AAAA,EAClB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAe,iBAAiB,YAAsC;AACpE,MAAI;AACF,UAAM,IAAI,CAAC,aAAa,eAAe,YAAY,MAAM,GAAG,EAAE,SAAS,EAAE,CAAC;AAC1E,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAOA,SAAS,eAAe,YAA4C;AAClE,QAAM,SAA0B,EAAE,eAAe,KAAK;AAEtD,MAAI,eAAe,QAAQ,eAAe,IAAI;AAC5C,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,WAAW,MAAM,GAAG;AAEnC,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,UAAU,KAAK,MAAM,MAAM,GAAG,CAAC,MAAM,WAAW;AACxD,aAAO,WAAW,MAAM,MAAM,CAAC;AAAA,IACjC,WAAW,MAAM,MAAM,GAAG,CAAC,MAAM,SAAS;AACxC,aAAO,OAAO,MAAM,MAAM,CAAC;AAAA,IAC7B,OAAO;AACL,aAAO,gBAAgB;AAAA,IACzB;AAAA,EACF;AAEA,SAAO;AACT;AAIA,SAAS,WAAW,QAAwB;AAC1C,QAAM,SAAS,OAAO,MAAM,OAAO,QAAQ,UAAU,EAAE,CAAC;AAExD,MACE,OAAO,aAAa,UACpB,OAAO,OAAO,aAAa,YAC3B,OAAO,aAAa,MACpB,OAAO,OAAO,aAAa,YAC3B,OAAO,aAAa,MACpB,OAAO,SAAS,WAAW,IAAI,KAC/B,OAAO,SAAS,MAChB;AACA,WAAO,WAAW,OAAO,SAAS,QAAQ,QAAQ,EAAE;AACpD,WAAO,OAAO,OAAO,MAAM;AAAA,EAC7B;AAEA,SAAO;AACT;",
  "names": []
}
