My latest articles:
- Advanced Bit Dependency Management and Configs
- Painless Monorepo Dependency Management with Bit
- The year 2021 for pnpm
- Trying pnpm on the JustAnswer multi-package repository
My videos:
Zoltan Kochan's npm packages
License: MIT License
which-pm
or preferred-pm
should probably read packageManager
from package.json
first, as corepack
uses it to determine which package manager should be used.
Before I read the codes, I feel it's difficult to make sure which package manager used by Process.Your codes inspire me, but I am still confused. How do you know we can find out the package manager through process.env.npm_config_user_agent
? Read the documents from Nodejs website ? I am really appreciated any answers about that.
Line 1 in 6da32f0
Line 4 in 6da32f0
In this type declaration, the return type is defined as Promise<whichpm.NPM | whichpm.YARN | whichpm.PNPM | whichpm.Other>
.
However, according to the actual code, this function could return null
.
Line 19 in 6da32f0
Therefore, the correct return type is Promise<whichpm.NPM | whichpm.YARN | whichpm.PNPM | whichpm.Other | null>
.
This type declaration should add null
to the type whichpm.Result
.
- type Result = NPM | YARN | PNPM | Other
+ type Result = NPM | YARN | PNPM | Other | null
Or, should add null
to the return type.
- declare function whichpm (pkgPath: string): Promise<whichpm.Result>
+ declare function whichpm (pkgPath: string): Promise<whichpm.Result | null>
Repro:
let renderHelp = require("render-help")
console.log('width =', process.stdout.columns)
console.log(renderHelp({
usages: ['pnpm add [options]'],
descriptionLists: [
{
title: 'Options',
list: [
{
name: '--filter',
description: `averylongsentenceaverylongsentenceaverylongsentenceaverylongsentenceaverylo`
}
]
}
]
}))
Prints:
width = 100
Usage: pnpm add [options]
Options:
--filter averylongsentenceaverylongsentenceaverylongsentenceaverylongsentenceavery
lo // <- terminal wraps the line, actually no \n
Edit:
packages/render-help/src/index.ts
Line 79 in 7eab989
Change the - 1
to - 3
should fix this issue.
If you run the following code snippet from inside of a workspace directory in an NPM package (like packages/<pkgname>
), the call to findYarnWorkspaceRoot()
in preferred-pm
ends up thinking that we're using Yarn.
import preferredPM from 'preferred-pm';
preferredPM(process.cwd()).then(pm => console.log(pm));
I'm not exactly sure how to fix this because you can't easily know if you're in an NPM workspace without recursively parsing the parent directories until you find a package.json
and see the workspaces
key.
It could be useful if packages like preferred-pm
could distinguish between those 2 as the difference between them is quite massive.
It seems that there is quite an easy way to do that. The only thing that needs to be checked is the __metadata:
field in the lock file. Berry is checking it like this:
https://github.com/yarnpkg/berry/blob/83311e1d4dec7fb6c0ead21f37efa9b687be58b9/packages/yarnpkg-core/sources/scriptUtils.ts#L86-L95
Which-pm and preferred-pm report "npm" when run inside of a yarn workspace. I would suggest using https://github.com/square/find-yarn-workspace-root to detect if there is a yarn workspace root, and running the detection from there too.
Workspaces support is now implemented in npm.
So, having workspaces in package.json should not force yarn anymore.
Lockfile should take precedence.
Thanks
There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.
Error type: undefined. Note: this is a nested preset so please contact the preset author if you are unable to fix it yourself.
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These updates are currently rate-limited. Click on a checkbox below to force their creation now.
@types/jest
, jest
, ts-jest
)These updates have been manually edited so Renovate will no longer make changes. To discard all commits and start over, click on a checkbox.
These updates are pending. To force PRs open, click the checkbox below.
These updates have all been created already. Click a checkbox below to force a retry/rebase of any.
.github/workflows/ci.yml
actions/checkout v1
actions/setup-node v1
pnpm/action-setup v2.4.0
better-path-resolve/package.json
is-windows ^1.0.2
mos 2.0.0-alpha.3
mos-plugin-readme ^1.0.4
tape ^5.3.2
node >=4
can-link/package.json
mos 2.0.0-alpha.3
mos-plugin-readme ^1.0.4
standard ^16.0.4
tape ^5.3.2
node >=10
can-write-to-dir/package.json
path-temp ^2.0.0
standard ^16.0.4
tape ^5.3.2
node >=10.13
cmd-extension/package.json
node >=10
comver-to-semver/package.json
tape ^5.3.2
node >=12.17
dir-is-case-sensitive/package.json
path-temp 2.0.0
@types/node 16.11.13
@types/tape ^4.13.2
tape ^5.3.2
ts-node ^10.4.0
typescript ^4.5.2
node >=10
graceful-git/package.json
retry ^0.13.1
safe-execa ^0.1.1
mos 2.0.0-alpha.3
mos-plugin-readme ^1.0.4
tape ^5.3.2
node >=10
is-inner-link/package.json
is-subdir ^1.2.0
make-dir ^3.1.0
mos 2.0.0-alpha.3
mos-plugin-readme ^1.0.4
standard ^16.0.4
symlink-dir ^5.0.1
tape ^5.3.2
node >=10
is-subdir/package.json
better-path-resolve 1.0.0
is-windows 1.0.2
mos 2.0.0-alpha.3
mos-plugin-readme ^1.0.4
tape ^5.3.2
node >=4
make-empty-dir/package.json
@zkochan/rimraf ^2.1.3
tape ^5.3.2
tempy ^1.0.1
node >=12.10
p-map-values/package.json
@types/jest ^27.0.3
jest ^27.4.3
ts-jest ^27.1.0
typescript ^4.5.2
node >=14
package.json
@changesets/cli ^2.18.1
typescript ^4.5.2
path-absolute/package.json
standard ^16.0.4
node >=4
path-temp/package.json
unique-string ^2.0.0
mos 2.0.0-alpha.3
mos-plugin-readme ^1.0.4
standard ^16.0.4
tape ^5.3.2
node >=8.15
preferred-pm/package.json
find-up ^5.0.0
find-yarn-workspace-root2 1.2.16
path-exists ^4.0.0
which-pm 2.0.0
ncp ^2.0.0
standard ^16.0.4
tape ^5.3.2
tempy ^1.0.1
node >=10
promise-share/package.json
p-reflect ^2.1.0
tape ^5.3.2
node >=8
read-ini-file/package.json
ini ^3.0.1
strip-bom ^4.0.0
mos 2.0.0-alpha.3
mos-plugin-readme ^1.0.4
standard ^16.0.4
tape ^5.3.2
node >=14.6
read-json5-file/package.json
json5 ^2.2.0
strip-bom ^4.0.0
mos 2.0.0-alpha.3
mos-plugin-readme ^1.0.4
standard ^16.0.4
tape ^5.3.2
node >=10
read-yaml-file/package.json
js-yaml ^4.1.0
strip-bom ^4.0.0
standard ^16.0.4
tape ^5.3.2
node >=10.13
realpath-missing/package.json
tape ^5.3.2
node >=10
rename-overwrite/package.json
@zkochan/rimraf ^2.1.2
fs-extra 10.1.0
jest ^27.4.3
load-json-file 6.2.0
standard ^16.0.4
symlink-dir ^5.0.1
tempy ^1.0.1
write-json-file ^4.3.0
node >=12.10
render-help/package.json
table ^6.7.5
@types/common-tags ^1.8.1
@types/jest ^27.0.3
@types/node 16.11.13
@types/table ^6.3.2
common-tags ^1.8.2
jest ^27.4.3
ts-jest ^27.1.0
typescript ^4.5.2
node >=10
resolve-link-target/package.json
standard ^16.0.4
symlink-dir ^5.0.1
tape ^5.3.2
node >=10
rimraf/package.json
rimraf ^3.0.2
standard ^16.0.4
node >=12.10
root-link-target/package.json
next-path ^1.0.0
path-temp 2.0.0
mos 2.0.0-alpha.3
mos-plugin-readme ^1.0.4
standard ^16.0.4
tape ^5.3.2
node >=10
run-groups/package.json
p-limit ^3.1.0
@types/node 16.11.13
@types/tape ^4.13.2
delay 5.0.0
tape ^5.3.2
ts-node ^10.4.0
typescript ^4.5.2
node >=10
safe-execa/package.json
@zkochan/which ^2.0.3
execa ^5.1.1
path-name ^1.0.0
node >=12
safe-promise-defer/package.json
promise-share ^1.0.0
@types/jest ^27.0.3
jest ^27.4.3
ts-jest ^27.1.0
typescript ^4.5.2
node >=12
which-pm-runs/package.json
@pnpm/exe ^8.6.12
bun ^0.8.1
cnpm ^7.1.1
execa ^5.1.1
npm ^8.2.0
tape ^5.3.2
yarn ^1.22.17
node >=4
which-pm/package.json
load-yaml-file ^0.2.0
path-exists ^4.0.0
standard ^16.0.4
tape ^5.3.2
node >=8.15
write-ini-file/package.json
ini ^3.0.1
make-dir ^3.1.0
write-file-atomic ^5.0.0
mos 2.0.0-alpha.3
mos-plugin-readme ^1.0.4
standard ^16.0.4
tape ^5.3.2
tempfile ^3.0.0
node >=14.6
write-json5-file/package.json
json5 ^2.2.0
sort-keys ^4.2.0
write-file-atomic ^3.0.3
mos 2.0.0-alpha.3
mos-plugin-readme ^1.0.4
standard ^16.0.4
tape ^5.3.2
tempfile ^3.0.0
node >=10.12
write-yaml-file/package.json
js-yaml ^4.1.0
write-file-atomic ^5.0.1
standard ^16.0.4
node >=16.14
Hey,
I use preferred pm to inform npm-check and at a project level this works well. However it often causes issues around global packages, in that after you update the package it seems to still be available for update. I would very much like a way to turn off preferred pm to global scipts.
Thanks!
Here is steps to reproduce:
pnpm add safe-execa
touch exec.mjs
with follow contents:import execa from 'safe-execa'
(async () => {
await execa.default('echo "hi"', [], {
stdio: 'inherit',
shell: true,
})
})()
node ./exec.mjs
will see the error below:xxxx/test-pnpm/test-publish/node_modules/.pnpm/@[email protected]/node_modules/@zkochan/which/which.js:10
Object.assign(new Error(`not found: ${cmd}`), { code: 'ENOENT' })
^
Error: not found: echo "hi"
should execute command successfully.
node -v prints: v16.15.1
safe-execa version: v0.1.2
Windows, macOS, or Linux?: macOS
After some research, I found that which.sync will throw a error like this:
TypeError: (opt.path || process.env.PATH || "").split is not a function
at getPathInfo (/xxxx/test/test-pnpm/test-publish/node_modules/.pnpm/@[email protected]/node_modules/@zkochan/which/which.js:19:56)
it seems that @zkochan/which
only accept string path option.
[edited to revise the request in light of correct understanding of the current behavior]
As per title, please implement isProperSubdir()
which would only return true
if the second parameter is a proper subdirectory of the first but not the same. This should be in the library because it should use the same path normalization/resolution strategy as the original function.
Alternatively we could add an optional boolean third argument to turn on the !==
check, defaulting to false
.
Implementation should be trivial and I could submit a PR, but please decide on the API variant.
I have no idea if I got it right, but as I understood it, realpath-missing
should return a path even for folders that does not exist (is missing), however, looking at the code, it is not the case.
I was looking for alternative of realpath
from node:fs/promises
which does not check for folder existence (like when we need to get realpath of a folder before its creation in case it does not exist yet), so I created the following function (using node:fs/promises
). Are you interested in pulling the code into you package? We could add a configuration parameter if we should check if the path exists (simply run and return the original await realpath(path)
) or not (run the function below).
Note that I wrote it in TypeScript.
import {realpath as rp} from 'node:fs/promises'
/**
* Get real path of a folder regardless if the folder exists
*
* @param path - Folder path to check
* @param append - Folders to append
* @returns Real path of the folder
*/
async function realpath({path, append}) {
if (/^\//.test(append)) {
path = append
append = undefined
}
if (/^\.\//.test(append)) {
append = append.replace(/^\.\//g, '')
}
path = path ? path.replace(/\/*$/, '') : path
path = path ? path.replace(/\/\/+/, '/') : path
append = append ? append.replace(/\/*$/, '') : append
append = append ? append.replace(/\/\/+/, '/') : append
while (/^\.\.\//.test(append)) {
const newPath = path ? path.replace(/\/[^/]*$/, '') : ''
if (path && newPath) {
path = newPath
} else if (path !== '/' && !newPath) {
path = '/'
} else {
throw Error(`Invalid path or append value provided.`)
}
append = append.replace(/^\.\.\//g, '')
}
if (!path) {
path = '/'
}
try {
return `${await rp(path)}${/^[^/]$/.test(path) && append ? '/' : ''}${append ? append : ''}`
} catch (e) {
if (e.code === 'ENOENT') {
let newPath = path.replace(/\/[^/]+$/, '')
if (newPath === path) {
if (path === '.') {
throw Error(e)
} else if (/^[^/]+$/.test(path)) {
const newAppend = `${path}${append ? `/${append}` : ''}`
return await this.realpath({path: '.', append: newAppend})
}
} else {
const newAppend = `${path && path !== '/' ? path.match(/[^/]+$/g)[0] : ''}${append ? `/${append}` : ''}`
return await this.realpath({path: newPath, append: newAppend})
}
}
throw Error(e)
}
}
Update
path
and append
values in order to make the function robust, including:
append
starts with a slash, then replace path
with append
value;append
starts with ./
, remove these characters;append
start with ../
, remove the final folder from path
:
join
from node:path
, as running join('/foo/bar', '../../../baz')
results in /baz
, but IMHO it should throw an error;append
and path
;// Test existing relative paths
realpath({path: '.'}) // '${PWD}'
realpath({path: './src'}) // '${PWD}/src'
realpath({path: 'src'}) // '${PWD}/src'
// Test existing absolute paths
realpath({path: '/etc'}) // '/etc'
realpath({path: '/'}) // '/'
// Test non-existent relative paths
realpath({path: 'asdf'}) // '${PWD}/asdf'
realpath({path: './asdf'}) // '${PWD}/asdf'
realpath({path: 'asdf/qwer'}) // '${PWD}/asdf/qwer'
realpath({path: './asdf/qwer'}) // '${PWD}/asdf/qwer'
// Test combining `append` with `../`
realpath({path: '/qwer/asdf/xzcv/yuoi', append: '../../../asdf'}) // '/qwer/asdf'
realpath({path: '/qwer/asdf/xzcv', append: '../../../asdf'}) // '/asdf'
realpath({path: '/qwer/asdf', append: '../../../asdf'}) // error
// Test some special cases
// - trailing slashes are removed
realpath({path: '/qwer/asdf/xzcv////', append: '../../../asdf////'}) // '/asdf'
// - multiple consequent slashes should be replaced with a slash
realpath({path: '/qwer/asdf////xzcv', append: '../../////../asdf'}) // '/asdf'
// - falsy `path` results in `/`
realpath({path: '', append: 'asdf'}) // '/asdf'
realpath({path: undefined, append: 'asdf'}) // '/asdf'
realpath({path: null, append: 'asdf'}) // '/asdf'
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.