private void VerifyContentLinks(HtmlString html, string path, ContentLinkType contentType, ILookup <string, string> lookup) { var xmlDoc = new XmlDocument(); var doc = xmlDoc.CreateDocumentFragment(); doc.InnerXml = html.ToString(); var childNodes = doc.ChildNodes.Cast <XmlNode>().Where(n => !(n is XmlWhitespace)).ToList(); var expectedList = lookup[path]; Assert.Equal(expectedList.Count(), childNodes.Count); foreach (var pair in childNodes.Zip(expectedList, Tuple.Create)) { var node = pair.Item1; var expected = pair.Item2; if (contentType == ContentLinkType.Javascript) { Assert.Equal("script", node.Name); Assert.Equal(2, node.Attributes.Count); Assert.Equal("text/javascript", node.Attributes.GetNamedItem("type").Value); Assert.Equal(expected, node.Attributes.GetNamedItem("src").Value); } else { Assert.Equal("link", node.Name); Assert.Equal(2, node.Attributes.Count); Assert.Equal("stylesheet", node.Attributes.GetNamedItem("rel").Value); Assert.Equal(expected, node.Attributes.GetNamedItem("href").Value); } } }
// This constructor exists for better factorization of code in AssetDependencies. // It should not be turned into public as AssetItem is not valid. internal AssetLink(IContentReference reference, ContentLinkType type) { if (reference == null) throw new ArgumentNullException("reference"); Item = null; this.type = type; this.reference = reference; }
/// <summary> /// Create an asset dependency of type <paramref name="type"/> and pointing to <paramref name="item"/> /// </summary> /// <param name="item">The item the dependency is pointing to</param> /// <param name="type">The type of the dependency between the items</param> public AssetLink(AssetItem item, ContentLinkType type) { if (item == null) throw new ArgumentNullException("item"); Item = item; this.type = type; reference = item.ToReference(); }
// This constructor exists for better factorization of code in AssetDependencies. // It should not be turned into public as AssetItem is not valid. internal AssetLink(IReference reference, ContentLinkType type) { if (reference == null) { throw new ArgumentNullException("reference"); } Item = null; this.type = type; this.reference = reference; }
/// <summary> /// Create an asset dependency of type <paramref name="type"/> and pointing to <paramref name="item"/> /// </summary> /// <param name="item">The item the dependency is pointing to</param> /// <param name="type">The type of the dependency between the items</param> public AssetLink(AssetItem item, ContentLinkType type) { if (item == null) { throw new ArgumentNullException("item"); } Item = item; this.type = type; reference = item.ToReference(); }
/// <summary> /// Create an asset dependency of a specified <paramref name="type"/> pointing to an asset <paramref name="item"/>. /// </summary> /// <param name="item">The item the dependency is pointing to.</param> /// <param name="type">The type of the dependency between the items.</param> public AssetLink(AssetItem item, ContentLinkType type) { if (item is null) { throw new ArgumentNullException(nameof(item)); } Item = item; Type = type; assetReference = item.ToReference(); }
/// <inheritdoc /> public AssetDependencies ComputeDependencies(AssetId assetId, AssetDependencySearchOptions dependenciesOptions = AssetDependencySearchOptions.All, ContentLinkType linkTypes = ContentLinkType.Reference, HashSet <AssetId> visited = null) { bool recursive = dependenciesOptions.HasFlag(AssetDependencySearchOptions.Recursive); if (visited is null && recursive) { visited = new HashSet <AssetId>(); } //var clock = Stopwatch.StartNew(); lock (Initialize()) { if (!Dependencies.TryGetValue(assetId, out AssetDependencies dependencies)) { return(null); } dependencies = new AssetDependencies(dependencies.Item); int inCount = 0, outCount = 0; if (dependenciesOptions.HasFlag(AssetDependencySearchOptions.In)) { CollectInputReferences(dependencies, assetId, visited, recursive, linkTypes, ref inCount); } if (dependenciesOptions.HasFlag(AssetDependencySearchOptions.Out)) { visited?.Clear(); CollectOutputReferences(dependencies, assetId, visited, recursive, linkTypes, ref outCount); } //Console.WriteLine("Time to compute dependencies: {0}ms in: {1} out:{2}", clock.ElapsedMilliseconds, inCount, outCount); return(dependencies); } }
/// <inheritdoc /> public List <AssetItem> FindAssetInheritances(AssetId assetId, AssetInheritanceSearchOptions searchOptions = AssetInheritanceSearchOptions.All) { var list = new List <AssetItem>(); lock (Initialize()) { ContentLinkType searchType = 0; if ((searchOptions & AssetInheritanceSearchOptions.Base) != 0) { searchType |= ContentLinkType.Inheritance; } if ((searchOptions & AssetInheritanceSearchOptions.Composition) != 0) { searchType |= ContentLinkType.CompositionInheritance; } AssetDependencies dependencies; if (Dependencies.TryGetValue(assetId, out dependencies)) { list.AddRange(dependencies.LinksOut.Where(p => (p.Type & searchType) != 0).Select(p => p.Item.Clone(true))); } } return(list); }
/// <summary> /// Adds a link going to the provided element. /// </summary> /// <param name="toItem">The element the link is going to</param> /// <param name="contentLinkType">The type of link</param> /// <param name="cloneAssetItem">Indicate if the <see cref="AssetItem"/> should be cloned or not</param> /// <exception cref="ArgumentException">A link to this element already exists</exception> public void AddLinkOut(AssetItem toItem, ContentLinkType contentLinkType, bool cloneAssetItem) { AddLink(ref children, new AssetLink(toItem, contentLinkType), cloneAssetItem); }
/// <summary> /// Adds a broken link out. /// </summary> /// <param name="reference">the reference to the missing element</param> /// <param name="contentLinkType">The type of link</param> /// <exception cref="ArgumentException">A broken link to this element already exists</exception> public void AddBrokenLinkOut(IReference reference, ContentLinkType contentLinkType) { AddLink(ref missingChildren, new AssetLink(reference, contentLinkType)); }
private AssetLink RemoveLink(ref Dictionary<Guid, AssetLink> dictionary, Guid id, ContentLinkType type) { if (dictionary == null || !dictionary.ContainsKey(id)) throw new ArgumentException("There is currently no link between elements '{0}' and '{1}'".ToFormat(item.Id, id)); var oldLink = dictionary[id]; var newLink = oldLink; newLink.Type &= ~type; oldLink.Type &= type; if(newLink.Type == 0) dictionary.Remove(id); if (dictionary.Count == 0) dictionary = null; return oldLink; }
/// <summary> /// Adds a link going into the element. /// </summary> /// <param name="fromItem">The element the link is coming from</param> /// <param name="contentLinkType">The type of link</param> /// <exception cref="ArgumentException">A link from this element already exists</exception> public void AddLinkIn(AssetItem fromItem, ContentLinkType contentLinkType) { AddLink(ref parents, new AssetLink(fromItem, contentLinkType)); }
/// <summary> /// Adds a link going to the provided element. /// </summary> /// <param name="toItem">The element the link is going to</param> /// <param name="contentLinkType">The type of link</param> /// <exception cref="ArgumentException">A link to this element already exists</exception> public void AddLinkOut(AssetItem toItem, ContentLinkType contentLinkType) { AddLink(ref children, new AssetLink(toItem, contentLinkType)); }
private void CollectInputReferences(AssetDependencies dependencyRoot, AssetId assetId, HashSet <AssetId> visited, bool recursive, ContentLinkType linkTypes, ref int count) { if (visited != null) { if (visited.Contains(assetId)) { return; } visited.Add(assetId); } count++; AssetDependencies dependencies; Dependencies.TryGetValue(assetId, out dependencies); if (dependencies != null) { foreach (var pair in dependencies.LinksIn) { if ((linkTypes & pair.Type) != 0) { dependencyRoot.AddLinkIn(pair); if (visited != null && recursive) { CollectInputReferences(dependencyRoot, pair.Item.Id, visited, true, linkTypes, ref count); } } } } }
/// <summary> /// Computes the dependencies for the specified asset. /// </summary> /// <param name="assetId">The asset id.</param> /// <param name="dependenciesOptions">The dependencies options.</param> /// <param name="linkTypes">The type of links to visit while computing the dependencies</param> /// <param name="visited">The list of element already visited.</param> /// <returns>The dependencies, or null if the object is not tracked.</returns> public AssetDependencies ComputeDependencies(AssetId assetId, AssetDependencySearchOptions dependenciesOptions = AssetDependencySearchOptions.All, ContentLinkType linkTypes = ContentLinkType.All, HashSet<AssetId> visited = null) { bool recursive = (dependenciesOptions & AssetDependencySearchOptions.Recursive) != 0; if (visited == null && recursive) visited = new HashSet<AssetId>(); //var clock = Stopwatch.StartNew(); lock (Initialize()) { AssetDependencies dependencies; if (!Dependencies.TryGetValue(assetId, out dependencies)) return null; dependencies = new AssetDependencies(dependencies.Item); int inCount = 0, outCount = 0; if ((dependenciesOptions & AssetDependencySearchOptions.In) != 0) { CollectInputReferences(dependencies, assetId, visited, recursive, linkTypes, ref inCount); } if ((dependenciesOptions & AssetDependencySearchOptions.Out) != 0) { visited?.Clear(); CollectOutputReferences(dependencies, assetId, visited, recursive, linkTypes, ref outCount); } //Console.WriteLine("Time to compute dependencies: {0}ms in: {1} out:{2}", clock.ElapsedMilliseconds, inCount, outCount); return dependencies; } }
private void CollectInputReferences(AssetDependencies dependencyRoot, AssetId assetId, HashSet<AssetId> visited, bool recursive, ContentLinkType linkTypes, ref int count) { if (visited != null) { if (visited.Contains(assetId)) return; visited.Add(assetId); } count++; AssetDependencies dependencies; Dependencies.TryGetValue(assetId, out dependencies); if (dependencies != null) { foreach (var pair in dependencies.LinksIn) { if ((linkTypes & pair.Type) != 0) { dependencyRoot.AddLinkIn(pair); if (visited != null && recursive) { CollectInputReferences(dependencyRoot, pair.Item.Id, visited, true, linkTypes, ref count); } } } } }
/// <summary> /// Adds a link going into the element. /// </summary> /// <param name="fromItem">The element the link is coming from</param> /// <param name="contentLinkType">The type of link</param> /// <param name="cloneAssetItem">Indicate if the <see cref="AssetItem"/> should be cloned or not</param> /// <exception cref="ArgumentException">A link from this element already exists</exception> public void AddLinkIn(AssetItem fromItem, ContentLinkType contentLinkType, bool cloneAssetItem) { AddLink(ref parents, new AssetLink(fromItem, contentLinkType), cloneAssetItem); }
private void CollectOutputReferences(AssetDependencies dependencyRoot, AssetId assetId, HashSet<AssetId> visited, bool recursive, ContentLinkType linkTypes, ref int count) { if (visited != null) { if (visited.Contains(assetId)) return; visited.Add(assetId); } count++; var dependencies = CalculateDependencies(assetId); if (dependencies == null) return; // Add missing references foreach (var missingRef in dependencies.BrokenLinksOut) { dependencyRoot.AddBrokenLinkOut(missingRef); } // Add output references foreach (var child in dependencies.LinksOut) { if ((linkTypes & child.Type) != 0) { dependencyRoot.AddLinkOut(child); if (visited != null && recursive) { CollectOutputReferences(dependencyRoot, child.Item.Id, visited, true, linkTypes, ref count); } } } }
/// <summary> /// Computes the dependencies for the specified asset. /// </summary> /// <param name="assetItem">The asset item.</param> /// <param name="dependenciesOptions">The dependencies options.</param> /// <param name="linkTypes">The type of links to visit while computing the dependencies</param> /// <param name="visited">The list of element already visited.</param> /// <returns>The dependencies.</returns> public AssetDependencies ComputeDependencies(AssetItem assetItem, AssetDependencySearchOptions dependenciesOptions = AssetDependencySearchOptions.All, ContentLinkType linkTypes = ContentLinkType.All, HashSet <Guid> visited = null) { if (assetItem == null) { throw new ArgumentNullException(nameof(assetItem)); } bool recursive = (dependenciesOptions & AssetDependencySearchOptions.Recursive) != 0; if (visited == null && recursive) { visited = new HashSet <Guid>(); } //var clock = Stopwatch.StartNew(); lock (Initialize()) { var dependencies = new AssetDependencies(assetItem); int inCount = 0, outCount = 0; if ((dependenciesOptions & AssetDependencySearchOptions.In) != 0) { CollectInputReferences(dependencies, assetItem, visited, recursive, linkTypes, ref inCount); } if ((dependenciesOptions & AssetDependencySearchOptions.Out) != 0) { visited?.Clear(); CollectOutputReferences(dependencies, assetItem, visited, recursive, linkTypes, ref outCount); } //Console.WriteLine("Time to compute dependencies: {0}ms in: {1} out:{2}", clock.ElapsedMilliseconds, inCount, outCount); return(dependencies); } }
private AssetLink RemoveLink(ref Dictionary <AssetId, AssetLink> dictionary, AssetId id, ContentLinkType type) { if (dictionary == null || !dictionary.ContainsKey(id)) { throw new ArgumentException("There is currently no link between elements '{0}' and '{1}'".ToFormat(item.Id, id)); } var oldLink = dictionary[id]; var newLink = oldLink; newLink.Type &= ~type; oldLink.Type &= type; if (newLink.Type == 0) { dictionary.Remove(id); } if (dictionary.Count == 0) { dictionary = null; } return(oldLink); }
private void VerifyContentLinks(IHtmlContent html, string path, ContentLinkType contentType, ILookup<string, string> lookup) { var xmlDoc = new XmlDocument(); var doc = xmlDoc.CreateDocumentFragment(); using (var writer = new StringWriter()) { html.WriteTo(writer, HtmlEncoder.Default); doc.InnerXml = writer.ToString(); } var childNodes = doc.ChildNodes.Cast<XmlNode>().Where(n => !(n is XmlWhitespace)).ToList(); var expectedList = lookup[path]; Assert.Equal(expectedList.Count(), childNodes.Count); foreach (var pair in childNodes.Zip(expectedList, Tuple.Create)) { var node = pair.Item1; var expected = pair.Item2; if (contentType == ContentLinkType.Javascript) { Assert.Equal("script", node.Name); Assert.Equal(2, node.Attributes.Count); Assert.Equal("text/javascript", node.Attributes.GetNamedItem("type").Value); Assert.Equal(expected, node.Attributes.GetNamedItem("src").Value); } else { Assert.Equal("link", node.Name); Assert.Equal(2, node.Attributes.Count); Assert.Equal("stylesheet", node.Attributes.GetNamedItem("rel").Value); Assert.Equal(expected, node.Attributes.GetNamedItem("href").Value); } } }
// // This constructor exists for better factorization of code in AssetDependencies. // It should not be turned into public as AssetItem is not valid. // internal AssetLink(IReference reference, ContentLinkType type) { Item = null; Type = type; assetReference = reference ?? throw new ArgumentNullException(nameof(reference)); }
private void CollectOutputReferences(AssetDependencies dependencyRoot, AssetId assetId, HashSet <AssetId> visited, bool recursive, ContentLinkType linkTypes, ref int count) { if (visited != null) { if (visited.Contains(assetId)) { return; } visited.Add(assetId); } count++; var dependencies = CalculateDependencies(assetId); if (dependencies == null) { return; } // Add missing references foreach (var missingRef in dependencies.BrokenLinksOut) { dependencyRoot.AddBrokenLinkOut(missingRef); } // Add output references foreach (var child in dependencies.LinksOut) { if ((linkTypes & child.Type) != 0) { dependencyRoot.AddLinkOut(child); if (visited != null && recursive) { CollectOutputReferences(dependencyRoot, child.Item.Id, visited, true, linkTypes, ref count); } } } }