+7
-3
@@ -5,3 +5,3 @@ // check to see if a bin is allowed to be overwritten | ||
| const binTarget = require('./bin-target.js') | ||
| const { resolve, dirname } = require('path') | ||
| const { resolve, dirname, sep } = require('path') | ||
| const readCmdShim = require('read-cmd-shim') | ||
@@ -38,3 +38,5 @@ const { readlink } = require('fs/promises') | ||
| if (resolved.toLowerCase().indexOf(path.toLowerCase()) !== 0) { | ||
| const resolvedLower = resolved.toLowerCase() | ||
| const pathLower = path.toLowerCase() | ||
| if (resolvedLower !== pathLower && !resolvedLower.startsWith(pathLower + sep)) { | ||
| return failEEXIST({ target }) | ||
@@ -70,3 +72,5 @@ } | ||
| if (resolved.toLowerCase().indexOf(path.toLowerCase()) !== 0) { | ||
| const resolvedLower = resolved.toLowerCase() | ||
| const pathLower = path.toLowerCase() | ||
| if (resolvedLower !== pathLower && !resolvedLower.startsWith(pathLower + sep)) { | ||
| return failEEXIST({ target: shim }) | ||
@@ -73,0 +77,0 @@ } |
+3
-1
@@ -7,2 +7,3 @@ // make sure that bins are executable, and that they don't have | ||
| readFile, | ||
| stat, | ||
| } = require('fs/promises') | ||
@@ -39,3 +40,4 @@ | ||
| const fixBin = (file, mode = execMode) => chmod(file, mode) | ||
| const fixBin = (file, mode = execMode) => stat(file) | ||
| .then(st => (st.mode & mode) === mode ? null : chmod(file, mode)) | ||
| .then(() => isWindowsHashbangFile(file)) | ||
@@ -42,0 +44,0 @@ .then(isWHB => isWHB ? dos2Unix(file) : null) |
+8
-16
| 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 | ||
| // global top pkgs on windows get bins installed in {prefix}. | ||
| // | ||
| // unix global top pkgs get their bins installed in {prefix}/bin, | ||
| // and mans in {prefix}/share/man | ||
| // unix global top pkgs get their bins installed in {prefix}/bin. | ||
| // | ||
| // non-top pkgs get their bins installed in {prefix}/node_modules/.bin, | ||
| // and do not install mans | ||
| // non-top pkgs get their bins installed in {prefix}/node_modules/.bin. | ||
| // | ||
| // 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. | ||
| // non-global top pkgs don't have any bins 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. | ||
| // | ||
| // As of v7, bin-links no longer installs man pages into the system man path for any package. `getPaths` still returns legacy man paths so pre-existing installs can be cleaned up on uninstall. | ||
| if (top && !global) { | ||
@@ -21,9 +18,4 @@ 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 }), | ||
| ]) | ||
| // 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. | ||
| return linkBins({ path, pkg, top, force: force || !top }) | ||
| } | ||
@@ -30,0 +22,0 @@ |
@@ -7,3 +7,3 @@ // if the thing isn't there, skip it | ||
| const { resolve, dirname } = require('path') | ||
| const { resolve, dirname, sep } = require('path') | ||
| const { lstat, mkdir, readlink, rm, symlink } = require('fs/promises') | ||
@@ -67,3 +67,3 @@ const { log } = require('proc-log') | ||
| target = resolve(dirname(to), target) | ||
| if (target.indexOf(path) === 0 || force) { | ||
| if (target === path || target.startsWith(path + sep) || force) { | ||
| return rm(to, rmOpts).then(() => CLOBBER) | ||
@@ -70,0 +70,0 @@ } |
+3
-2
@@ -1,2 +0,2 @@ | ||
| const { resolve, dirname } = require('path') | ||
| const { resolve, dirname, sep } = require('path') | ||
| const { lstat } = require('fs/promises') | ||
@@ -67,3 +67,4 @@ const throwNonEnoent = er => { | ||
| target = resolve(dirname(to), target) | ||
| if (target.indexOf(resolve(path)) !== 0) { | ||
| const base = resolve(path) | ||
| if (target !== base && !target.startsWith(base + sep)) { | ||
| return failEEXIST({ from, to, path }) | ||
@@ -70,0 +71,0 @@ } |
+12
-11
| { | ||
| "name": "bin-links", | ||
| "version": "6.0.0", | ||
| "version": "7.0.0", | ||
| "description": "JavaScript package binary linker", | ||
@@ -27,11 +27,11 @@ "main": "./lib/index.js", | ||
| "dependencies": { | ||
| "cmd-shim": "^8.0.0", | ||
| "npm-normalize-package-bin": "^5.0.0", | ||
| "proc-log": "^6.0.0", | ||
| "read-cmd-shim": "^6.0.0", | ||
| "write-file-atomic": "^7.0.0" | ||
| "cmd-shim": "^9.0.0", | ||
| "npm-normalize-package-bin": "^6.0.0", | ||
| "proc-log": "^7.0.0", | ||
| "read-cmd-shim": "^7.0.0", | ||
| "write-file-atomic": "^8.0.0" | ||
| }, | ||
| "devDependencies": { | ||
| "@npmcli/eslint-config": "^5.0.0", | ||
| "@npmcli/template-oss": "4.27.1", | ||
| "@npmcli/eslint-config": "^6.0.0", | ||
| "@npmcli/template-oss": "5.1.0", | ||
| "require-inject": "^1.4.4", | ||
@@ -53,3 +53,3 @@ "tap": "^16.0.1" | ||
| "engines": { | ||
| "node": "^20.17.0 || >=22.9.0" | ||
| "node": "^22.22.2 || ^24.15.0 || >=26.0.0" | ||
| }, | ||
@@ -60,5 +60,6 @@ "author": "GitHub Inc.", | ||
| "windowsCI": false, | ||
| "version": "4.27.1", | ||
| "publish": true | ||
| "version": "5.1.0", | ||
| "publish": true, | ||
| "updateNpm": false | ||
| } | ||
| } |
+5
-4
| # bin-links [](https://npm.im/bin-links) [](https://npm.im/bin-links) [](https://travis-ci.org/npm/bin-links) [](https://ci.appveyor.com/project/npm/bin-links) [](https://coveralls.io/github/npm/bin-links?branch=latest) | ||
| [`bin-links`](https://github.com/npm/bin-links) is a standalone library that links | ||
| binaries and man pages for JavaScript packages | ||
| binaries for JavaScript packages | ||
@@ -46,5 +46,6 @@ ## Install | ||
| for top level global packages on Windows.) | ||
| * Links man files listed under the `man` property of pkg to the share/man | ||
| directory. (This is only done for top-level global packages on Unix | ||
| systems.) | ||
| * As of v7, `bin-links` no longer installs man pages. Global installs | ||
| used to create symlinks under `${prefix}/share/man`; this is no longer | ||
| done. Pre-existing man symlinks from older installs are still | ||
| reported by `getPaths()` so that `npm uninstall -g` can clean them up. | ||
@@ -51,0 +52,0 @@ ### Contributing |
| 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 |
92
1.1%19808
-5.02%17
-5.56%406
-10.57%+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
Updated
Updated
Updated
Updated