Issue 1:
Is there an existing issue for this?

I have searched the existing issues

Current Behavior

npm install -g creates a folder with the literal name ${XDG_DATA_HOME} in the current directory, and treats it as the data home dir.

Presumably something in the code is not escaping the variable properly under some conditions.

Note that I do have $XDG_HOME_DIR in my dotfiles and using launchctl. I have not been able to avoid the bug by un-setting the var.

This did not use to happen until the last few days. Unfortunately, this is rather annoying to debug because the bug itself specifically breaks global npm installation. So I can't run npm install -g npm@7.0.0 or npm install -g npm@7.20.1 to get a proper install of another version, for example.

Expected Behavior

The command uses the value of the XDG_DATA_HOME env var (or the default), without creating a dir named ${XDG_DATA_HOME}.

Steps To Reproduce

Run npm install -g or npx. For example:

npm install -g jq

Running npx jq also gives this error:

node:internal/modules/cjs/loader:930
throw err;
^

Error: Cannot find module 'commander'
Require stack:
- /Users/lgarron/.cache/npm/_npx/db665b9ed68ddd8b/node_modules/jq/bin/jq
at Function.Module._resolveFilename (node:internal/modules/cjs/loader:927:15)
at Function.Module._load (node:internal/modules/cjs/loader:772:27)
at Module.require (node:internal/modules/cjs/loader:999:19)
at require (node:internal/modules/cjs/helpers:93:18)
at Object.<anonymous> (/Users/lgarron/.cache/npm/_npx/db665b9ed68ddd8b/node_modules/jq/bin/jq:7:15)
at Module._compile (node:internal/modules/cjs/loader:1095:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1124:10)
at Module.load (node:internal/modules/cjs/loader:975:32)
at Function.Module._load (node:internal/modules/cjs/loader:816:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:79:12) {
code: 'MODULE_NOT_FOUND',
requireStack: [
'/Users/lgarron/.cache/npm/_npx/db665b9ed68ddd8b/node_modules/jq/bin/jq'
]
}

I don't know how related it is, but it's what led me to observing the directory issue.

Environment

npm 7.19.1

node v16.5.0

macOS 11.5

I know this report is not super helpful, but I could use some advice on how to debug this.

I've spent an hour in @npmcli/config to figure out where this is coming from, but it uses a lot of indirection to load configs. Most useful would probably be to bisect some packages, but I don't know how to do that when npm install -g is not working. (I tried to symlink ./${XDG_DATA_HOME} to the appropriate global directory, but that doesn't seem to work.)

Issue 2:
Current Behavior:

npm uninstall -g <package> doesn't run the preuninstall script

Also, npm install -g <package> doesn't run the preuninstall script from the previously installed version of the same package

Installing a newer version of a global package does trigger preuninstall in v6

Expected Behavior:

npm uninstall -g <package> should run the preuninstall script

Steps To Reproduce:

Since npm7 removed console output for scripts during installation, so I echo something to a logfile instead.

Create a package with these scripts:

{
"name": "testpackage",
"version":"0.0.1",
"scripts": {
"preinstall": "echo \"preinstall\" >> /logs/log.txt",
"preuninstall": "echo \"preuninstall\" >> /logs/log.txt"
}
}

run npm pack

run npm install -g ./testpackage-0.0.1.tgz

run npm install -g ./testpackage-0.0.1.tgz again (this should have triggered preuninstall for the previous installation)

run npm uninstall -g testpackage

confirm that the text file in /logs/log.txt does in fact not contain any 'preuninstall' lines

Images:

In v7:

In v6:

Environment:

OS: Windows 10

Node: 15.14.0

npm: 7.7.6