Skip to content

Commit

Permalink
fix: use URL instead of url.parse
Browse files Browse the repository at this point in the history
  • Loading branch information
wraithgar committed Aug 24, 2023
1 parent 19c1bc7 commit 4470605
Showing 1 changed file with 37 additions and 41 deletions.
78 changes: 37 additions & 41 deletions lib/npa.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module.exports.resolve = resolve
module.exports.toPurl = toPurl
module.exports.Result = Result

const url = require('url')
const { URL } = require('url')
const HostedGit = require('hosted-git-info')
const semver = require('semver')
const path = global.FAKE_WINDOWS ? require('path').win32 : require('path')
Expand Down Expand Up @@ -245,8 +245,8 @@ function fromFile (res, where) {
const rawWithPrefix = prefix + res.rawSpec
let rawNoPrefix = rawWithPrefix.replace(/^file:/, '')
try {
resolvedUrl = new url.URL(rawWithPrefix, `file://${path.resolve(where)}/`)
specUrl = new url.URL(rawWithPrefix)
resolvedUrl = new URL(rawWithPrefix, `file://${path.resolve(where)}/`)
specUrl = new URL(rawWithPrefix)
} catch (originalError) {
const er = new Error('Invalid file: URL, must comply with RFC 8909')
throw Object.assign(er, {
Expand All @@ -263,17 +263,17 @@ function fromFile (res, where) {
// Remove when we want a breaking change to come into RFC compliance.
if (resolvedUrl.host && resolvedUrl.host !== 'localhost') {
const rawSpec = res.rawSpec.replace(/^file:\/\//, 'file:///')
resolvedUrl = new url.URL(rawSpec, `file://${path.resolve(where)}/`)
specUrl = new url.URL(rawSpec)
resolvedUrl = new URL(rawSpec, `file://${path.resolve(where)}/`)
specUrl = new URL(rawSpec)
rawNoPrefix = rawSpec.replace(/^file:/, '')
}
// turn file:/../foo into file:../foo
// for 1, 2 or 3 leading slashes since we attempted
// in the previous step to make it a file protocol url with a leading slash
if (/^\/{1,3}\.\.?(\/|$)/.test(rawNoPrefix)) {
const rawSpec = res.rawSpec.replace(/^file:\/{1,3}/, 'file:')
resolvedUrl = new url.URL(rawSpec, `file://${path.resolve(where)}/`)
specUrl = new url.URL(rawSpec)
resolvedUrl = new URL(rawSpec, `file://${path.resolve(where)}/`)
specUrl = new URL(rawSpec)
rawNoPrefix = rawSpec.replace(/^file:/, '')
}
// XXX end 8909 violation backwards compatibility section
Expand Down Expand Up @@ -329,28 +329,29 @@ function unsupportedURLType (protocol, spec) {
return err
}

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],
}
}

function fromURL (res) {
let rawSpec = res.rawSpec
res.saveSpec = rawSpec
if (rawSpec.startsWith('git+ssh:')) {
// 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.
const matched = rawSpec.match(/^git\+ssh:\/\/([^:#]+:[^#]+(?:\.git)?)(?:#(.*))?$/i)
if (matched && !matched[1].match(/:[0-9]+\/?.*$/i)) {
res.type = 'git'
setGitCommittish(res, matched[2])
res.fetchSpec = matched[1]
return res
}
} else if (rawSpec.startsWith('git+file://')) {
// URL can't handle windows paths
const noProtocol = rawSpec.slice(11).replace(/\\/g, '/')
rawSpec = `git+file://${noProtocol}`
}
// eslint-disable-next-line node/no-deprecated-api
const urlparse = url.parse(res.rawSpec)
res.saveSpec = res.rawSpec
const parsedUrl = new URL(rawSpec)
// check the protocol, and then see if it's git or not
switch (urlparse.protocol) {
switch (parsedUrl.protocol) {
case 'git:':
case 'git+http:':
case 'git+https:':
Expand All @@ -359,21 +360,16 @@ function fromURL (res) {
case 'git+file:':
case 'git+ssh:': {
res.type = 'git'
const match = urlparse.protocol === 'git+ssh:' ? matchGitScp(res.rawSpec)
: null
if (match) {
setGitCommittish(res, match.gitCommittish)
res.fetchSpec = match.fetchSpec
setGitCommittish(res, parsedUrl.hash.slice(1))
if (parsedUrl.protocol === 'git+file:' && /^git\+file:\/\/[a-z]:/i.test(rawSpec)) {
// URL can't handle drive letters on windows file paths, the host can't contain a :
res.fetchSpec = `git+file://${parsedUrl.host.toLowerCase()}:${parsedUrl.pathname}`
} else {
setGitCommittish(res, urlparse.hash != null ? urlparse.hash.slice(1) : '')
urlparse.protocol = urlparse.protocol.replace(/^git[+]/, '')
if (urlparse.protocol === 'file:' && /^git\+file:\/\/[a-z]:/i.test(res.rawSpec)) {
// keep the drive letter : on windows file paths
urlparse.host += ':'
urlparse.hostname += ':'
}
delete urlparse.hash
res.fetchSpec = url.format(urlparse)
parsedUrl.hash = ''
res.fetchSpec = parsedUrl.toString()
}
if (res.fetchSpec.startsWith('git+')) {
res.fetchSpec = res.fetchSpec.slice(4)
}
break
}
Expand All @@ -384,7 +380,7 @@ function fromURL (res) {
break

default:
throw unsupportedURLType(urlparse.protocol, res.rawSpec)
throw unsupportedURLType(parsedUrl.protocol, rawSpec)
}

return res
Expand Down

0 comments on commit 4470605

Please sign in to comment.