/// <summary>Search for a component in a project based on its tag name and fully qualified name.</summary> /// <remarks> /// This method makes several assumptions about the nature of components. First, it assumes that a component /// a given name `Name` will be located in a file `Name.razor`. Second, it assumes that the namespace the /// component is present in has the same name as the assembly its corresponding tag helper is loaded from. /// Implicitly, this method inherits any assumptions made by TrySplitNamespaceAndType. /// </remarks> /// <param name="tagHelper">A TagHelperDescriptor to find the corresponding Razor component for.</param> /// <returns>The corresponding DocumentSnapshot if found, null otherwise.</returns> /// <exception cref="ArgumentNullException">Thrown if <paramref name="tagHelper"/> is null.</exception> public override async Task <DocumentSnapshot?> TryLocateComponentAsync(TagHelperDescriptor tagHelper) { if (tagHelper is null) { throw new ArgumentNullException(nameof(tagHelper)); } var typeName = tagHelper.GetTypeNameIdentifier(); var namespaceName = tagHelper.GetTypeNamespace(); if (typeName == null || namespaceName == null) { _logger.LogWarning($"Could not split namespace and type for name {tagHelper.Name}."); return(null); } var lookupSymbolName = RemoveGenericContent(typeName); var projects = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( () => _projectSnapshotManager.Projects.ToArray(), CancellationToken.None).ConfigureAwait(false); foreach (var project in projects) { foreach (var path in project.DocumentFilePaths) { // Get document and code document var documentSnapshot = project.GetDocument(path); // Rule out if not Razor component with correct name if (!IsPathCandidateForComponent(documentSnapshot, lookupSymbolName)) { continue; } var razorCodeDocument = await documentSnapshot.GetGeneratedOutputAsync().ConfigureAwait(false); if (razorCodeDocument is null) { continue; } // Make sure we have the right namespace of the fully qualified name if (!ComponentNamespaceMatchesFullyQualifiedName(razorCodeDocument, namespaceName)) { continue; } return(documentSnapshot); } } return(null); }