protected bool ApplyChangesInternal(
            IGraphContext graphContext,
            IDependency updatedDependency,
            GraphNode dependencyGraphNode,
            ImmutableArray <IDependency> updatedChildren,
            string nodeProjectPath,
            ITargetedDependenciesSnapshot targetedSnapshot)
        {
            IEnumerable <DependencyNodeInfo> existingChildrenInfo = GetExistingChildren();
            IEnumerable <DependencyNodeInfo> updatedChildrenInfo  = updatedChildren.Select(DependencyNodeInfo.FromDependency);

            var diff = new SetDiff <DependencyNodeInfo>(existingChildrenInfo, updatedChildrenInfo);

            bool anyChanges = false;

            foreach (DependencyNodeInfo nodeToRemove in diff.Removed)
            {
                anyChanges = true;
                Builder.RemoveGraphNode(graphContext, nodeProjectPath, nodeToRemove.Id, dependencyGraphNode);
            }

            foreach (DependencyNodeInfo nodeToAdd in diff.Added)
            {
                if (!targetedSnapshot.DependenciesWorld.TryGetValue(nodeToAdd.Id, out IDependency dependency) ||
                    !dependency.Visible)
                {
                    continue;
                }

                anyChanges = true;
                Builder.AddGraphNode(
                    graphContext,
                    nodeProjectPath,
                    dependencyGraphNode,
                    dependency.ToViewModel(targetedSnapshot));
            }

            // Update the node info saved on the 'inputNode'
            dependencyGraphNode.SetValue(DependenciesGraphSchema.DependencyIdProperty, updatedDependency.Id);
            dependencyGraphNode.SetValue(DependenciesGraphSchema.ResolvedProperty, updatedDependency.Resolved);

            return(anyChanges);

            IEnumerable <DependencyNodeInfo> GetExistingChildren()
            {
                foreach (GraphNode childNode in dependencyGraphNode.FindDescendants())
                {
                    string id = childNode.GetValue <string>(DependenciesGraphSchema.DependencyIdProperty);

                    if (!string.IsNullOrEmpty(id))
                    {
                        bool resolved = childNode.GetValue <bool>(DependenciesGraphSchema.ResolvedProperty);

                        yield return(new DependencyNodeInfo(id, childNode.Label, resolved));
                    }
                }
            }
        }
        public void ProducesCorrectDiff(int[] before, int[] after, int[] added, int[] removed)
        {
            var diff = new SetDiff <int>(before, after);

            var actualAdded   = new HashSet <int>(diff.Added);
            var actualRemoved = new HashSet <int>(diff.Removed);

            Assert.True(actualAdded.SetEquals(added));
            Assert.True(actualRemoved.SetEquals(removed));
        }
        private void ProcessSharedProjectsUpdates(
            IProjectSharedFoldersSnapshot sharedFolders,
            TargetFramework targetFramework,
            DependenciesChangesBuilder changesBuilder)
        {
            Requires.NotNull(sharedFolders, nameof(sharedFolders));
            Requires.NotNull(targetFramework, nameof(targetFramework));
            Requires.NotNull(changesBuilder, nameof(changesBuilder));

            DependenciesSnapshot snapshot = _dependenciesSnapshotProvider.CurrentSnapshot;

            if (!snapshot.DependenciesByTargetFramework.TryGetValue(targetFramework, out TargetedDependenciesSnapshot? targetedSnapshot))
            {
                return;
            }

            IEnumerable <string> sharedFolderProjectPaths = sharedFolders.Value.Select(sf => sf.ProjectPath);
            var currentSharedImportNodePaths = targetedSnapshot.Dependencies
                                               .Where(pair => pair.Flags.Contains(DependencyTreeFlags.SharedProjectDependency))
                                               .Select(pair => pair.FilePath !)
                                               .ToList();

            var diff = new SetDiff <string>(currentSharedImportNodePaths, sharedFolderProjectPaths);

            // process added nodes
            foreach (string addedSharedImportPath in diff.Added)
            {
                IDependencyModel added = new SharedProjectDependencyModel(
                    addedSharedImportPath,
                    addedSharedImportPath,
                    isResolved: true,
                    isImplicit: false,
                    properties: ImmutableStringDictionary <string> .EmptyOrdinal);
                changesBuilder.Added(targetFramework, added);
            }

            // process removed nodes
            foreach (string removedSharedImportPath in diff.Removed)
            {
                bool exists = currentSharedImportNodePaths.Any(nodePath => PathHelper.IsSamePath(nodePath, removedSharedImportPath));

                if (exists)
                {
                    changesBuilder.Removed(
                        targetFramework,
                        ProjectRuleHandler.ProviderTypeString,
                        dependencyId: removedSharedImportPath);
                }
            }
        }
        public DependenciesSnapshot SetTargets(
            ImmutableArray <ITargetFramework> targetFrameworks,
            ITargetFramework activeTargetFramework)
        {
            bool activeChanged = !activeTargetFramework.Equals(ActiveTargetFramework);

            ImmutableDictionary <ITargetFramework, TargetedDependenciesSnapshot> map = DependenciesByTargetFramework;

            var diff = new SetDiff <ITargetFramework>(map.Keys, targetFrameworks);

            map = map.RemoveRange(diff.Removed);
            map = map.AddRange(
                diff.Added.Select(
                    added => new KeyValuePair <ITargetFramework, TargetedDependenciesSnapshot>(
                        added,
                        TargetedDependenciesSnapshot.CreateEmpty(added, null))));

            if (activeChanged || !ReferenceEquals(map, DependenciesByTargetFramework))
            {
                return(new DependenciesSnapshot(activeTargetFramework, map));
            }

            return(this);
        }