From 4b9f928a906a424c3f8a8c425e9f3a895a4c5da8 Mon Sep 17 00:00:00 2001 From: Javier Sagredo Date: Thu, 7 May 2026 01:15:54 +0200 Subject: [PATCH] Show tyvars on class node labels MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Class nodes now read "BftCrypto c" / "Bar a b" instead of just the class name, in both the classes view (Render.hs's classNodes) and the instance-view ensureClassNode helpers. External classes — for which we don't know the tyvars — still fall back to the bare name. Edge labels (the positional substitution into a superclass's args) keep using the *origin* class's tyvar names via edgeLabel, so an arrow `Bar a b ──(b)──► Foo b` reads consistently — same letter on edge and target node. Co-Authored-By: Claude Opus 4.7 (1M context) --- data/viewer.js | 13 +++++++++++-- src/Classgraph/Render.hs | 13 ++++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/data/viewer.js b/data/viewer.js index f86a705..4e20c6d 100644 --- a/data/viewer.js +++ b/data/viewer.js @@ -533,9 +533,15 @@ if (seenNodes.has(id)) return id; seenNodes.add(id); const known = classById.get(id); + // Include the class's tyvars in the label when we have them + // (i.e. the class is defined in this project). External classes + // fall back to bare qnName — we don't have their tyvars here. + const label = (known && known.ciTyVars && known.ciTyVars.length > 0) + ? known.ciName.qnName + ' ' + known.ciTyVars.map(tv => tv.tvName).join(' ') + : qn.qnName; els.push({ group: 'nodes', data: Object.assign({ id, - label: qn.qnName, + label, kind: 'class', external: !known, package: qn.qnPackage, @@ -981,9 +987,12 @@ if (seenNodes.has(id)) return id; seenNodes.add(id); const known = classById.get(id); + const label = (known && known.ciTyVars && known.ciTyVars.length > 0) + ? known.ciName.qnName + ' ' + known.ciTyVars.map(tv => tv.tvName).join(' ') + : qn.qnName; els.push({ group: 'nodes', data: { id, - label: qn.qnName, + label, kind: 'class', external: !known, package: qn.qnPackage, diff --git a/src/Classgraph/Render.hs b/src/Classgraph/Render.hs index b6e9436..ff149bd 100644 --- a/src/Classgraph/Render.hs +++ b/src/Classgraph/Render.hs @@ -118,7 +118,7 @@ buildGraph pd sourceRoots = CyGraph classNodes = [ CyNode $ Aeson.object [ "id" Aeson..= renderQualName (ciName c) - , "label" Aeson..= qnName (ciName c) + , "label" Aeson..= classNodeLabel c , "kind" Aeson..= ("class" :: Text) , "module" Aeson..= qnModule (ciName c) , "package" Aeson..= qnPackage (ciName c) @@ -129,6 +129,17 @@ buildGraph pd sourceRoots = CyGraph | c <- pdClasses pd ] + -- A class node renders as `Foo a b c`, with the same names the + -- user wrote. Edge labels (positional substitution into a + -- superclass's args) keep using the *origin* class's tyvar names + -- via 'edgeLabel', so an arrow from `Bar a b` up to `Foo a` reads + -- as `(a)` on the edge and `Foo a` on the target node — same + -- letter, no aliasing. + classNodeLabel c = case ciTyVars c of + [] -> qnName (ciName c) + tvs -> qnName (ciName c) <> " " + <> T.intercalate " " (map tvName tvs) + familyNodes = [ CyNode $ Aeson.object [ "id" Aeson..= renderQualName (tfName f) -- 2.54.0