11cb0ef41Sopenharmony_ci'use strict' 21cb0ef41Sopenharmony_cimodule.exports = npa 31cb0ef41Sopenharmony_cimodule.exports.resolve = resolve 41cb0ef41Sopenharmony_cimodule.exports.toPurl = toPurl 51cb0ef41Sopenharmony_cimodule.exports.Result = Result 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ciconst { URL } = require('url') 81cb0ef41Sopenharmony_ciconst HostedGit = require('hosted-git-info') 91cb0ef41Sopenharmony_ciconst semver = require('semver') 101cb0ef41Sopenharmony_ciconst path = global.FAKE_WINDOWS ? require('path').win32 : require('path') 111cb0ef41Sopenharmony_ciconst validatePackageName = require('validate-npm-package-name') 121cb0ef41Sopenharmony_ciconst { homedir } = require('os') 131cb0ef41Sopenharmony_ciconst log = require('proc-log') 141cb0ef41Sopenharmony_ci 151cb0ef41Sopenharmony_ciconst isWindows = process.platform === 'win32' || global.FAKE_WINDOWS 161cb0ef41Sopenharmony_ciconst hasSlashes = isWindows ? /\\|[/]/ : /[/]/ 171cb0ef41Sopenharmony_ciconst isURL = /^(?:git[+])?[a-z]+:/i 181cb0ef41Sopenharmony_ciconst isGit = /^[^@]+@[^:.]+\.[^:]+:.+$/i 191cb0ef41Sopenharmony_ciconst isFilename = /[.](?:tgz|tar.gz|tar)$/i 201cb0ef41Sopenharmony_ci 211cb0ef41Sopenharmony_cifunction npa (arg, where) { 221cb0ef41Sopenharmony_ci let name 231cb0ef41Sopenharmony_ci let spec 241cb0ef41Sopenharmony_ci if (typeof arg === 'object') { 251cb0ef41Sopenharmony_ci if (arg instanceof Result && (!where || where === arg.where)) { 261cb0ef41Sopenharmony_ci return arg 271cb0ef41Sopenharmony_ci } else if (arg.name && arg.rawSpec) { 281cb0ef41Sopenharmony_ci return npa.resolve(arg.name, arg.rawSpec, where || arg.where) 291cb0ef41Sopenharmony_ci } else { 301cb0ef41Sopenharmony_ci return npa(arg.raw, where || arg.where) 311cb0ef41Sopenharmony_ci } 321cb0ef41Sopenharmony_ci } 331cb0ef41Sopenharmony_ci const nameEndsAt = arg[0] === '@' ? arg.slice(1).indexOf('@') + 1 : arg.indexOf('@') 341cb0ef41Sopenharmony_ci const namePart = nameEndsAt > 0 ? arg.slice(0, nameEndsAt) : arg 351cb0ef41Sopenharmony_ci if (isURL.test(arg)) { 361cb0ef41Sopenharmony_ci spec = arg 371cb0ef41Sopenharmony_ci } else if (isGit.test(arg)) { 381cb0ef41Sopenharmony_ci spec = `git+ssh://${arg}` 391cb0ef41Sopenharmony_ci } else if (namePart[0] !== '@' && (hasSlashes.test(namePart) || isFilename.test(namePart))) { 401cb0ef41Sopenharmony_ci spec = arg 411cb0ef41Sopenharmony_ci } else if (nameEndsAt > 0) { 421cb0ef41Sopenharmony_ci name = namePart 431cb0ef41Sopenharmony_ci spec = arg.slice(nameEndsAt + 1) || '*' 441cb0ef41Sopenharmony_ci } else { 451cb0ef41Sopenharmony_ci const valid = validatePackageName(arg) 461cb0ef41Sopenharmony_ci if (valid.validForOldPackages) { 471cb0ef41Sopenharmony_ci name = arg 481cb0ef41Sopenharmony_ci spec = '*' 491cb0ef41Sopenharmony_ci } else { 501cb0ef41Sopenharmony_ci spec = arg 511cb0ef41Sopenharmony_ci } 521cb0ef41Sopenharmony_ci } 531cb0ef41Sopenharmony_ci return resolve(name, spec, where, arg) 541cb0ef41Sopenharmony_ci} 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_ciconst isFilespec = isWindows ? /^(?:[.]|~[/]|[/\\]|[a-zA-Z]:)/ : /^(?:[.]|~[/]|[/]|[a-zA-Z]:)/ 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_cifunction resolve (name, spec, where, arg) { 591cb0ef41Sopenharmony_ci const res = new Result({ 601cb0ef41Sopenharmony_ci raw: arg, 611cb0ef41Sopenharmony_ci name: name, 621cb0ef41Sopenharmony_ci rawSpec: spec, 631cb0ef41Sopenharmony_ci fromArgument: arg != null, 641cb0ef41Sopenharmony_ci }) 651cb0ef41Sopenharmony_ci 661cb0ef41Sopenharmony_ci if (name) { 671cb0ef41Sopenharmony_ci res.setName(name) 681cb0ef41Sopenharmony_ci } 691cb0ef41Sopenharmony_ci 701cb0ef41Sopenharmony_ci if (spec && (isFilespec.test(spec) || /^file:/i.test(spec))) { 711cb0ef41Sopenharmony_ci return fromFile(res, where) 721cb0ef41Sopenharmony_ci } else if (spec && /^npm:/i.test(spec)) { 731cb0ef41Sopenharmony_ci return fromAlias(res, where) 741cb0ef41Sopenharmony_ci } 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_ci const hosted = HostedGit.fromUrl(spec, { 771cb0ef41Sopenharmony_ci noGitPlus: true, 781cb0ef41Sopenharmony_ci noCommittish: true, 791cb0ef41Sopenharmony_ci }) 801cb0ef41Sopenharmony_ci if (hosted) { 811cb0ef41Sopenharmony_ci return fromHostedGit(res, hosted) 821cb0ef41Sopenharmony_ci } else if (spec && isURL.test(spec)) { 831cb0ef41Sopenharmony_ci return fromURL(res) 841cb0ef41Sopenharmony_ci } else if (spec && (hasSlashes.test(spec) || isFilename.test(spec))) { 851cb0ef41Sopenharmony_ci return fromFile(res, where) 861cb0ef41Sopenharmony_ci } else { 871cb0ef41Sopenharmony_ci return fromRegistry(res) 881cb0ef41Sopenharmony_ci } 891cb0ef41Sopenharmony_ci} 901cb0ef41Sopenharmony_ci 911cb0ef41Sopenharmony_ciconst defaultRegistry = 'https://registry.npmjs.org' 921cb0ef41Sopenharmony_ci 931cb0ef41Sopenharmony_cifunction toPurl (arg, reg = defaultRegistry) { 941cb0ef41Sopenharmony_ci const res = npa(arg) 951cb0ef41Sopenharmony_ci 961cb0ef41Sopenharmony_ci if (res.type !== 'version') { 971cb0ef41Sopenharmony_ci throw invalidPurlType(res.type, res.raw) 981cb0ef41Sopenharmony_ci } 991cb0ef41Sopenharmony_ci 1001cb0ef41Sopenharmony_ci // URI-encode leading @ of scoped packages 1011cb0ef41Sopenharmony_ci let purl = 'pkg:npm/' + res.name.replace(/^@/, '%40') + '@' + res.rawSpec 1021cb0ef41Sopenharmony_ci if (reg !== defaultRegistry) { 1031cb0ef41Sopenharmony_ci purl += '?repository_url=' + reg 1041cb0ef41Sopenharmony_ci } 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_ci return purl 1071cb0ef41Sopenharmony_ci} 1081cb0ef41Sopenharmony_ci 1091cb0ef41Sopenharmony_cifunction invalidPackageName (name, valid, raw) { 1101cb0ef41Sopenharmony_ci // eslint-disable-next-line max-len 1111cb0ef41Sopenharmony_ci const err = new Error(`Invalid package name "${name}" of package "${raw}": ${valid.errors.join('; ')}.`) 1121cb0ef41Sopenharmony_ci err.code = 'EINVALIDPACKAGENAME' 1131cb0ef41Sopenharmony_ci return err 1141cb0ef41Sopenharmony_ci} 1151cb0ef41Sopenharmony_ci 1161cb0ef41Sopenharmony_cifunction invalidTagName (name, raw) { 1171cb0ef41Sopenharmony_ci // eslint-disable-next-line max-len 1181cb0ef41Sopenharmony_ci const err = new Error(`Invalid tag name "${name}" of package "${raw}": Tags may not have any characters that encodeURIComponent encodes.`) 1191cb0ef41Sopenharmony_ci err.code = 'EINVALIDTAGNAME' 1201cb0ef41Sopenharmony_ci return err 1211cb0ef41Sopenharmony_ci} 1221cb0ef41Sopenharmony_ci 1231cb0ef41Sopenharmony_cifunction invalidPurlType (type, raw) { 1241cb0ef41Sopenharmony_ci // eslint-disable-next-line max-len 1251cb0ef41Sopenharmony_ci const err = new Error(`Invalid type "${type}" of package "${raw}": Purl can only be generated for "version" types.`) 1261cb0ef41Sopenharmony_ci err.code = 'EINVALIDPURLTYPE' 1271cb0ef41Sopenharmony_ci return err 1281cb0ef41Sopenharmony_ci} 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_cifunction Result (opts) { 1311cb0ef41Sopenharmony_ci this.type = opts.type 1321cb0ef41Sopenharmony_ci this.registry = opts.registry 1331cb0ef41Sopenharmony_ci this.where = opts.where 1341cb0ef41Sopenharmony_ci if (opts.raw == null) { 1351cb0ef41Sopenharmony_ci this.raw = opts.name ? opts.name + '@' + opts.rawSpec : opts.rawSpec 1361cb0ef41Sopenharmony_ci } else { 1371cb0ef41Sopenharmony_ci this.raw = opts.raw 1381cb0ef41Sopenharmony_ci } 1391cb0ef41Sopenharmony_ci 1401cb0ef41Sopenharmony_ci this.name = undefined 1411cb0ef41Sopenharmony_ci this.escapedName = undefined 1421cb0ef41Sopenharmony_ci this.scope = undefined 1431cb0ef41Sopenharmony_ci this.rawSpec = opts.rawSpec || '' 1441cb0ef41Sopenharmony_ci this.saveSpec = opts.saveSpec 1451cb0ef41Sopenharmony_ci this.fetchSpec = opts.fetchSpec 1461cb0ef41Sopenharmony_ci if (opts.name) { 1471cb0ef41Sopenharmony_ci this.setName(opts.name) 1481cb0ef41Sopenharmony_ci } 1491cb0ef41Sopenharmony_ci this.gitRange = opts.gitRange 1501cb0ef41Sopenharmony_ci this.gitCommittish = opts.gitCommittish 1511cb0ef41Sopenharmony_ci this.gitSubdir = opts.gitSubdir 1521cb0ef41Sopenharmony_ci this.hosted = opts.hosted 1531cb0ef41Sopenharmony_ci} 1541cb0ef41Sopenharmony_ci 1551cb0ef41Sopenharmony_ciResult.prototype.setName = function (name) { 1561cb0ef41Sopenharmony_ci const valid = validatePackageName(name) 1571cb0ef41Sopenharmony_ci if (!valid.validForOldPackages) { 1581cb0ef41Sopenharmony_ci throw invalidPackageName(name, valid, this.raw) 1591cb0ef41Sopenharmony_ci } 1601cb0ef41Sopenharmony_ci 1611cb0ef41Sopenharmony_ci this.name = name 1621cb0ef41Sopenharmony_ci this.scope = name[0] === '@' ? name.slice(0, name.indexOf('/')) : undefined 1631cb0ef41Sopenharmony_ci // scoped packages in couch must have slash url-encoded, e.g. @foo%2Fbar 1641cb0ef41Sopenharmony_ci this.escapedName = name.replace('/', '%2f') 1651cb0ef41Sopenharmony_ci return this 1661cb0ef41Sopenharmony_ci} 1671cb0ef41Sopenharmony_ci 1681cb0ef41Sopenharmony_ciResult.prototype.toString = function () { 1691cb0ef41Sopenharmony_ci const full = [] 1701cb0ef41Sopenharmony_ci if (this.name != null && this.name !== '') { 1711cb0ef41Sopenharmony_ci full.push(this.name) 1721cb0ef41Sopenharmony_ci } 1731cb0ef41Sopenharmony_ci const spec = this.saveSpec || this.fetchSpec || this.rawSpec 1741cb0ef41Sopenharmony_ci if (spec != null && spec !== '') { 1751cb0ef41Sopenharmony_ci full.push(spec) 1761cb0ef41Sopenharmony_ci } 1771cb0ef41Sopenharmony_ci return full.length ? full.join('@') : this.raw 1781cb0ef41Sopenharmony_ci} 1791cb0ef41Sopenharmony_ci 1801cb0ef41Sopenharmony_ciResult.prototype.toJSON = function () { 1811cb0ef41Sopenharmony_ci const result = Object.assign({}, this) 1821cb0ef41Sopenharmony_ci delete result.hosted 1831cb0ef41Sopenharmony_ci return result 1841cb0ef41Sopenharmony_ci} 1851cb0ef41Sopenharmony_ci 1861cb0ef41Sopenharmony_ci// sets res.gitCommittish, res.gitRange, and res.gitSubdir 1871cb0ef41Sopenharmony_cifunction setGitAttrs (res, committish) { 1881cb0ef41Sopenharmony_ci if (!committish) { 1891cb0ef41Sopenharmony_ci res.gitCommittish = null 1901cb0ef41Sopenharmony_ci return 1911cb0ef41Sopenharmony_ci } 1921cb0ef41Sopenharmony_ci 1931cb0ef41Sopenharmony_ci // for each :: separated item: 1941cb0ef41Sopenharmony_ci for (const part of committish.split('::')) { 1951cb0ef41Sopenharmony_ci // if the item has no : the n it is a commit-ish 1961cb0ef41Sopenharmony_ci if (!part.includes(':')) { 1971cb0ef41Sopenharmony_ci if (res.gitRange) { 1981cb0ef41Sopenharmony_ci throw new Error('cannot override existing semver range with a committish') 1991cb0ef41Sopenharmony_ci } 2001cb0ef41Sopenharmony_ci if (res.gitCommittish) { 2011cb0ef41Sopenharmony_ci throw new Error('cannot override existing committish with a second committish') 2021cb0ef41Sopenharmony_ci } 2031cb0ef41Sopenharmony_ci res.gitCommittish = part 2041cb0ef41Sopenharmony_ci continue 2051cb0ef41Sopenharmony_ci } 2061cb0ef41Sopenharmony_ci // split on name:value 2071cb0ef41Sopenharmony_ci const [name, value] = part.split(':') 2081cb0ef41Sopenharmony_ci // if name is semver do semver lookup of ref or tag 2091cb0ef41Sopenharmony_ci if (name === 'semver') { 2101cb0ef41Sopenharmony_ci if (res.gitCommittish) { 2111cb0ef41Sopenharmony_ci throw new Error('cannot override existing committish with a semver range') 2121cb0ef41Sopenharmony_ci } 2131cb0ef41Sopenharmony_ci if (res.gitRange) { 2141cb0ef41Sopenharmony_ci throw new Error('cannot override existing semver range with a second semver range') 2151cb0ef41Sopenharmony_ci } 2161cb0ef41Sopenharmony_ci res.gitRange = decodeURIComponent(value) 2171cb0ef41Sopenharmony_ci continue 2181cb0ef41Sopenharmony_ci } 2191cb0ef41Sopenharmony_ci if (name === 'path') { 2201cb0ef41Sopenharmony_ci if (res.gitSubdir) { 2211cb0ef41Sopenharmony_ci throw new Error('cannot override existing path with a second path') 2221cb0ef41Sopenharmony_ci } 2231cb0ef41Sopenharmony_ci res.gitSubdir = `/${value}` 2241cb0ef41Sopenharmony_ci continue 2251cb0ef41Sopenharmony_ci } 2261cb0ef41Sopenharmony_ci log.warn('npm-package-arg', `ignoring unknown key "${name}"`) 2271cb0ef41Sopenharmony_ci } 2281cb0ef41Sopenharmony_ci} 2291cb0ef41Sopenharmony_ci 2301cb0ef41Sopenharmony_cifunction fromFile (res, where) { 2311cb0ef41Sopenharmony_ci if (!where) { 2321cb0ef41Sopenharmony_ci where = process.cwd() 2331cb0ef41Sopenharmony_ci } 2341cb0ef41Sopenharmony_ci res.type = isFilename.test(res.rawSpec) ? 'file' : 'directory' 2351cb0ef41Sopenharmony_ci res.where = where 2361cb0ef41Sopenharmony_ci 2371cb0ef41Sopenharmony_ci // always put the '/' on where when resolving urls, or else 2381cb0ef41Sopenharmony_ci // file:foo from /path/to/bar goes to /path/to/foo, when we want 2391cb0ef41Sopenharmony_ci // it to be /path/to/bar/foo 2401cb0ef41Sopenharmony_ci 2411cb0ef41Sopenharmony_ci let specUrl 2421cb0ef41Sopenharmony_ci let resolvedUrl 2431cb0ef41Sopenharmony_ci const prefix = (!/^file:/.test(res.rawSpec) ? 'file:' : '') 2441cb0ef41Sopenharmony_ci const rawWithPrefix = prefix + res.rawSpec 2451cb0ef41Sopenharmony_ci let rawNoPrefix = rawWithPrefix.replace(/^file:/, '') 2461cb0ef41Sopenharmony_ci try { 2471cb0ef41Sopenharmony_ci resolvedUrl = new URL(rawWithPrefix, `file://${path.resolve(where)}/`) 2481cb0ef41Sopenharmony_ci specUrl = new URL(rawWithPrefix) 2491cb0ef41Sopenharmony_ci } catch (originalError) { 2501cb0ef41Sopenharmony_ci const er = new Error('Invalid file: URL, must comply with RFC 8089') 2511cb0ef41Sopenharmony_ci throw Object.assign(er, { 2521cb0ef41Sopenharmony_ci raw: res.rawSpec, 2531cb0ef41Sopenharmony_ci spec: res, 2541cb0ef41Sopenharmony_ci where, 2551cb0ef41Sopenharmony_ci originalError, 2561cb0ef41Sopenharmony_ci }) 2571cb0ef41Sopenharmony_ci } 2581cb0ef41Sopenharmony_ci 2591cb0ef41Sopenharmony_ci // XXX backwards compatibility lack of compliance with RFC 8089 2601cb0ef41Sopenharmony_ci if (resolvedUrl.host && resolvedUrl.host !== 'localhost') { 2611cb0ef41Sopenharmony_ci const rawSpec = res.rawSpec.replace(/^file:\/\//, 'file:///') 2621cb0ef41Sopenharmony_ci resolvedUrl = new URL(rawSpec, `file://${path.resolve(where)}/`) 2631cb0ef41Sopenharmony_ci specUrl = new URL(rawSpec) 2641cb0ef41Sopenharmony_ci rawNoPrefix = rawSpec.replace(/^file:/, '') 2651cb0ef41Sopenharmony_ci } 2661cb0ef41Sopenharmony_ci // turn file:/../foo into file:../foo 2671cb0ef41Sopenharmony_ci // for 1, 2 or 3 leading slashes since we attempted 2681cb0ef41Sopenharmony_ci // in the previous step to make it a file protocol url with a leading slash 2691cb0ef41Sopenharmony_ci if (/^\/{1,3}\.\.?(\/|$)/.test(rawNoPrefix)) { 2701cb0ef41Sopenharmony_ci const rawSpec = res.rawSpec.replace(/^file:\/{1,3}/, 'file:') 2711cb0ef41Sopenharmony_ci resolvedUrl = new URL(rawSpec, `file://${path.resolve(where)}/`) 2721cb0ef41Sopenharmony_ci specUrl = new URL(rawSpec) 2731cb0ef41Sopenharmony_ci rawNoPrefix = rawSpec.replace(/^file:/, '') 2741cb0ef41Sopenharmony_ci } 2751cb0ef41Sopenharmony_ci // XXX end RFC 8089 violation backwards compatibility section 2761cb0ef41Sopenharmony_ci 2771cb0ef41Sopenharmony_ci // turn /C:/blah into just C:/blah on windows 2781cb0ef41Sopenharmony_ci let specPath = decodeURIComponent(specUrl.pathname) 2791cb0ef41Sopenharmony_ci let resolvedPath = decodeURIComponent(resolvedUrl.pathname) 2801cb0ef41Sopenharmony_ci if (isWindows) { 2811cb0ef41Sopenharmony_ci specPath = specPath.replace(/^\/+([a-z]:\/)/i, '$1') 2821cb0ef41Sopenharmony_ci resolvedPath = resolvedPath.replace(/^\/+([a-z]:\/)/i, '$1') 2831cb0ef41Sopenharmony_ci } 2841cb0ef41Sopenharmony_ci 2851cb0ef41Sopenharmony_ci // replace ~ with homedir, but keep the ~ in the saveSpec 2861cb0ef41Sopenharmony_ci // otherwise, make it relative to where param 2871cb0ef41Sopenharmony_ci if (/^\/~(\/|$)/.test(specPath)) { 2881cb0ef41Sopenharmony_ci res.saveSpec = `file:${specPath.substr(1)}` 2891cb0ef41Sopenharmony_ci resolvedPath = path.resolve(homedir(), specPath.substr(3)) 2901cb0ef41Sopenharmony_ci } else if (!path.isAbsolute(rawNoPrefix)) { 2911cb0ef41Sopenharmony_ci res.saveSpec = `file:${path.relative(where, resolvedPath)}` 2921cb0ef41Sopenharmony_ci } else { 2931cb0ef41Sopenharmony_ci res.saveSpec = `file:${path.resolve(resolvedPath)}` 2941cb0ef41Sopenharmony_ci } 2951cb0ef41Sopenharmony_ci 2961cb0ef41Sopenharmony_ci res.fetchSpec = path.resolve(where, resolvedPath) 2971cb0ef41Sopenharmony_ci return res 2981cb0ef41Sopenharmony_ci} 2991cb0ef41Sopenharmony_ci 3001cb0ef41Sopenharmony_cifunction fromHostedGit (res, hosted) { 3011cb0ef41Sopenharmony_ci res.type = 'git' 3021cb0ef41Sopenharmony_ci res.hosted = hosted 3031cb0ef41Sopenharmony_ci res.saveSpec = hosted.toString({ noGitPlus: false, noCommittish: false }) 3041cb0ef41Sopenharmony_ci res.fetchSpec = hosted.getDefaultRepresentation() === 'shortcut' ? null : hosted.toString() 3051cb0ef41Sopenharmony_ci setGitAttrs(res, hosted.committish) 3061cb0ef41Sopenharmony_ci return res 3071cb0ef41Sopenharmony_ci} 3081cb0ef41Sopenharmony_ci 3091cb0ef41Sopenharmony_cifunction unsupportedURLType (protocol, spec) { 3101cb0ef41Sopenharmony_ci const err = new Error(`Unsupported URL Type "${protocol}": ${spec}`) 3111cb0ef41Sopenharmony_ci err.code = 'EUNSUPPORTEDPROTOCOL' 3121cb0ef41Sopenharmony_ci return err 3131cb0ef41Sopenharmony_ci} 3141cb0ef41Sopenharmony_ci 3151cb0ef41Sopenharmony_cifunction fromURL (res) { 3161cb0ef41Sopenharmony_ci let rawSpec = res.rawSpec 3171cb0ef41Sopenharmony_ci res.saveSpec = rawSpec 3181cb0ef41Sopenharmony_ci if (rawSpec.startsWith('git+ssh:')) { 3191cb0ef41Sopenharmony_ci // git ssh specifiers are overloaded to also use scp-style git 3201cb0ef41Sopenharmony_ci // specifiers, so we have to parse those out and treat them special. 3211cb0ef41Sopenharmony_ci // They are NOT true URIs, so we can't hand them to URL. 3221cb0ef41Sopenharmony_ci 3231cb0ef41Sopenharmony_ci // This regex looks for things that look like: 3241cb0ef41Sopenharmony_ci // git+ssh://git@my.custom.git.com:username/project.git#deadbeef 3251cb0ef41Sopenharmony_ci // ...and various combinations. The username in the beginning is *required*. 3261cb0ef41Sopenharmony_ci const matched = rawSpec.match(/^git\+ssh:\/\/([^:#]+:[^#]+(?:\.git)?)(?:#(.*))?$/i) 3271cb0ef41Sopenharmony_ci if (matched && !matched[1].match(/:[0-9]+\/?.*$/i)) { 3281cb0ef41Sopenharmony_ci res.type = 'git' 3291cb0ef41Sopenharmony_ci setGitAttrs(res, matched[2]) 3301cb0ef41Sopenharmony_ci res.fetchSpec = matched[1] 3311cb0ef41Sopenharmony_ci return res 3321cb0ef41Sopenharmony_ci } 3331cb0ef41Sopenharmony_ci } else if (rawSpec.startsWith('git+file://')) { 3341cb0ef41Sopenharmony_ci // URL can't handle windows paths 3351cb0ef41Sopenharmony_ci rawSpec = rawSpec.replace(/\\/g, '/') 3361cb0ef41Sopenharmony_ci } 3371cb0ef41Sopenharmony_ci const parsedUrl = new URL(rawSpec) 3381cb0ef41Sopenharmony_ci // check the protocol, and then see if it's git or not 3391cb0ef41Sopenharmony_ci switch (parsedUrl.protocol) { 3401cb0ef41Sopenharmony_ci case 'git:': 3411cb0ef41Sopenharmony_ci case 'git+http:': 3421cb0ef41Sopenharmony_ci case 'git+https:': 3431cb0ef41Sopenharmony_ci case 'git+rsync:': 3441cb0ef41Sopenharmony_ci case 'git+ftp:': 3451cb0ef41Sopenharmony_ci case 'git+file:': 3461cb0ef41Sopenharmony_ci case 'git+ssh:': 3471cb0ef41Sopenharmony_ci res.type = 'git' 3481cb0ef41Sopenharmony_ci setGitAttrs(res, parsedUrl.hash.slice(1)) 3491cb0ef41Sopenharmony_ci if (parsedUrl.protocol === 'git+file:' && /^git\+file:\/\/[a-z]:/i.test(rawSpec)) { 3501cb0ef41Sopenharmony_ci // URL can't handle drive letters on windows file paths, the host can't contain a : 3511cb0ef41Sopenharmony_ci res.fetchSpec = `git+file://${parsedUrl.host.toLowerCase()}:${parsedUrl.pathname}` 3521cb0ef41Sopenharmony_ci } else { 3531cb0ef41Sopenharmony_ci parsedUrl.hash = '' 3541cb0ef41Sopenharmony_ci res.fetchSpec = parsedUrl.toString() 3551cb0ef41Sopenharmony_ci } 3561cb0ef41Sopenharmony_ci if (res.fetchSpec.startsWith('git+')) { 3571cb0ef41Sopenharmony_ci res.fetchSpec = res.fetchSpec.slice(4) 3581cb0ef41Sopenharmony_ci } 3591cb0ef41Sopenharmony_ci break 3601cb0ef41Sopenharmony_ci case 'http:': 3611cb0ef41Sopenharmony_ci case 'https:': 3621cb0ef41Sopenharmony_ci res.type = 'remote' 3631cb0ef41Sopenharmony_ci res.fetchSpec = res.saveSpec 3641cb0ef41Sopenharmony_ci break 3651cb0ef41Sopenharmony_ci 3661cb0ef41Sopenharmony_ci default: 3671cb0ef41Sopenharmony_ci throw unsupportedURLType(parsedUrl.protocol, rawSpec) 3681cb0ef41Sopenharmony_ci } 3691cb0ef41Sopenharmony_ci 3701cb0ef41Sopenharmony_ci return res 3711cb0ef41Sopenharmony_ci} 3721cb0ef41Sopenharmony_ci 3731cb0ef41Sopenharmony_cifunction fromAlias (res, where) { 3741cb0ef41Sopenharmony_ci const subSpec = npa(res.rawSpec.substr(4), where) 3751cb0ef41Sopenharmony_ci if (subSpec.type === 'alias') { 3761cb0ef41Sopenharmony_ci throw new Error('nested aliases not supported') 3771cb0ef41Sopenharmony_ci } 3781cb0ef41Sopenharmony_ci 3791cb0ef41Sopenharmony_ci if (!subSpec.registry) { 3801cb0ef41Sopenharmony_ci throw new Error('aliases only work for registry deps') 3811cb0ef41Sopenharmony_ci } 3821cb0ef41Sopenharmony_ci 3831cb0ef41Sopenharmony_ci res.subSpec = subSpec 3841cb0ef41Sopenharmony_ci res.registry = true 3851cb0ef41Sopenharmony_ci res.type = 'alias' 3861cb0ef41Sopenharmony_ci res.saveSpec = null 3871cb0ef41Sopenharmony_ci res.fetchSpec = null 3881cb0ef41Sopenharmony_ci return res 3891cb0ef41Sopenharmony_ci} 3901cb0ef41Sopenharmony_ci 3911cb0ef41Sopenharmony_cifunction fromRegistry (res) { 3921cb0ef41Sopenharmony_ci res.registry = true 3931cb0ef41Sopenharmony_ci const spec = res.rawSpec.trim() 3941cb0ef41Sopenharmony_ci // no save spec for registry components as we save based on the fetched 3951cb0ef41Sopenharmony_ci // version, not on the argument so this can't compute that. 3961cb0ef41Sopenharmony_ci res.saveSpec = null 3971cb0ef41Sopenharmony_ci res.fetchSpec = spec 3981cb0ef41Sopenharmony_ci const version = semver.valid(spec, true) 3991cb0ef41Sopenharmony_ci const range = semver.validRange(spec, true) 4001cb0ef41Sopenharmony_ci if (version) { 4011cb0ef41Sopenharmony_ci res.type = 'version' 4021cb0ef41Sopenharmony_ci } else if (range) { 4031cb0ef41Sopenharmony_ci res.type = 'range' 4041cb0ef41Sopenharmony_ci } else { 4051cb0ef41Sopenharmony_ci if (encodeURIComponent(spec) !== spec) { 4061cb0ef41Sopenharmony_ci throw invalidTagName(spec, res.raw) 4071cb0ef41Sopenharmony_ci } 4081cb0ef41Sopenharmony_ci res.type = 'tag' 4091cb0ef41Sopenharmony_ci } 4101cb0ef41Sopenharmony_ci return res 4111cb0ef41Sopenharmony_ci} 412