The fact that Foo1 and Foo2 are both called "Foo" is an artefact of how humans write software, but its meaningless to the computer. Foo2 usually has all the features of Foo1, but because the API is programmatically incompatible, when it comes to the dependency tree, they should be totally separate items.
You see forms of this all over the place. Eg, HTTP APIs are usually /api/v1/ not /api/v1.2/. Debian's apt repository has packages for 'llvm-10', 'llvm-11', 'llvm-12', and so on. I used to think this was silly; but now I think it might be the only way to do that in a coherent way.
I'm going to try being even more clear:
"Package Foo v1.2.3" should usually be spelled "Package Foo1, v2.3"
For example, the migration from react 17.x.x to react 18.x.x is actually a change from depending on package react17 to depending on react18. React17 and react18 are two different packages which have been designed by the same team, and happen to have similar APIs in order to make migration easier.
If I designed npm today I'd make "react16", "react17" and "react18" all be essentially different packages (under a namespace). They should probably only share their lists of authorized authors.
You can see this confusion all over the place. For example, when setting up peerDependencies in a nodejs project, there are suggestions[1] to use a version like `"chai": ">= 1.5.2 < 2"`. This is because chai v1 and chai v2 are essentially different packages. You want to say "chai v1 should be a peer dependency". But its unintentionally awkward to say that clearly. And with the current nomenclature, there's no way to express a dependency on both chai1 and chai2 - despite them being different, incompatible packages.
Even though nodejs is obsessed about semver, it still makes a mess of things by pretending as if major versions and minor versions are similar. They are not.
[1] Last couple paragraphs of https://nodejs.org/es/blog/npm/peer-dependencies/
> For example, let’s say you support click^7. Click 8 comes out, and someone writes a library requiring click^8. Now your library can’t be installed at the same time as that other library, your requirements do not overlap.
What I'm arguing for is that click^7 and click^8 should be seen as different packages that (like any other packages with different names) can be installed side-by-side without issue. It sounds weird, but it makes this problem goes away entirely.
Nodejs and (I think) cargo both support this. I've never run into errors like this in rust or node.
Another advantage of this approach: Integration tests in all previous versions of a package should pass on the current version of that package. I'd love to see test runners which actually enforce this - which should be pretty easy to do in a language like rust where integration tests are clearly separated.
Sometimes (rarely) it makes sense to allow an integration test for react16 v1.0 to fail on react16 v2.0, but that implies a violation of semver compatibility. So it should be the exception. Not the default.
And promotion and bonuses! This is the major impetus for these efforts.
From top of mind it used to be Urchin Analytics, then Google analytics, then universal analytics and now GA4.
But these Windows go to 11?