Skip to content

Instantly share code, notes, and snippets.

@daleyjem
Last active February 8, 2023 21:05
Show Gist options
  • Save daleyjem/31b5d91a18c2ebcf6b6a191d277a51ba to your computer and use it in GitHub Desktop.
Save daleyjem/31b5d91a18c2ebcf6b6a191d277a51ba to your computer and use it in GitHub Desktop.
How to add a caret to package.json versions without getting latest semver match

It doesn't make sense upon initial description reading, but there is a use case for it... Updating a package.json dependency to use a caret without getting the latest semver match.

I'm currently working on a very large project, in which we would like to enforce exact version matches across all child workspace package.json files.

Understand that when I say child workspace packages, you mustn't assume this project is a monorepo that publishes its packages. It uses yarn workspaces simply for the benefit of doing non-relative-path imports:

import { thing } from 'internal-package-a'
// vs
import { thing } from '../path/to/some/index.js'

Anyway, we currently "fix" the lack of version parity by incorporating resolutions in the root package.json file, and in many cases, we had versions defined there that didn't use a caret (^). Well now we want carets, if not just for getting rid of yarn install warnings of resolutions not meeting a requested version from somewhere else.

I want to add these carets as a "silent" update though. I know that the current versions used work, and there's no promise that even a newer patch version bump isn't going to make things in my project break. If we want to upgrade individual versions of stuff, that should be in another story.

So how is this done you ask?

It's kind of easy actually, but a bit of a manual process. I would in most cases never recommend manually editing the yarn.lock file, but in this one, it is necessary.

Let's say there's an entry in your yarn.lock file that looks like this:

assert@1.1.1:
  version "1.1.1"
  resolved "https://registry.yarnpkg.com/assert/-/assert-1.1.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91"
  integrity sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=
  dependencies:
    util "0.10.3"

...and I want to add a caret to assert in my package.json file:

  "dependencies": {
    "assert": "^1.1.1"
  }

If I just run yarn install after that change, the yarn.lock file is going to update to something like this:

assert@^1.1.1:
  version "1.30.1"
  resolved "https://registry.yarnpkg.com/assert/-/assert-1.30.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91"
  integrity sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=
  dependencies:
    util "0.10.3"

Well that's not what I want. I want to stay at version 1.1.1. In that case, what you want to do is copy everything below the first declaration line (assert@^1.1.1) from the previous commit diff and paste it over the new stuff (version, resolved, integrity, etc.). Then, running yarn install after that should not update the yarn.lock again, and you'll be locked into version 1.1.1. It's almost as if you originally added the caret at the time when 1.1.1 was the latest version.

assert@^1.1.1:
  version "1.1.1" # I copied from this line
  resolved "https://registry.yarnpkg.com/assert/-/assert-1.1.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91"
  integrity sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=
  dependencies:
    util "0.10.3" # ...to this line

Note: This has only been tested with yarn v1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment