Skip to content

Votre propre rendu

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.

ts
import { loadReqIfPackage, ReqIfIndex } from "reqif-preview";

// Les octets de votre fichier .reqif ou .reqifz.
// Voir [Démarrage](/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)!;

Vous n'êtes pas obligé d'utiliser le HTML fourni. loadReqIfPackage — et parseReqIfXml pour du XML déjà en mémoire — vous donnent un modèle de données typé, acyclique et sérialisable (ReqIfDocument) qui reflète fidèlement le modèle UML de la spec ReqIF : Specification, SpecObject, SpecHierarchy, AttributeDefinition*, AttributeValue*, DatatypeDefinition*, etc.

Acyclique, et pourquoi ça compte

Les références croisées — typeRef, definitionRef, objectRef, sourceRef… — restent de simples chaînes d'identifiants. Pas d'objets imbriqués circulaires.

C'est un choix de conception, pas une facilité d'implémentation : un modèle cyclique casse JSON.stringify, casse le passage par postMessage vers un Web Worker, casse la mise en cache dans IndexedDB, et rend tout instantané de débogage illisible. Le prix à payer est une indirection à la lecture — c'est le rôle de ReqIfIndex.

ts
import { parseReqIfXml, ReqIfIndex } from "reqif-preview";

const xmlString = await (await fetch("/exigences.reqif")).text();
const doc = parseReqIfXml(xmlString);
const index = new ReqIfIndex(doc);

for (const spec of doc.coreContent.specifications) {
  for (const node of spec.children) {
    const requirement = index.specObjects.get(node.objectRef);
    console.log(requirement?.longName);
  }
}

ReqIfIndex accepte aussi bien un document qu'un tableau de documents. Pour un .reqifz multi-documents, passez pkg.documents — c'est ce qui fait résoudre les relations qui traversent la frontière entre deux .reqif. Voir Liens entre exigences.

Lire une valeur d'attribut

Trouver « l'attribut nommé ReqIF.Text » demande de traverser valuesdefinitionRefAttributeDefinitionlongName. Deux helpers exportés font ce chemin pour vous :

ts
import { resolveAttribute, valueToPlainText } from "reqif-preview";

const { value, definition } = resolveAttribute(obj, index, "ReqIF.Text");
const text = valueToPlainText(value, index); // string | undefined

La correspondance se fait sur le nom long ou l'identifiant, insensible à la casse et aux espaces (normalizeKey), parce que les exports réels écrivent indifféremment ReqIF.ForeignID, Foreign ID ou ForeignID.

valueToPlainText résout les libellés d'énumération si vous lui passez l'index — sans lui, une valeur d'énumération n'est qu'une liste d'identifiants.

Contenu enrichi

Pour un AttributeValueXHTML, vous disposez de :

ExpressionRésultat
value.valueun arbre XhtmlNode[] portable, sans dépendance au DOM
value.originalValuel'original avant simplification, s'il existe (détails)
renderXhtmlContent(value.value, { attachments })sérialise cet arbre en HTML assaini (sécurité)
xhtmlToPlainText(value.value)extrait le texte brut — recherche plein texte, export CSV

L'arbre XhtmlNode est délibérément minimal : un nœud est soit { type: "text", value }, soit { type: "element", tag, attributes, children }. Le préfixe de namespace est retiré et le nom de balise mis en minuscules à l'analyse, donc <xhtml:P> et <p> arrivent tous les deux comme "p".

Métadonnées de cycle de vie

extractLifecycleInfo(obj, index) renvoie l'auteur et la date de création/modification en appliquant les conventions reconnues (ReqIF.ForeignCreatedBy/On, ReqIF.ForeignModifiedBy/On), qu'elles soient stockées en chaîne ou en XHTML. C'est ce que le rendu par défaut affiche dans sa ligne « Créé par / Modifié par » ; l'exporter permet de la reconstruire à votre façon.

Rendre une seule spécification, de façon synchrone

renderSpecification est synchrone — pensé pour une UI virtualisée qui rend à la volée pendant le défilement. Il exige en contrepartie des pièces jointes déjà résolues :

ts
import { createAttachmentLookup, renderSpecification, ReqIfIndex } from "reqif-preview";

const index = new ReqIfIndex(pkg.documents);
const lookup = await createAttachmentLookup(pkg.document, pkg.attachments);

const html = renderSpecification(spec, index, lookup); // sync

Le modèle complet

Les définitions exactes sont dans src/types.ts, annotées avec le numéro de clause de la spec qu'elles implémentent. La page Modèle de données en donne la carte.

Publié sous licence MIT. Conforme à OMG ReqIF v1.2 (formal/2016-07-01).