You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Vue du graphe compréhensible d'un coup d'œil, même sur un gros dépôt #50
La vue graph.html est illisible pour un humain. Constat sur un projet Symfony de 42 k lignes : 302 nœuds pour 302 communautés (chaque point est un groupe), groupes nommés d'après une classe arbitraire, tests et classes du framework mélangés au code applicatif, pelote centrale (« hairball »), couleurs sans sens. Au-delà de quelques dizaines de nœuds, un graphe à forces ne montre plus l'architecture.
User story
En tant que développeur qui découvre un projet, je veux comprendre son architecture d'un coup d'œil, sans lire, afin de savoir où intervenir, même sur un très gros dépôt.
Acceptance criteria
Trois niveaux de zoom (modèle C4, S. Brown ; mantra « overview first, zoom and filter, details on demand », B. Shneiderman 1996) : domaines, puis un domaine rangé en colonnes par couche, puis une classe
Variables visuelles porteuses de sens (J. Bertin) : position = couche, taille = coût, couleur = un seul signal (dette), légende visible
Liens agrégés avec leur nombre ; appels dans un sens interdit mis en évidence
Tests et classes du framework masqués par défaut, activables par filtre
Reste lisible sur un dépôt de 450 k lignes (40 000 nœuds)
Hints
Évaluer d'abord graphify export callflow-html (Mermaid) et graphify tree comme base avant d'écrire une nouvelle vue
Accessibilité : contrastes AA, information jamais portée par la seule couleur, navigation clavier
Conception validée le 2026-10-11 : vue en trois niveaux de zoom (domaines, puis un domaine en colonnes par couche, puis une classe), variables visuelles porteuses de sens, tests et framework masqués par défaut. Mise en œuvre lancée.
Approche envisagée : callflow-html et tree évalués comme base, mais tous deux chargent leur bibliothèque depuis un CDN sans version figée ni SRI, et callflow-html regroupe par communautés (le défaut constaté ici). Je reprends le principe d'agrégation par section et le chargement fidèle au sens des arcs (paths.restore_arc_direction), et j'écris une vue sans dépendance : données des trois niveaux calculées en Python (testables), rendu SVG/HTML natif, hors ligne.
Niveau 1 : les domaines du dépôt, longueur de barre = nombre de classes, appelants au-dessus des appelés, 15 boîtes au plus (les plus petites regroupées), les 15 liens les plus forts avec leur nombre d'appels. Les domaines qui rappellent un domaine situé au-dessus (cycle) portent un badge rouge « ! ».
Niveau 2 : un domaine, ses classes en colonnes par couche (Route, Controller, Service, Repository, Entity / Model, View, Other), arcs agrégés entre couches ; une classe qui appelle une couche à sa gauche est entourée de rouge avec un triangle.
Niveau 3 : une classe, ses méthodes triées par nombre d'appelants, appelants et appelés avec fichier:ligne de chaque appel.
Tests, framework / vendor et code hors racine masqués par défaut, chaque filtre affiche son nombre de classes.
Comment
graphify/zoom_html.py : build_zoom_data calcule tout ce que la page affiche (domaine, couche, agrégats, sens interdit, ordre des domaines), write_zoom_html écrit la page ; rendu SVG et HTML natif sans bibliothèque.
tests/test_zoom_html.py : 22 tests sur un graphe neutre (Item, Shared) : couches et domaines Symfony par type, par domaine, Laravel ; tests, vendor, hors racine ; sens interdit ; cycle entre domaines ; sens des arcs _src/_tgt ; gabarits ; échappement des libellés ; CLI.
README.md, ARCHITECTURE.md : commande et module documentés.
Pourquoi ce choix
Rendu écrit plutôt que callflow-html ou tree : les deux chargent leur bibliothèque depuis un CDN sans version figée ni SRI (callflow-html et tree chargent leur bibliothèque depuis un CDN sans version figée ni SRI #52), ne marchent pas hors ligne, et callflow-html regroupe par communautés, le défaut constaté ici. Repris : l'agrégation des arêtes par section et le contrat de sens des arcs (paths.restore_arc_direction).
Domaine sous un dossier de couche (src/Controller/Account/ donne Account) plutôt que le premier dossier sous src/ au sens strict : sur un projet Symfony rangé par type, la lecture stricte aurait affiché les couches à la place des domaines.
Seuls les appels EXTRACTED peuvent être signalés à contre-sens : un appel INFERRED (résolu par le nom) est compté et tracé en pointillé, jamais accusé. Alternative écartée : tout compter, qui aurait signalé des dépendances non prouvées.
Au niveau 1, les liens de cycle sont révélés au survol ou au focus, le badge reste visible : la première version les traçait tous et produisait une pelote rouge sur ClientXCMS (20 liens à contre-sens sur 15 boîtes).
Données calculées en Python plutôt qu'en JavaScript : les règles qui portent un jugement sont testées par pytest.
Apprentissages
Charger graph.json dans un nx.Graph fusionne les arêtes parallèles (un appel et une référence entre les mêmes nœuds) : la vue lit donc la liste brute des liens pour ne perdre aucun appel.
Le marqueur _callable_class (posé par le moteur d'extraction, toutes langues) identifie les classes de façon fiable ; les méthodes sont les cibles des arêtes method.
Sur le projet A (rangé par type), 290 classes (entités, dépôts à plat) n'ont pas de domaine connu : c'est l'architecture réelle, pas un défaut de la vue.
Contraste du texte en SVG vérifié par calcul des paires de couleurs, axe-core ne le mesure pas sur le SVG.
Suite complète lancée avant les deux derniers ajustements de placement des libellés (script de la page) ; tests ciblés relancés après.
Quality
Tests : tests/test_zoom_html.py 22/22 ; suite complète 7641 passed, 14 skipped, 0 failed ; tests ciblés après les derniers ajustements 117 passed.
Contrôle de mutation : retirer la règle EXTRACTED, lire source/target au lieu de _src/_tgt, ou désactiver le marquage des cycles fait échouer un test à chaque fois.
Ruff : 0. Pyright : 0 erreur sur les fichiers nouveaux ; aucune nouvelle erreur sur cli.py et __main__.py (2 erreurs préexistantes sur main).
Accessibilité : axe-core 4.10.3 (WCAG 2.0/2.1 A et AA), 0 violation sur 3 niveaux x 2 thèmes x 3 projets réels ; parcours clavier aller-retour vérifié ; aucun défilement horizontal à 320 px ; aucun texte sous 12 px.
Activity
github-actions commentedon Oct 11, 2026
Thanks for opening this issue, @alexwrite. A maintainer will take a look soon.
If you would like to discuss it in real time, come say hi on our Discord server. For longer-form questions and ideas there is also GitHub Discussions.
To help us triage, please make sure the report includes what you expected, what actually happened, and the steps (and a small sample) to reproduce it.
alexwrite commentedon Oct 11, 2026
Conception validée le 2026-10-11 : vue en trois niveaux de zoom (domaines, puis un domaine en colonnes par couche, puis une classe), variables visuelles porteuses de sens, tests et framework masqués par défaut. Mise en œuvre lancée.
alexwrite commentedon Oct 11, 2026
Prise en charge (branche
feat/zoom-view).Périmètre de fichiers visé :
graphify/zoom_html.py(nouveau : calcul des trois niveaux + rendu HTML autonome)graphify/cli.py,graphify/__main__.py(sous-commandegraphify export zoom-html, aide CLI)README.md,ARCHITECTURE.mdtests/test_zoom_html.py(nouveau)Approche envisagée :
callflow-htmlettreeévalués comme base, mais tous deux chargent leur bibliothèque depuis un CDN sans version figée ni SRI, etcallflow-htmlregroupe par communautés (le défaut constaté ici). Je reprends le principe d'agrégation par section et le chargement fidèle au sens des arcs (paths.restore_arc_direction), et j'écris une vue sans dépendance : données des trois niveaux calculées en Python (testables), rendu SVG/HTML natif, hors ligne.alexwrite commentedon Oct 11, 2026
Fait
graphify export zoom-htmlécrit une page HTML autonome, hors ligne, en trois niveaux de zoom : PR feat(export): add zoom-html, a three-level architecture view #57.fichier:lignede chaque appel.Comment
graphify/zoom_html.py:build_zoom_datacalcule tout ce que la page affiche (domaine, couche, agrégats, sens interdit, ordre des domaines),write_zoom_htmlécrit la page ; rendu SVG et HTML natif sans bibliothèque.graphify/cli.py,graphify/__main__.py: sous-commandeexport zoom-html, aide CLI.tests/test_zoom_html.py: 22 tests sur un graphe neutre (Item,Shared) : couches et domaines Symfony par type, par domaine, Laravel ; tests, vendor, hors racine ; sens interdit ; cycle entre domaines ; sens des arcs_src/_tgt; gabarits ; échappement des libellés ; CLI.README.md,ARCHITECTURE.md: commande et module documentés.Pourquoi ce choix
callflow-htmloutree: les deux chargent leur bibliothèque depuis un CDN sans version figée ni SRI (callflow-html et tree chargent leur bibliothèque depuis un CDN sans version figée ni SRI #52), ne marchent pas hors ligne, etcallflow-htmlregroupe par communautés, le défaut constaté ici. Repris : l'agrégation des arêtes par section et le contrat de sens des arcs (paths.restore_arc_direction).src/Controller/Account/donneAccount) plutôt que le premier dossier soussrc/au sens strict : sur un projet Symfony rangé par type, la lecture stricte aurait affiché les couches à la place des domaines.Apprentissages
graph.jsondans unnx.Graphfusionne les arêtes parallèles (un appel et une référence entre les mêmes nœuds) : la vue lit donc la liste brute des liens pour ne perdre aucun appel.graphify export <format> --helpn'atteint jamais l'aide détaillée : la garde d'aide universelle répond avant (L'aide détaillée de graphify export <format> --help est inaccessible #53)._callable_class(posé par le moteur d'extraction, toutes langues) identifie les classes de façon fiable ; les méthodes sont les cibles des arêtesmethod.Faiblesses restantes
Quality
tests/test_zoom_html.py22/22 ; suite complète 7641 passed, 14 skipped, 0 failed ; tests ciblés après les derniers ajustements 117 passed.source/targetau lieu de_src/_tgt, ou désactiver le marquage des cycles fait échouer un test à chaque fois.cli.pyet__main__.py(2 erreurs préexistantes surmain).Merge: three-level zoom view, export zoom-html (#50)