-
Notifications
You must be signed in to change notification settings - Fork 690
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
Support multiple version axes #948
Comments
Perhaps subsequent axes could require a label prefix such as: |
Nesting could be supported with multiple This would be interpreted as the following axes:
|
I’m confused why this would be useful. In the node ecosystem, compatibility with typescript would be achieved using peerDependencies, and compatibility with node using engines.node. Ecmascript editions are a completely inappropriate target since no engine implements each yearly edition all at once. |
For cross building. Any time you have a build matrix (GitHub, Travis CI, CircleCI) and maintain parallel releases of an API for different targets there is no good way to version these. In the Ivy / Maven world people end up abusing the artifact name. Consider the Slinky library which has a two axes build matrix, one for the Scala.js version and another for the Scala version (arguably there should be a third for the React version). It ends up looking like:
Where
That is true but what would your versioning be if you wanted to publish a single version of your library
That was only included to demonstrate a possible syntax. I tried to use TypeScript as it is more relatable to a wider audience whilst being orthogonal to the real issue we are having right now with ScalablyTyped. If that example doesn't appeal then there are many more. Vendored/bundled libraries Often people will vendor or bundle a library within their own and include some modifications. The new library needs its own version but it also needs to take into account the version of the code it is vendoring. The build matrix would have an axis for the downstream library version. The version should be the modification version crossed with the downstream library version. Transpiling from one language/tool to another Consider the case of ScalablyTyped that generates Scala types from TypeScript types. Different ScalablyTyped versions can produce wildly different types and there is a set of core types. Then there are different Scala.js versions and different Scala versions. As a library author who publishes a ScalablyTyped library containing the types then there would be a build matrix with these three axes. The version is a cross product of these three axes plus the main library version. I argue that TypeScript type library authors should be doing something similar but don't because there is no mechanism available. Cross building for different target environments Scala libraries are a prime example of where this is a problem. The Scala standard library is just a dependency like the TypeScript example but almost every library is published for multiple Scala versions. The build tool sbt has built-in syntax to get the right Scala version which appends the Scala binary version to the artifact name. With my proposal this would move to the version where it belongs. |
In the specific case for TS, you may or may not be able to, but in the general case, you'd include both versions in your peer deps range, and it would Just Work. I do it all the time for react, eslint, and babel plugins. I don't think semver is the right place to capture this information. You could certainly devise your own standard that composes multiple semver versions, of course. |
For the situation I am describing this doesn't work. Consider where the types are using a new feature that was added in TypeScript 5.0. The version range must start at 5.0. This forces all users to upgrade to TypeScript 5.0. You could argue well then only use TypeScript features from 4.0. But that kinda sucks for users who could otherwise take advantage of the new features of 5.0. The best solution (that I know of) would be to publish two different artifacts, one for each TypeScript
That is one way it could be done. It would be an extension to SemVer and use the same version field. For these reasons I think SemVer is the right place to do that. A major downside to this approach would be that it would be beholden to any future changes that SemVer were to make. If SemVer were to start using Anyway this is just a very early stage idea. It would obviously need a lot of buy in from tool maintainers to make it feasible. |
In that case, it'd be a semver-major bump, and you'd just maintain v1 and v2 simultaneously. Semver isn't a solution for all problems, and these problems aren't something I personally think semver should solve. |
But then this is a problem. Remember in this example the JavaScript library and the TypeScript definitions are separate packages but the goal is to keep the main versions in sync. The JavaScript library which has no dependency on TypeScript would be v1 and the TypeScript library which only has type definitions would be v1 and v2. Surely you wouldn't suggest to do a major bump of the JavaScript library. If you did then v1 and v2 would be the same identical binary. A minor release would then result in v1.1 and v2.1 which are still identical. A major release would then have to be v3 and v4 which makes no sense. Anyway, let's not Strawman on the TypeScript example. I concede on that. I guess people clearly do not cross build for TypeScript even though in theory they could. If you replace TypeScript for Node.js and would you find cross building for different Node versions? If not then there are plenty of other languages / environments / runtimes where this does happen.
No of course not. In my view SemVer is all about helping to communicate and enforce API compatibility. The version of the supported runtime etc is just as important in the compatibility story as the version of the library. Having a single version axis is insufficient. The real compatibility is more accurately described by the cartesian product of each version axis. It is not a valid solution to simply say bump a single version. There are by definition independent (emphasis) version axes. If we could use a single version then it would be done this way but it is not. The artifact name suffix is used because we have nothing else. The introduction to SemVer says:
We are still very much still living in dependency hell, even with SemVer. I believe that this proposal is right in line with this sentiment. It is extending the rules to be based on widespread common practices, at least in the Java/Scala ecosystem. |
In the assembler/C/C++ worlds we've been dealing with these sorts of things for decades: LibName-DOS5-x86 When the targets are different and evolve at different rates, you give them different names. |
There are situations where an API has multiple axes for compatibility.
Typical examples include:
Consider a JavaScript library with TypeScript definitions where those TypeScript definitions are published separately via DefinitelyTyped. The version of the library might be 1.0.0 and the types might be compatible with TypeScript 5.0. This TypeScript API really needs to have two separate versions, one for the library API version 1.0.0 and another for the TypeScript verison 5.0. If the TypeScript library is published with the same version as the JavaScript library 1.0.0 then there is no way to signal that it might not be compatible with TypeScript 4.0 for example.
Some approaches might include:
1.0.0-typescript.5.0
foo_typescript5
version1.0.0
None of these are great.
I propose SemVer 3 which supports multiple version axes.
One form could be:
1.0.0/5.0
This might be a bit too simplistic. How could we handle adding/removing an axis and or changing the order?
The text was updated successfully, but these errors were encountered: