1const semver = require('semver') 2const { basename } = require('path') 3const { URL } = require('url') 4module.exports = (name, tgz) => { 5 const base = basename(tgz) 6 if (!base.endsWith('.tgz')) { 7 return null 8 } 9 10 if (tgz.startsWith('http:/') || tgz.startsWith('https:/')) { 11 const u = new URL(tgz) 12 // registry url? check for most likely pattern. 13 // either /@foo/bar/-/bar-1.2.3.tgz or 14 // /foo/-/foo-1.2.3.tgz, and fall through to 15 // basename checking. Note that registries can 16 // be mounted below the root url, so /a/b/-/x/y/foo/-/foo-1.2.3.tgz 17 // is a potential option. 18 const tfsplit = u.pathname.slice(1).split('/-/') 19 if (tfsplit.length > 1) { 20 const afterTF = tfsplit.pop() 21 if (afterTF === base) { 22 const pre = tfsplit.pop() 23 const preSplit = pre.split(/\/|%2f/i) 24 const project = preSplit.pop() 25 const scope = preSplit.pop() 26 return versionFromBaseScopeName(base, scope, project) 27 } 28 } 29 } 30 31 const split = name.split(/\/|%2f/i) 32 const project = split.pop() 33 const scope = split.pop() 34 return versionFromBaseScopeName(base, scope, project) 35} 36 37const versionFromBaseScopeName = (base, scope, name) => { 38 if (!base.startsWith(name + '-')) { 39 return null 40 } 41 42 const parsed = semver.parse(base.substring(name.length + 1, base.length - 4)) 43 return parsed ? { 44 name: scope && scope.charAt(0) === '@' ? `${scope}/${name}` : name, 45 version: parsed.version, 46 } : null 47} 48