Liens entre exigences (SpecRelation)
Conventions des exemples de cette page
Pour ne pas répéter la même amorce partout, les exemples qui suivent supposent ce décor. Chaque bloc ne montre donc que ce qu'il démontre.
import { loadReqIfPackage, ReqIfIndex } from "reqif-preview";
// Les octets de votre fichier .reqif ou .reqifz.
// Voir [Démarrage](/fr/guide/demarrage) pour les obtenir depuis un <input type="file">,
// depuis Node ou depuis une URL.
declare const bytes: Uint8Array;
const pkg = await loadReqIfPackage(bytes);
const doc = pkg.document; // le premier document du paquet
// pkg.documents, pas pkg.document : c'est ce qui résout les relations qui
// traversent la frontière entre deux .reqif d'un même .reqifz.
const index = new ReqIfIndex(pkg.documents);
const spec = doc.coreContent.specifications[0];
const obj = index.specObjects.get(spec.children[0].objectRef)!;Les liens typés entre exigences — « dérive de », « satisfait », « trace vers » — sont affichés automatiquement pour chaque objet qui en possède : ses liens sortants (→) et entrants (←), avec le nom du type de relation et un lien d'ancrage vers l'objet lié si celui-ci est rendu dans la même page.
<div class="reqif-relations">
<div class="reqif-relations-label">Liens</div>
<div class="reqif-relation">
<span>→</span> <span>Dérive de</span>
<a href="#reqif-obj-...">Exigence système — Authentification</a>
</div>
</div>Si l'objet lié n'est pas trouvé, le libellé s'affiche quand même, sans lien cliquable, et l'événement unresolved-reference est émis (diagnostics).
C'est visible par défaut, y compris en readingMode :
const html = await renderPackageToHtml(pkg, { showRelations: false }); // pour le masquerRelations entre documents d'un même .reqifz
Elles se résolvent. La spec type SOURCE et TARGET d'une SpecRelation en GLOBAL-REF (clause 11, règle 5b), c'est-à-dire qu'une relation peut légalement viser un objet d'un autre .reqif du paquet — c'est même le scénario d'échange canonique : exigences client d'un côté, exigences système de l'autre, reliées par « dérive de ».
renderPackageToHtml construit donc un index unique couvrant tous les documents.
Si vous appelez renderDocumentToHtml document par document, chacun n'est indexé que sur lui-même, et les relations qui traversent la frontière ne résolvent plus. Passez votre propre index partagé en 4ᵉ argument pour retrouver le même comportement :
const options: RenderOptions = { layout: "tabs" };
const index = new ReqIfIndex(pkg.documents); // et non pkg.document
const html = await renderDocumentToHtml(doc, pkg.attachments, options, index);pkg.documents, pas pkg.document
pkg.document est un accesseur de confort pour le cas mono-document ; il ne renvoie que le premier. Passer celui-là au constructeur reconstruit exactement l'index partiel qu'on cherchait à éviter.
Objets rendus plusieurs fois
Un même SpecObject peut légalement apparaître à plusieurs endroits d'une arborescence — une exigence transverse citée sous deux chapitres, par exemple.
Seule la première occurrence porte l'id d'ancrage. C'est déjà ce que fait un navigateur en résolvant un fragment : émettre le même id plusieurs fois produit un HTML invalide sans rendre les autres occurrences atteignables pour autant. Chaque doublon émet un événement duplicate-dom-id.
Conséquence pratique : un lien de relation vers un objet dupliqué mène toujours à sa première apparition dans l'ordre du document. C'est déterministe et stable entre deux rendus.
Ancres : la forme des identifiants
| Élément | id émis |
|---|---|
| Document (onglet) | reqif-doc-<identifiant du header> |
| Spécification (onglet) | reqif-spec-<identifiant de la Specification> |
| Objet | reqif-obj-<identifiant du SpecObject> |
Ils dérivent tous de l'identifiant ReqIF, jamais d'un compteur de position : un lien partagé survit à l'insertion d'un élément avant sa cible.
Un routeur SPA peut neutraliser ces liens
Les liens de relation sont de simples <a href="#…">, comme les onglets. Un framework qui intercepte les clics internes et fait history.pushState laisse :target inchangé : le lien ne rouvrira pas l'onglet contenant sa cible. Le mécanisme et les remèdes sont détaillés dans Onglets, numérotation, lecture.
Limite actuelle
Seules les SpecRelation — liens objet-à-objet — sont affichées. Les RelationGroup, qui regroupent des relations entre deux Specification, sont parsées (doc.coreContent.specRelationGroups) mais pas encore rendues. Elles restent exploitables directement via le modèle de données si vous en avez besoin.