namespace CodeGraph.Graph;
///
/// Set of basic algorithms to build for higher algorithms
///
public static class CodeGraphExtensions
{
public static CodeGraph Clone(this CodeGraph originalCodeGraph)
{
return originalCodeGraph.Clone(null, null);
}
///
/// Clones the given code graph.
/// Relationships and code element can be filtered to generate sub graphs.
/// If no code element list is given (null) all code elements are returned.
///
public static CodeGraph Clone(this CodeGraph originalCodeGraph, Func? relationshipFilter,
HashSet? codeElementIds)
{
List includedOriginalElements;
if (codeElementIds is null)
{
includedOriginalElements = originalCodeGraph.Nodes.Values.ToList();
}
else
{
includedOriginalElements = originalCodeGraph.Nodes.Values
.Where(n => codeElementIds.Contains(n.Id))
.ToList();
}
var clonedCodeStructure = new CodeGraph();
// First pass: Create all elements without setting relationships
foreach (var originalElement in includedOriginalElements)
{
var clonedElement = CloneElement(originalElement);
clonedCodeStructure.Nodes[clonedElement.Id] = clonedElement;
}
// Second pass: Set relationships (parent / child / relationships)
foreach (var originalElement in includedOriginalElements)
{
var clonedElement = clonedCodeStructure.Nodes[originalElement.Id];
// Set parent
if (originalElement.Parent != null)
{
// Note that we may lose the parent!
var parent = clonedCodeStructure.TryGetCodeElement(originalElement.Parent?.Id);
clonedElement.Parent = parent;
}
// Set children
foreach (var originalChild in originalElement.Children)
{
var clonedChild = clonedCodeStructure.TryGetCodeElement(originalChild.Id);
if (clonedChild is null)
{
continue;
}
clonedElement.Children.Add(clonedChild);
}
// Set relationships
foreach (var originalRelationship in originalElement.Relationships)
{
if (relationshipFilter == null || relationshipFilter(originalRelationship))
{
if (clonedCodeStructure.Nodes.ContainsKey(originalRelationship.TargetId))
{
var clonedRelationship = new Relationship(
clonedElement.Id,
originalRelationship.TargetId,
originalRelationship.Type,
originalRelationship.Attributes
);
clonedRelationship.SourceLocations.AddRange(originalRelationship.SourceLocations);
clonedElement.Relationships.Add(clonedRelationship);
}
}
}
}
return clonedCodeStructure;
}
private static CodeElement CloneElement(CodeElement originalElement)
{
return originalElement.CloneSimple();
}
///
/// Returns a subgraph with only the included elements and their associated relationships.
///
public static CodeGraph SubGraphOf(this CodeGraph graph, HashSet includedElements)
{
return graph.Clone(IncludeRelationship, includedElements);
bool IncludeRelationship(Relationship relationship)
{
return includedElements.Contains(relationship.SourceId) && includedElements.Contains(relationship.TargetId);
}
}
///
/// Returns a subgraph with the root element and all children and associated relationships
///
public static CodeGraph SubGraphOf(this CodeGraph graph, CodeElement rootElement)
{
var includedElements = rootElement.GetChildrenIncludingSelf();
return SubGraphOf(graph, includedElements);
}
public static HashSet DeleteCodeElementAndAllChildren(this CodeGraph graph, string codeElementIds)
{
var element = graph.TryGetCodeElement(codeElementIds);
if (element is null)
{
return [];
}
var elementIdsToRemove = element.GetChildrenIncludingSelf().ToHashSet();
graph.RemoveCodeElements(elementIdsToRemove);
return elementIdsToRemove;
}
}