npm, Cargo, Composer en pip interpreteren allemaal dezelfde semver-afkortingen anders, en slechts twee van de dertien range-expressies die ik heb getest, gedragen zich identiek bij alle vier de managers.

Ik heb voor elke manager aparte parsers geschreven, hun officiële specificaties gevolgd en vervolgens elke range getest tegen een matrix van negentien versienummers. De 13 × 19-matrix (247 cellen) gaf een gefragmenteerd beeld: slechts 17 cellen gaven bij elke tool hetzelfde "ja" of "nee"-antwoord, en de meeste van die 17 waren unanieme afwijzingen. Kortom, de tools zijn veel vaker het eens over "nee" dan over "yes".

Waarom de tools uiteenlopen

Alle vier de managers beweren Semantic Versioning te volgen, maar elke manager voegt zijn eigen regels voor afkortingen toe.

  • Caret (^) en dot-x – npm ondersteunt caret; pip negeert zowel caret als dot-x. Dat alleen al zorgt voor een verschil van 49 cellen tussen npm en pip.
  • Bare versions – Cargo behandelt een gewone 1.2.3 als een caret-range, wat betekent: "compatibel met 1.x". npm en Composer lezen dezelfde string als een exacte match en accepteren alleen 1.2.3.
  • Tilde (~) – De tilde van Cargo legt de minor versie vast (~1.2 komt overeen met 1.2.* maar niet met 1.3.0). De tilde van Composer legt de major versie vast (~1.2 komt overeen met 1.*). De twee interpretaties lopen uiteen bij elke versie waarbij het minor-component verandert.

De afhandeling van pre-releases zorgt voor een extra verrassing. Een range zoals ^1.2.3 bevat 2.0.0-rc.1 niet, ook al is het numerieke deel lager dan de bovengrens. De regel: pre-releases worden uitgesloten, tenzij de range expliciet een pre-release-identifier vermeldt.

De enige veilige syntax voor meerdere tools

Het experiment laat zien dat expliciete ongelijkheids-ranges — bijvoorbeeld >=1.2.0 <2.0.0 — op dezelfde manier werken in npm, Cargo, Composer en pip. Elke manager behandelt de twee grenzen als letterlijke numerieke limieten, zonder verborgen caret- of tilde-semantiek.

Als je "elke 1.x versie die minstens 1.2 is" wilt uitdrukken, schrijf het dan volledig uit. Het kost een paar extra tekens, maar het garandeert een voorspelbare resolutie, waar de code ook draait.

Wanneer afkortingen nog steeds zinvol zijn

Afkortingen blijven aantrekkelijk voor projecten in één taal. Binnen een puur npm-ecosysteem vat ^1.2.3 bondig samen: "compatibel met toekomstige minor- en patch-releases". Hetzelfde geldt voor de caret van Cargo of de tilde van Composer wanneer je weet dat de tool die het gebruikt niet zal veranderen. Het gevaar ontstaat wanneer hetzelfde manifest wordt hergebruikt over taalgrenzen heen, of wanneer een CI-job afhankelijkheden uit meerdere ecosystemen ophaalt.

Conclusie

Vertrouwen op semver-afkortingen voor compatibiliteit tussen verschillende talen is een gok. De enige betrouwbare manier om te garanderen dat een versiebeperking overal hetzelfde betekent, is door expliciete ongelijkheden te schrijven. Als je beknoptheid nodig hebt, blijf dan binnen één ecosysteem; als je consistentie nodig hebt, ruil de afkorting dan in voor duidelijkheid.