This commit is contained in:
2025-08-18 23:06:34 +08:00
parent 0bc04fb659
commit ed18af0cad
1926 changed files with 275098 additions and 0 deletions

9
package/node_modules/bin-links/lib/bin-target.js generated vendored Normal file
View File

@@ -0,0 +1,9 @@
const isWindows = require('./is-windows.js')
const getPrefix = require('./get-prefix.js')
const getNodeModules = require('./get-node-modules.js')
const { dirname } = require('path')
module.exports = ({ top, path }) =>
!top ? getNodeModules(path) + '/.bin'
: isWindows ? getPrefix(path)
: dirname(getPrefix(path)) + '/bin'

74
package/node_modules/bin-links/lib/check-bin.js generated vendored Normal file
View File

@@ -0,0 +1,74 @@
// check to see if a bin is allowed to be overwritten
// either rejects or resolves to nothing. return value not relevant.
const isWindows = require('./is-windows.js')
const binTarget = require('./bin-target.js')
const { resolve, dirname } = require('path')
const readCmdShim = require('read-cmd-shim')
const { readlink } = require('fs/promises')
const checkBin = async ({ bin, path, top, global, force }) => {
// always ok to clobber when forced
// always ok to clobber local bins, or when forced
if (force || !global || !top) {
return
}
// ok, need to make sure, then
const target = resolve(binTarget({ path, top }), bin)
path = resolve(path)
return isWindows ? checkShim({ target, path }) : checkLink({ target, path })
}
// only enoent is allowed. anything else is a problem.
const handleReadLinkError = async ({ er, target }) =>
er.code === 'ENOENT' ? null
: failEEXIST({ target })
const checkLink = async ({ target, path }) => {
const current = await readlink(target)
.catch(er => handleReadLinkError({ er, target }))
if (!current) {
return
}
const resolved = resolve(dirname(target), current)
if (resolved.toLowerCase().indexOf(path.toLowerCase()) !== 0) {
return failEEXIST({ target })
}
}
const handleReadCmdShimError = ({ er, target }) =>
er.code === 'ENOENT' ? null
: failEEXIST({ target })
const failEEXIST = ({ target }) =>
Promise.reject(Object.assign(new Error('EEXIST: file already exists'), {
path: target,
code: 'EEXIST',
}))
const checkShim = async ({ target, path }) => {
const shims = [
target,
target + '.cmd',
target + '.ps1',
]
await Promise.all(shims.map(async shim => {
const current = await readCmdShim(shim)
.catch(er => handleReadCmdShimError({ er, target: shim }))
if (!current) {
return
}
const resolved = resolve(dirname(shim), current.replace(/\\/g, '/'))
if (resolved.toLowerCase().indexOf(path.toLowerCase()) !== 0) {
return failEEXIST({ target: shim })
}
}))
}
module.exports = checkBin

18
package/node_modules/bin-links/lib/check-bins.js generated vendored Normal file
View File

@@ -0,0 +1,18 @@
const checkBin = require('./check-bin.js')
const normalize = require('npm-normalize-package-bin')
const checkBins = async ({ pkg, path, top, global, force }) => {
// always ok to clobber when forced
// always ok to clobber local bins, or when forced
if (force || !global || !top) {
return
}
pkg = normalize(pkg)
if (!pkg.bin) {
return
}
await Promise.all(Object.keys(pkg.bin)
.map(bin => checkBin({ bin, path, top, global, force })))
}
module.exports = checkBins

42
package/node_modules/bin-links/lib/fix-bin.js generated vendored Normal file
View File

@@ -0,0 +1,42 @@
// make sure that bins are executable, and that they don't have
// windows line-endings on the hashbang line.
const {
chmod,
open,
readFile,
} = require('fs/promises')
const execMode = 0o777 & (~process.umask())
const writeFileAtomic = require('write-file-atomic')
const isWindowsHashBang = buf =>
buf[0] === '#'.charCodeAt(0) &&
buf[1] === '!'.charCodeAt(0) &&
/^#![^\n]+\r\n/.test(buf.toString())
const isWindowsHashbangFile = file => {
const FALSE = () => false
return open(file, 'r').then(fh => {
const buf = Buffer.alloc(2048)
return fh.read(buf, 0, 2048, 0)
.then(
() => {
const isWHB = isWindowsHashBang(buf)
return fh.close().then(() => isWHB, () => isWHB)
},
// don't leak FD if read() fails
() => fh.close().then(FALSE, FALSE)
)
}, FALSE)
}
const dos2Unix = file =>
readFile(file, 'utf8').then(content =>
writeFileAtomic(file, content.replace(/^(#![^\n]+)\r\n/, '$1\n')))
const fixBin = (file, mode = execMode) => chmod(file, mode)
.then(() => isWindowsHashbangFile(file))
.then(isWHB => isWHB ? dos2Unix(file) : null)
module.exports = fixBin

19
package/node_modules/bin-links/lib/get-node-modules.js generated vendored Normal file
View File

@@ -0,0 +1,19 @@
// we know it's global and/or not top, so the path has to be
// {prefix}/node_modules/{name}. Can't rely on pkg.name, because
// it might be installed as an alias.
const { dirname, basename } = require('path')
// this gets called a lot and can't change, so memoize it
const memo = new Map()
module.exports = path => {
if (memo.has(path)) {
return memo.get(path)
}
const scopeOrNm = dirname(path)
const nm = basename(scopeOrNm) === 'node_modules' ? scopeOrNm
: dirname(scopeOrNm)
memo.set(path, nm)
return nm
}

42
package/node_modules/bin-links/lib/get-paths.js generated vendored Normal file
View File

@@ -0,0 +1,42 @@
// get all the paths that are (or might be) installed for a given pkg
// There's no guarantee that all of these will be installed, but if they
// are present, then we can assume that they're associated.
const binTarget = require('./bin-target.js')
const manTarget = require('./man-target.js')
const { resolve, basename, extname } = require('path')
const isWindows = require('./is-windows.js')
module.exports = ({ path, pkg, global, top }) => {
if (top && !global) {
return []
}
const binSet = []
const binTarg = binTarget({ path, top })
if (pkg.bin) {
for (const bin of Object.keys(pkg.bin)) {
const b = resolve(binTarg, bin)
binSet.push(b)
if (isWindows) {
binSet.push(b + '.cmd')
binSet.push(b + '.ps1')
}
}
}
const manTarg = manTarget({ path, top })
const manSet = []
if (manTarg && pkg.man && Array.isArray(pkg.man) && pkg.man.length) {
for (const man of pkg.man) {
if (!/.\.[0-9]+(\.gz)?$/.test(man)) {
return binSet
}
const section = extname(basename(man, '.gz')).slice(1)
const base = basename(man)
manSet.push(resolve(manTarg, 'man' + section, base))
}
}
return manSet.length ? [...binSet, ...manSet] : binSet
}

3
package/node_modules/bin-links/lib/get-prefix.js generated vendored Normal file
View File

@@ -0,0 +1,3 @@
const { dirname } = require('path')
const getNodeModules = require('./get-node-modules.js')
module.exports = path => dirname(getNodeModules(path))

44
package/node_modules/bin-links/lib/index.js generated vendored Normal file
View File

@@ -0,0 +1,44 @@
const linkBins = require('./link-bins.js')
const linkMans = require('./link-mans.js')
const binLinks = opts => {
const { path, pkg, force, global, top } = opts
// global top pkgs on windows get bins installed in {prefix}, and no mans
//
// unix global top pkgs get their bins installed in {prefix}/bin,
// and mans in {prefix}/share/man
//
// non-top pkgs get their bins installed in {prefix}/node_modules/.bin,
// and do not install mans
//
// non-global top pkgs don't have any bins or mans linked. From here on
// out, if it's top, we know that it's global, so no need to pass that
// option further down the stack.
if (top && !global) {
return Promise.resolve()
}
return Promise.all([
// allow clobbering within the local node_modules/.bin folder.
// only global bins are protected in this way, or else it is
// yet another vector for excessive dependency conflicts.
linkBins({ path, pkg, top, force: force || !top }),
linkMans({ path, pkg, top, force }),
])
}
const shimBin = require('./shim-bin.js')
const linkGently = require('./link-gently.js')
const resetSeen = () => {
shimBin.resetSeen()
linkGently.resetSeen()
}
const checkBins = require('./check-bins.js')
const getPaths = require('./get-paths.js')
module.exports = Object.assign(binLinks, {
checkBins,
resetSeen,
getPaths,
})

2
package/node_modules/bin-links/lib/is-windows.js generated vendored Normal file
View File

@@ -0,0 +1,2 @@
const platform = process.env.__TESTING_BIN_LINKS_PLATFORM__ || process.platform
module.exports = platform === 'win32'

9
package/node_modules/bin-links/lib/link-bin.js generated vendored Normal file
View File

@@ -0,0 +1,9 @@
const linkGently = require('./link-gently.js')
const fixBin = require('./fix-bin.js')
// linking bins is simple. just symlink, and if we linked it, fix the bin up
const linkBin = ({ path, to, from, absFrom, force }) =>
linkGently({ path, to, from, absFrom, force })
.then(linked => linked && fixBin(absFrom))
module.exports = linkBin

23
package/node_modules/bin-links/lib/link-bins.js generated vendored Normal file
View File

@@ -0,0 +1,23 @@
const isWindows = require('./is-windows.js')
const binTarget = require('./bin-target.js')
const { dirname, resolve, relative } = require('path')
const linkBin = isWindows ? require('./shim-bin.js') : require('./link-bin.js')
const normalize = require('npm-normalize-package-bin')
const linkBins = ({ path, pkg, top, force }) => {
pkg = normalize(pkg)
if (!pkg.bin) {
return Promise.resolve([])
}
const promises = []
const target = binTarget({ path, top })
for (const [key, val] of Object.entries(pkg.bin)) {
const to = resolve(target, key)
const absFrom = resolve(path, val)
const from = relative(dirname(to), absFrom)
promises.push(linkBin({ path, from, to, absFrom, force }))
}
return Promise.all(promises)
}
module.exports = linkBins

90
package/node_modules/bin-links/lib/link-gently.js generated vendored Normal file
View File

@@ -0,0 +1,90 @@
// if the thing isn't there, skip it
// if there's a non-symlink there already, eexist
// if there's a symlink already, pointing somewhere else, eexist
// if there's a symlink already, pointing into our pkg, remove it first
// then create the symlink
const { resolve, dirname } = require('path')
const { lstat, mkdir, readlink, rm, symlink } = require('fs/promises')
const throwNonEnoent = er => {
if (er.code !== 'ENOENT') {
throw er
}
}
const rmOpts = {
recursive: true,
force: true,
}
// even in --force mode, we never create a link over a link we've
// already created. you can have multiple packages in a tree trying
// to contend for the same bin, or the same manpage listed multiple times,
// which creates a race condition and nondeterminism.
const seen = new Set()
const SKIP = Symbol('skip - missing or already installed')
const CLOBBER = Symbol('clobber - ours or in forceful mode')
const linkGently = async ({ path, to, from, absFrom, force }) => {
if (seen.has(to)) {
return false
}
seen.add(to)
// if the script or manpage isn't there, just ignore it.
// this arguably *should* be an install error of some sort,
// or at least a warning, but npm has always behaved this
// way in the past, so it'd be a breaking change
return Promise.all([
lstat(absFrom).catch(throwNonEnoent),
lstat(to).catch(throwNonEnoent),
]).then(([stFrom, stTo]) => {
// not present in package, skip it
if (!stFrom) {
return SKIP
}
// exists! maybe clobber if we can
if (stTo) {
if (!stTo.isSymbolicLink()) {
return force && rm(to, rmOpts).then(() => CLOBBER)
}
return readlink(to).then(target => {
if (target === from) {
return SKIP
} // skip it, already set up like we want it.
target = resolve(dirname(to), target)
if (target.indexOf(path) === 0 || force) {
return rm(to, rmOpts).then(() => CLOBBER)
}
// neither skip nor clobber
return false
})
} else {
// doesn't exist, dir might not either
return mkdir(dirname(to), { recursive: true })
}
})
.then(skipOrClobber => {
if (skipOrClobber === SKIP) {
return false
}
return symlink(from, to, 'file').catch(er => {
if (skipOrClobber === CLOBBER || force) {
return rm(to, rmOpts).then(() => symlink(from, to, 'file'))
}
throw er
}).then(() => true)
})
}
const resetSeen = () => {
for (const p of seen) {
seen.delete(p)
}
}
module.exports = Object.assign(linkGently, { resetSeen })

53
package/node_modules/bin-links/lib/link-mans.js generated vendored Normal file
View File

@@ -0,0 +1,53 @@
const { dirname, relative, join, resolve, basename } = require('path')
const linkGently = require('./link-gently.js')
const manTarget = require('./man-target.js')
const linkMans = async ({ path, pkg, top, force }) => {
const target = manTarget({ path, top })
if (!target || !Array.isArray(pkg?.man) || !pkg.man.length) {
return []
}
const links = []
// `new Set` to filter out duplicates
for (let man of new Set(pkg.man)) {
if (!man || typeof man !== 'string') {
continue
}
// break any links to c:\\blah or /foo/blah or ../blah
man = join('/', man).replace(/\\|:/g, '/').slice(1)
const parseMan = man.match(/\.([0-9]+)(\.gz)?$/)
if (!parseMan) {
throw Object.assign(new Error('invalid man entry name\n' +
'Man files must end with a number, ' +
'and optionally a .gz suffix if they are compressed.'
), {
code: 'EBADMAN',
path,
pkgid: pkg._id,
man,
})
}
const section = parseMan[1]
const base = basename(man)
const absFrom = resolve(path, man)
/* istanbul ignore if - that unpossible */
if (absFrom.indexOf(path) !== 0) {
throw Object.assign(new Error('invalid man entry'), {
code: 'EBADMAN',
path,
pkgid: pkg._id,
man,
})
}
const to = resolve(target, 'man' + section, base)
const from = relative(dirname(to), absFrom)
links.push(linkGently({ from, to, path, absFrom, force }))
}
return Promise.all(links)
}
module.exports = linkMans

6
package/node_modules/bin-links/lib/man-target.js generated vendored Normal file
View File

@@ -0,0 +1,6 @@
const isWindows = require('./is-windows.js')
const getPrefix = require('./get-prefix.js')
const { dirname } = require('path')
module.exports = ({ top, path }) => !top || isWindows ? null
: dirname(getPrefix(path)) + '/share/man'

86
package/node_modules/bin-links/lib/shim-bin.js generated vendored Normal file
View File

@@ -0,0 +1,86 @@
const { resolve, dirname } = require('path')
const { lstat } = require('fs/promises')
const throwNonEnoent = er => {
if (er.code !== 'ENOENT') {
throw er
}
}
const cmdShim = require('cmd-shim')
const readCmdShim = require('read-cmd-shim')
const fixBin = require('./fix-bin.js')
// even in --force mode, we never create a shim over a shim we've
// already created. you can have multiple packages in a tree trying
// to contend for the same bin, which creates a race condition and
// nondeterminism.
const seen = new Set()
const failEEXIST = ({ to, from }) =>
Promise.reject(Object.assign(new Error('EEXIST: file already exists'), {
path: to,
dest: from,
code: 'EEXIST',
}))
const handleReadCmdShimError = ({ er, from, to }) =>
er.code === 'ENOENT' ? null
: er.code === 'ENOTASHIM' ? failEEXIST({ from, to })
: Promise.reject(er)
const SKIP = Symbol('skip - missing or already installed')
const shimBin = ({ path, to, from, absFrom, force }) => {
const shims = [
to,
to + '.cmd',
to + '.ps1',
]
for (const shim of shims) {
if (seen.has(shim)) {
return true
}
seen.add(shim)
}
return Promise.all([
...shims,
absFrom,
].map(f => lstat(f).catch(throwNonEnoent))).then((stats) => {
const [, , , stFrom] = stats
if (!stFrom) {
return SKIP
}
if (force) {
return false
}
return Promise.all(shims.map((s, i) => [s, stats[i]]).map(([s, st]) => {
if (!st) {
return false
}
return readCmdShim(s)
.then(target => {
target = resolve(dirname(to), target)
if (target.indexOf(resolve(path)) !== 0) {
return failEEXIST({ from, to, path })
}
return false
}, er => handleReadCmdShimError({ er, from, to }))
}))
})
.then(skip => skip !== SKIP && doShim(absFrom, to))
}
const doShim = (absFrom, to) =>
cmdShim(absFrom, to).then(() => fixBin(absFrom))
const resetSeen = () => {
for (const p of seen) {
seen.delete(p)
}
}
module.exports = Object.assign(shimBin, { resetSeen })