165 lines
5.2 KiB
Markdown
165 lines
5.2 KiB
Markdown
# 34. Packages, identité et collisions de namespaces
|
|
|
|
## 34.1 Identité indépendante du namespace — V1 REQUIS — FIGÉ
|
|
|
|
L'identité d'un package est indépendante de ses namespaces internes.
|
|
|
|
Identité canonique :
|
|
|
|
```text
|
|
vendor/package
|
|
```
|
|
|
|
Coordonnée exacte :
|
|
|
|
```text
|
|
vendor/package@version
|
|
```
|
|
|
|
Sélecteur de dépendance :
|
|
|
|
```text
|
|
vendor/package@requirement
|
|
```
|
|
|
|
Exemples :
|
|
|
|
```text
|
|
saselang/core@1.4.0
|
|
saselang/compiler-core@^0.8
|
|
acme/http-client@>=2.5,<3.0
|
|
sdl/sdl@3.1.*
|
|
```
|
|
|
|
Le `vendor/package` désigne l'identité logique. La version exacte ou l'exigence SemVer ne change jamais cette identité ; elle sélectionne une instance/résolution de cette identité.
|
|
|
|
Le namespace interne peut être totalement différent et ne doit pas être dérivé automatiquement de `vendor/package`.
|
|
|
|
## 34.2 Syntaxe des identifiants package — V1 REQUIS — FIGÉE EN PRINCIPE
|
|
|
|
Pour `vendor` et `package` :
|
|
|
|
```regex
|
|
[a-z][a-z0-9]*(?:-[a-z0-9]+)*
|
|
```
|
|
|
|
Règles :
|
|
|
|
- ASCII lowercase ;
|
|
- `-` sépare les mots à l'intérieur d'un composant ;
|
|
- `_` est interdit ;
|
|
- aucune conversion automatique `-` <-> `_` n'existe ;
|
|
- `/` sépare `vendor` et `package` ;
|
|
- `@` introduit une version exacte ou un requirement SemVer.
|
|
|
|
Cette convention doit fonctionner de manière identique dans les manifests, le resolver, le lockfile, les outils et la qualification `from` des imports.
|
|
|
|
## 34.3 Collision de namespaces — V1 REQUIS — FIGÉ
|
|
|
|
Deux packages peuvent légalement définir le même namespace et le même nom de symbole sans représenter le même type.
|
|
|
|
Par exemple, deux packages peuvent chacun fournir :
|
|
|
|
```text
|
|
namespace parser.ast;
|
|
public class Node
|
|
```
|
|
|
|
L'identité sémantique réelle d'un symbole inclut au minimum :
|
|
|
|
```text
|
|
instance de package résolue
|
|
+ namespace
|
|
+ symbole
|
|
```
|
|
|
|
Ainsi :
|
|
|
|
```text
|
|
acme/parser@2.4.1 :: parser.ast.Node
|
|
other/parser@5.0.0 :: parser.ast.Node
|
|
```
|
|
|
|
sont deux types distincts.
|
|
|
|
## 34.4 Qualification d'import par dépendance — V1 REQUIS — FIGÉ
|
|
|
|
Tout symbole provenant d'une dépendance externe doit être importé explicitement avec une clause `from` contenant son sélecteur canonique :
|
|
|
|
```text
|
|
from "vendor/package@requirement"
|
|
```
|
|
|
|
Direction syntaxique :
|
|
|
|
```text
|
|
import func some.namespace::function from "sdl/sdl@2.1.*" as sdlfun1;
|
|
import type some.namespace.Type from "acme/parser@^3.0" as ParserType;
|
|
```
|
|
|
|
La grammaire finale des différentes formes `import type|func|const|var` reste à harmoniser avec la grammaire lexicale complète, mais les règles sémantiques suivantes sont figées :
|
|
|
|
- `from` est **obligatoire** pour toute provenance extérieure au package courant ;
|
|
- le sélecteur `vendor/package@requirement` doit correspondre à un requirement effectivement déclaré dans le scope de dépendances applicable au fichier/package ;
|
|
- `from` ne déclenche jamais une résolution ad hoc ;
|
|
- le lockfile associe ce requirement à une version exacte résolue ;
|
|
- les dépendances transitives ne sont pas directement importables : un package qui utilise directement leur API doit les déclarer comme dépendances directes ;
|
|
- après l'import, le code utilise le nom local du symbole ou son alias ; la coordonnée package n'apparaît pas dans les expressions ordinaires.
|
|
|
|
Sans `from`, un `import` ne peut viser que le package courant.
|
|
|
|
L'alias `as` reste facultatif lorsque le nom local obtenu est unique dans le fichier. Il devient nécessaire lorsque plusieurs imports produiraient le même nom local ou lorsqu'un renommage explicite est souhaité.
|
|
|
|
## 34.5 Plusieurs versions directes d'une même identité — V1 REQUIS — FIGÉ EN PRINCIPE
|
|
|
|
Un même package consommateur peut déclarer plusieurs requirements directs pour le même `vendor/package` afin d'utiliser plusieurs lignées incompatibles en parallèle.
|
|
|
|
Exemple conceptuel :
|
|
|
|
```text
|
|
sdl/sdl@2.1.*
|
|
sdl/sdl@^3.0
|
|
```
|
|
|
|
Le code choisit explicitement l'instance souhaitée avec `from` :
|
|
|
|
```text
|
|
import func ... from "sdl/sdl@2.1.*" as sdlfun1;
|
|
import func ... from "sdl/sdl@^3.0" as sdlfun2;
|
|
```
|
|
|
|
Si les deux imports exposent le même nom terminal dans le même fichier, des alias locaux distincts sont obligatoires. La sélection de version ne peut pas être reportée à un chemin pleinement qualifié utilisé directement dans le corps du code.
|
|
|
|
Pour un même scope effectif de dépendances, deux requirements portant sur le même `vendor/package` doivent être **disjoints**.
|
|
|
|
Exemples autorisés :
|
|
|
|
```text
|
|
sdl/sdl@2.1.*
|
|
sdl/sdl@^3.0
|
|
```
|
|
|
|
Exemples interdits :
|
|
|
|
```text
|
|
sdl/sdl@>=1.0
|
|
sdl/sdl@^4.5
|
|
```
|
|
|
|
car les ensembles de versions acceptées se recouvrent.
|
|
|
|
De même :
|
|
|
|
```text
|
|
sdl/sdl@^3.0
|
|
sdl/sdl@3.1.*
|
|
```
|
|
|
|
est interdit puisque `3.1.*` appartient déjà à `^3.0`.
|
|
|
|
Le resolver doit détecter l'intersection SemVer des requirements avant résolution. Une intersection non vide est une erreur de manifest, même si une version particulière permettrait techniquement de satisfaire les deux requirements.
|
|
|
|
Cette règle supprime toute ambiguïté entre plusieurs slots directs de la même identité et rend `from "vendor/package@requirement"` déterministe.
|
|
|
|
Le graphe transitif peut lui aussi contenir plusieurs versions d'une même identité. Chaque instance résolue conserve une identité de type distincte lorsque les versions ne sont pas unifiées par le resolver.
|