Your IP : 18.227.46.202
// Do not rely on package._fields, so that we don't throw
// false failures if a tree is generated by other clients.
// Only relies on child.resolved, which MAY come from
// client-specific package.json meta _fields, but most of
// the time will be pulled out of a lockfile
const semver = require('semver')
const npa = require('npm-package-arg')
const { relative } = require('path')
const fromPath = require('./from-path.js')
const depValid = (child, requested, requestor) => {
// NB: we don't do much to verify 'tag' type requests.
// Just verify that we got a remote resolution. Presumably, it
// came from a registry and was tagged at some point.
if (typeof requested === 'string') {
try {
// tarball/dir must have resolved to the same tgz on disk, but for
// file: deps that depend on other files/dirs, we must resolve the
// location based on the *requestor* file/dir, not where it ends up.
// '' is equivalent to '*'
requested = npa.resolve(child.name, requested || '*', fromPath(requestor, requestor.edgesOut.get(child.name)))
} catch (er) {
// Not invalid because the child doesn't match, but because
// the spec itself is not supported. Nothing would match,
// so the edge is definitely not valid and never can be.
er.dependency = child.name
er.requested = requested
requestor.errors.push(er)
return false
}
}
// if the lockfile is super old, or hand-modified,
// then it's possible to hit this state.
if (!requested) {
const er = new Error('Invalid dependency specifier')
er.dependency = child.name
er.requested = requested
requestor.errors.push(er)
return false
}
switch (requested.type) {
case 'range':
if (requested.fetchSpec === '*') {
return true
}
// fallthrough
case 'version':
// if it's a version or a range other than '*', semver it
return semver.satisfies(child.version, requested.fetchSpec, true)
case 'directory':
return linkValid(child, requested, requestor)
case 'file':
return tarballValid(child, requested, requestor)
case 'alias':
// check that the alias target is valid
return depValid(child, requested.subSpec, requestor)
case 'tag':
// if it's a tag, we just verify that it has a tarball resolution
// presumably, it came from the registry and was tagged at some point
return child.resolved && npa(child.resolved).type === 'remote'
case 'remote':
// verify that we got it from the desired location
return child.resolved === requested.fetchSpec
case 'git': {
// if it's a git type, verify that they're the same repo
//
// if it specifies a definite commit, then it must have the
// same commit to be considered the same repo
//
// if it has a #semver:<range> specifier, verify that the
// version in the package is in the semver range
const resRepo = npa(child.resolved || '')
const resHost = resRepo.hosted
const reqHost = requested.hosted
const reqCommit = /^[a-fA-F0-9]{40}$/.test(requested.gitCommittish || '')
const nc = { noCommittish: !reqCommit }
const sameRepo =
resHost ? reqHost && reqHost.ssh(nc) === resHost.ssh(nc)
: resRepo.fetchSpec === requested.fetchSpec
return !sameRepo ? false
: !requested.gitRange ? true
: semver.satisfies(child.package.version, requested.gitRange, {
loose: true,
})
}
default: // unpossible, just being cautious
break
}
const er = new Error('Unsupported dependency type')
er.dependency = child.name
er.requested = requested
requestor.errors.push(er)
return false
}
const linkValid = (child, requested, requestor) => {
const isLink = !!child.isLink
// if we're installing links and the node is a link, then it's invalid because we want
// a real node to be there
if (requestor.installLinks) {
return !isLink
}
// directory must be a link to the specified folder
return isLink && relative(child.realpath, requested.fetchSpec) === ''
}
const tarballValid = (child, requested, requestor) => {
if (child.isLink) {
return false
}
if (child.resolved) {
return child.resolved.replace(/\\/g, '/') === `file:${requested.fetchSpec.replace(/\\/g, '/')}`
}
// if we have a legacy mutated package.json file. we can't be 100%
// sure that it resolved to the same file, but if it was the same
// request, that's a pretty good indicator of sameness.
if (child.package._requested) {
return child.package._requested.saveSpec === requested.saveSpec
}
// ok, we're probably dealing with some legacy cruft here, not much
// we can do at this point unfortunately.
return false
}
module.exports = (child, requested, accept, requestor) =>
depValid(child, requested, requestor) ||
(typeof accept === 'string' ? depValid(child, accept, requestor) : false)