Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Unable to install/downgrade with tilde versioning #636

Closed
ux-engineer opened this issue Dec 26, 2019 · 9 comments
Closed

[BUG] Unable to install/downgrade with tilde versioning #636

ux-engineer opened this issue Dec 26, 2019 · 9 comments
Labels
Bug thing that needs fixing

Comments

@ux-engineer
Copy link

What / Why

I have Typescript version ^3.7.4 installed as a devDependency in package.json:

{
  "name": "my-awesome-package",
  "version": "1.0.0",
  "devDependencies": {
    "typescript": "^3.7.4"
  }
}

When

I want to downgrade Typescript locked to the minor version 3.5, but with the newest patch versions applied. So the correct SemVer version tag would be with the tilde character, so ~3.5.0 in this case.

Current Behavior

Using NPM version 6.9.0 and Node 12.5.0.

I have tried running npm i -D typescript@~3.5.0, however after the installation package.json has "typescript": "^3.5.3".

Adding flag --save-exact doesn't work either, that results in "typescript": "3.5.3".

Expected Behavior

Package.json should have been updated with "typescript": "~3.5.3".

References

@ljharb
Copy link
Contributor

ljharb commented Dec 26, 2019

I’d expect the explicit prefix right be honored, but lacking that, you can NPM_CONFIG_SAVE_PREFIX=~ npm install typescript@~3.5.0 in the meantime, i think?

@Thunderforge
Copy link

I’d expect the explicit prefix right be honored, but lacking that, you can NPM_CONFIG_SAVE_PREFIX=~ npm install typescript@~3.5.0 in the meantime, i think?

This works, although on macOS and Linux, you have to do NPM_CONFIG_SAVE_PREFIX="~" npm install typescript@~3.5.0. If you do ~ instead of "~", then the prefix will expand to your user directory, which is obviously not what you want.

@darcyclarke darcyclarke added the Bug thing that needs fixing label Oct 30, 2020
@jameschensmith
Copy link
Contributor

jameschensmith commented Mar 15, 2021

Ran into this problem today in v6.14.6. The workaround is nice, but having the explicit prefix honored would have saved me a search to this GitHub issue 😅

Edit: Still a bug in v7.6.3.

@jameschensmith
Copy link
Contributor

jameschensmith commented Mar 16, 2021

I'm not too familiar with the architecture of npm, but I believe this bug would be for arborist. It uses npm-package-arg (npa) to parse package name and specifier, but npa is working as intended:

const npa = require("npm-package-arg");
console.log(JSON.stringify(npa("typescript@~3.5.0"), undefined, 2));
// {
//   "type": "range",
//   "registry": true,
//   "raw": "typescript@~3.5.0",
//   "name": "typescript",
//   "escapedName": "typescript",
//   "rawSpec": "~3.5.0",
//   "saveSpec": null,
//   "fetchSpec": "~3.5.0"
// }

The logic appears to be at reify.js#L900-L912 (v2.2.8 snippet), but this is just a guess. For lines 908-909, range should resolve to spec (which should be rawSpec from the example above), as it's a range that shouldn't be a subset of prefixRange.

These are my findings so far.

@jameschensmith
Copy link
Contributor

jameschensmith commented Mar 16, 2021

Follow-up. It appears to be the npa call on line 893 (v2.2.8 snippet). Currently, it's only passing spec as the argument, so the example above is actually the following (removed file path second argument because it's not necessary to replicate):

const npa = require("npm-package-arg");
console.log(JSON.stringify(npa("~3.5.0"), undefined, 2));
// {
//   "type": "tag",
//   "registry": true,
//   "raw": "~3.5.0",
//   "name": "~3.5.0",
//   "escapedName": "~3.5.0",
//   "rawSpec": "",
//   "saveSpec": null,
//   "fetchSpec": "latest"
// }

As you can see, the results are completely different. (1) It's not a range type anymore, and (2) rawSpec is an empty string. While this could be an issue with npa (i.e. should it handle parsing specs without packages?), I think the fix would be to address the npa call on line 893 mentioned above. Below is a possible solution:

    if (this[_resolvedAdd]) {
      const root = this.idealTree
      const pkg = root.package
      for (const { name } of this[_resolvedAdd]) {
-        const req = npa(root.edgesOut.get(name).spec, root.realpath)
+        const req = npa.resolve(name, root.edgesOut.get(name).spec, root.realpath)

I still think we should move this issue to arborist/npa for the issues respectively. @ux-engineer, I'll create the new tickets, referencing this ticket, and start working on a fix for both mentioned issues tomorrow ☺️

@jameschensmith
Copy link
Contributor

@isaacs, I tested this in in v7.7.0. It should be addressed now 😊👍

@isaacs
Copy link
Contributor

isaacs commented Jun 1, 2021

Fixed in arborist some time ago.

@isaacs isaacs closed this as completed Jun 1, 2021
@cscleison
Copy link

@isaacs i'm on npm 8.9.0
the example npm i -D typescript@~4.6.3 works fine. package.json will have "typescript": "~4.6.3", as expected.
however npm i ramda@~0.27.0 will give me "ramda": "^0.27.2",

interestingly, if I do npm update ramda afterwards, it doesn't update to 0.28 for example. it says it's up to date.

@ljharb
Copy link
Contributor

ljharb commented May 6, 2022

That’s expected since 0.28 isn’t in-range.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug thing that needs fixing
Projects
None yet
Development

No branches or pull requests

7 participants