Documentation
¶
Index ¶
- func ComputeCouplingMetrics(g DirectedGraph, config CouplingConfig) (map[string]*CouplingMetrics, error)
- func StronglyConnectedComponents(ctx context.Context, g DirectedGraph) ([][]string, error)
- type ChainFinder
- type CouplingConfig
- type CouplingMetrics
- type CycleDetector
- type CycleResult
- type DirectedGraph
- type MapGraph
- func (g *MapGraph) AddEdge(from, to string)
- func (g *MapGraph) AddNode(id string)
- func (g *MapGraph) HasNode(nodeID string) bool
- func (g *MapGraph) NodeCount() int
- func (g *MapGraph) NodeIDs() []string
- func (g *MapGraph) Predecessors(nodeID string) []string
- func (g *MapGraph) Successors(nodeID string) []string
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ComputeCouplingMetrics ¶
func ComputeCouplingMetrics(g DirectedGraph, config CouplingConfig) (map[string]*CouplingMetrics, error)
ComputeCouplingMetrics computes Robert Martin's coupling metrics for all nodes in the directed graph.
func StronglyConnectedComponents ¶ added in v0.2.2
func StronglyConnectedComponents(ctx context.Context, g DirectedGraph) ([][]string, error)
StronglyConnectedComponents returns every strongly connected component of g, including single-node components, using Tarjan's algorithm. Components are returned in reverse topological order: a component appears before any component it depends on.
The pass checks ctx once per visited node and returns ctx.Err() as soon as the context is cancelled.
Types ¶
type ChainFinder ¶ added in v0.2.2
type ChainFinder struct {
// contains filtered or unexported fields
}
ChainFinder answers longest-dependency-chain queries over a directed graph.
Finding the longest simple path in a graph that may contain cycles is NP-hard, so a ChainFinder walks the condensation instead: strongly connected components are collapsed to single vertices and the heaviest chains through the resulting DAG are memoized in one linear pass, weighting each component by how many nodes it holds. Each query then expands a component chain into a concrete route through the members of every component it crosses, so every chain returned is a real simple path in the graph.
A chain is maximal in dependency layers: no other simple path crosses more strongly connected components. Within a component the route is not guaranteed maximal — the final component is walked greedily through as many members as it can reach, while components the chain passes through are crossed by the shortest route between the edges that enter and leave them. Recovering the longest route through a cycle is the NP-hard problem again.
Chains are ranked by weight (the node count of the components they cross) and, between equally heavy chains, by the lexicographic order of the components they cross, each component named by its smallest member. That order depends only on the graph, not on traversal, so repeated queries over the same graph return the same chains.
func NewChainFinder ¶ added in v0.2.2
func NewChainFinder(ctx context.Context, g DirectedGraph) (*ChainFinder, error)
NewChainFinder builds the condensation of g and memoizes the best chain reachable from every component. Construction is linear in the graph size; each subsequent query is linear in the length of the chain it returns.
The condensation and the memoizing pass check ctx as they go and return ctx.Err() as soon as the context is cancelled.
func (*ChainFinder) LongestChain ¶ added in v0.2.2
func (f *ChainFinder) LongestChain() []string
LongestChain returns the longest chain anywhere in the graph.
func (*ChainFinder) LongestChainFrom ¶ added in v0.2.2
func (f *ChainFinder) LongestChainFrom(nodeID string) []string
LongestChainFrom returns the longest chain that starts at nodeID, or nil if the node is not in the graph.
func (*ChainFinder) LongestChains ¶ added in v0.2.3
LongestChains returns the limit best-ranked chains in the graph, best first. Chains may start anywhere, so a reported chain can be the tail of another. Every chain contains at least one edge: a node that depends on nothing is not a chain, so a graph without edges has none. A limit of zero or less returns nil.
The ranking pass is linear in the graph size times limit and checks ctx as it goes, returning ctx.Err() as soon as the context is cancelled.
type CouplingConfig ¶
type CouplingConfig struct {
// AbstractnessFunc computes the abstractness (0.0–1.0) for a given node.
// pyscn: ratio of public names matching abstract patterns.
// jscan: export ratio.
// If nil, Abstractness defaults to 0.0 for all nodes.
AbstractnessFunc func(nodeID string) (float64, error)
}
CouplingConfig configures coupling metric computation.
type CouplingMetrics ¶
type CouplingMetrics struct {
NodeID string
Ca int // Afferent coupling (incoming edges)
Ce int // Efferent coupling (outgoing edges)
Instability float64 // Ce / (Ca + Ce), 0 = maximally stable
Abstractness float64 // Provided by language-specific callback
Distance float64 // |Abstractness + Instability - 1|
}
CouplingMetrics holds Robert Martin's package coupling metrics for a node.
type CycleDetector ¶
type CycleDetector struct {
// contains filtered or unexported fields
}
CycleDetector finds strongly connected components using Tarjan's algorithm.
func NewCycleDetector ¶
func NewCycleDetector() *CycleDetector
NewCycleDetector creates a new CycleDetector.
func (*CycleDetector) DetectCycles ¶
func (d *CycleDetector) DetectCycles(g DirectedGraph) *CycleResult
DetectCycles finds all cycles (SCCs with size > 1) in the directed graph.
type CycleResult ¶
type CycleResult struct {
// Cycles contains all strongly connected components with more than one node.
Cycles [][]string
// HasCycles is true if any cycle was found.
HasCycles bool
// AffectedNodes contains all nodes that participate in at least one cycle.
AffectedNodes map[string]bool
}
CycleResult holds the result of cycle detection via Tarjan's SCC algorithm.
type DirectedGraph ¶
type DirectedGraph interface {
// NodeIDs returns all node identifiers in the graph.
NodeIDs() []string
// Successors returns the IDs of nodes that this node has edges to.
Successors(nodeID string) []string
// Predecessors returns the IDs of nodes that have edges to this node.
Predecessors(nodeID string) []string
// NodeCount returns the number of nodes in the graph.
NodeCount() int
// HasNode returns true if the node exists in the graph.
HasNode(nodeID string) bool
}
DirectedGraph provides read-only access to a directed graph. pyscn's DependencyGraph (map[string]*ModuleNode) and jscan's domain.DependencyGraph (method-based) can both implement this.
type MapGraph ¶
type MapGraph struct {
// contains filtered or unexported fields
}
MapGraph is a simple directed graph implementation backed by maps. Useful for testing and as a default implementation.
func (*MapGraph) AddEdge ¶
AddEdge adds a directed edge from → to. Both nodes are created if absent.
func (*MapGraph) Predecessors ¶
Predecessors returns the IDs of nodes that have an edge to nodeID.
func (*MapGraph) Successors ¶
Successors returns the IDs of nodes reachable by one edge from nodeID.