public static List FindDiff()

in src/dotnet/APIView/APIViewWeb/Helpers/CodeFileHelpers.cs [430:507]


        public static List<ReviewLine> FindDiff(List<ReviewLine> activeLines, List<ReviewLine> diffLines)
        {
            List<ReviewLine> resultLines = [];
            Dictionary<string, int> refCountMap = [];

            //Set lines from diff revision as not from active revision
            foreach (var line in diffLines)
            {
                line.IsActiveRevisionLine = false;
            }

            UpdateMissingRelatedLineId(activeLines);
            UpdateMissingRelatedLineId(diffLines);

            var intersectLines = diffLines.Intersect(activeLines);
            var interleavedLines = activeLines.InterleavedUnion(diffLines);

            foreach (var line in interleavedLines)
            {
                if (line.IsDocumentation || line.Processed || (!line.IsActiveRevisionLine && line.IsSkippedFromDiff()))
                    continue;


                // Current node is not in both revisions. Mark current node as added or removed and then go to next sibling.
                // If a node is diff then no need to check it's children as they will be marked as diff as well.
                if (!intersectLines.Contains(line))
                {
                    //Recursively mark line as added or removed if line is not skipped from diff
                    if (!line.IsSkippedFromDiff())
                    {
                        MarkTreeNodeAsModified(line, line.IsActiveRevisionLine ? DiffKind.Added : DiffKind.Removed);
                    }

                    //Check if diff revision has a line at same level with same Line Id. This is to handle where a API was removed and added back in different order.
                    // This will also ensure added and modified lines are visible next to each other in the review.
                    var relatedLine = line.IsActiveRevisionLine ? diffLines.FirstOrDefault(l => !string.IsNullOrEmpty(l.LineId) && l.LineId == line.LineId) :
                        activeLines.FirstOrDefault(l => !string.IsNullOrEmpty(l.LineId) && l.LineId == line.LineId);
                    if (relatedLine != null)
                    {
                        relatedLine.Processed = true;
                        if (!relatedLine.IsSkippedFromDiff())
                        {
                            MarkTreeNodeAsModified(relatedLine, relatedLine.IsActiveRevisionLine ? DiffKind.Added : DiffKind.Removed);
                            //Identify the tokens within modified lines and highlight them in the UI
                            FindModifiedTokens(line, relatedLine);
                        }                        
                    }

                    if (relatedLine != null)
                    {
                        // First add removed line and then added line
                        resultLines.Add(line.IsActiveRevisionLine ? relatedLine : line);
                        resultLines.Add(line.IsActiveRevisionLine ? line : relatedLine);
                    }
                    else
                    {
                        resultLines.Add(line);
                    }
                    continue;
                }

                var activeLine = activeLines.FirstOrDefault(l => l.LineId == line.LineId && l.Processed == false && l.Equals(line));
                if (activeLine == null)
                    activeLine = line;
                //current node is present in both trees. Compare child nodes recursively
                var diffLine = diffLines.FirstOrDefault(l => l.LineId == line.LineId && l.Processed == false && l.Equals(line));
                var diffLineChildren = diffLine != null ? diffLine.Children : new List<ReviewLine>();
                var resultantSubTree = FindDiff(activeLine.Children, diffLineChildren);
                //Update new resulting subtree as children of current node
                activeLine.Children.Clear();
                activeLine.Children.AddRange(resultantSubTree);
                resultLines.Add(activeLine);
                activeLine.Processed = true;
                if (diffLine != null)
                    diffLine.Processed = true;
            }
            return resultLines;
        }