npm, Cargo, Composer et pip interprètent tous de manière différente le même raccourci semver, et seulement deux des treize expressions de plage que j'ai testées se comportent de manière identique sur les quatre.

J'ai écrit des parseurs distincts pour chaque gestionnaire, suivi leurs spécifications officielles, puis j'ai testé chaque plage par rapport à une matrice de dix-neuf numéros de version. La grille de 13 × 19 (247 cellules) a dressé un portrait fragmenté : seules 17 cellules ont donné la même réponse « oui » ou « non » pour chaque outil, et la plupart de ces 17 étaient des rejets unanimes. En résumé, les outils sont d'accord sur le « non » bien plus souvent que sur le « oui ».

Pourquoi les outils divergent

Les quatre gestionnaires prétendent suivre le Semantic Versioning, pourtant chacun ajoute ses propres règles de raccourcis.

  • Caret (^) et dot-x – npm prend en charge le caret ; pip ignore à la fois le caret et le dot-x. Cela crée à lui seul un désaccord sur 49 cellules entre npm et pip.
  • Versions brutes – Cargo traite une version simple 1.2.3 comme une plage caret, ce qui signifie « compatible avec 1.x ». npm et Composer lisent la même chaîne comme une correspondance exacte, n'acceptant que 1.2.3.
  • Tilde (~) – Le tilde de Cargo verrouille la version mineure (~1.2 correspond à 1.2.* mais pas à 1.3.0). Le tilde de Composer verrouille la version majeure (~1.2 correspond à 1.*). Les deux interprétations divergent pour toute version qui modifie la composante mineure.

La gestion des pré-versions (pre-releases) apporte une autre surprise. Une plage comme ^1.2.3 n'inclut pas 2.0.0-rc.1, même si la partie numérique est inférieure à la limite supérieure. La règle : les pré-versions sont exclues à moins que la plage ne mentionne explicitement un identifiant de pré-version.

La seule syntaxe sûre entre les outils

L'expérience montre que les plages d'inégalité explicites — par exemple >=1.2.0 <2.0.0 — se comportent de la même manière dans npm, Cargo, Composer et pip. Chaque gestionnaire traite les deux limites comme des limites numériques littérales, sans sémantique cachée de caret ou de tilde.

Si vous devez exprimer « n'importe quelle version 1.x qui est au moins la 1.2 », écrivez-la en entier. Cela coûte quelques caractères supplémentaires, mais cela garantit une résolution prévisible partout où le code s'exécute.

Quand les raccourcis restent pertinents

Les raccourcis restent attractifs pour les projets mono-langage. Au sein d'un écosystème npm pur, ^1.2.3 capture succinctement « compatible avec les futures versions mineures et patch ». Il en va de même pour le caret de Cargo ou le tilde de Composer lorsque vous savez que l'outil consommateur ne changera pas. Le danger apparaît lorsque le même manifeste est réutilisé entre différents langages, ou lorsqu'un job de CI récupère des dépendances provenant de plusieurs écosystèmes.

À retenir

Compter sur les raccourcis semver pour la compatibilité multi-langage est un pari risqué. La seule façon fiable de garantir qu'une contrainte de version signifie la même chose partout est d'écrire des inégalités explicites. Lorsque vous avez besoin de brièveté, restez au sein d'un seul écosystème ; lorsque vous avez besoin de cohérence, sacrifiez le raccourci au profit de la clarté.