Exemplo n.º 1
0
        // Internal for testing
        internal static IReadOnlyList <OmniSharpHostDocument> GetHostDocuments(ICollection <ProjectItemInstance> projectItems)
        {
            var hostDocuments = new HashSet <OmniSharpHostDocument>();

            foreach (var item in projectItems)
            {
                if (item.ItemType == RazorGenerateWithTargetPathItemType)
                {
                    var filePath             = Path.Combine(item.Project.Directory, item.EvaluatedInclude);
                    var originalTargetPath   = item.GetMetadataValue(RazorTargetPathMetadataName);
                    var normalizedTargetPath = NormalizeTargetPath(originalTargetPath);
                    var hostDocument         = new OmniSharpHostDocument(filePath, normalizedTargetPath, FileKinds.Legacy);
                    hostDocuments.Add(hostDocument);
                }
                else if (item.ItemType == RazorComponentWithTargetPathItemType)
                {
                    var filePath             = Path.Combine(item.Project.Directory, item.EvaluatedInclude);
                    var originalTargetPath   = item.GetMetadataValue(RazorTargetPathMetadataName);
                    var normalizedTargetPath = NormalizeTargetPath(originalTargetPath);
                    var fileKind             = FileKinds.GetComponentFileKindFromFilePath(filePath);
                    var hostDocument         = new OmniSharpHostDocument(filePath, normalizedTargetPath, fileKind);
                    hostDocuments.Add(hostDocument);
                }
            }

            return(hostDocuments.ToList());
        }
Exemplo n.º 2
0
        protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
        {
            if (FileKinds.IsComponent(codeDocument.GetFileKind()))
            {
                // Hot reload does not apply to components.
                return;
            }

            var @namespace = documentNode.FindPrimaryNamespace();
            var @class     = documentNode.FindPrimaryClass();

            var classIndex = @namespace.Children.IndexOf(@class);

            if (classIndex == -1)
            {
                return;
            }

            var identifierFeature = Engine.Features.OfType <IMetadataIdentifierFeature>().First();
            var identifier        = identifierFeature.GetIdentifier(codeDocument, codeDocument.Source);

            var metadataAttributeNode = new CreateNewOnMetadataUpdateAttributeIntermediateNode();

            // Metadata attributes need to be inserted right before the class declaration.
            @namespace.Children.Insert(classIndex, metadataAttributeNode);

            // [global:Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemMetadataAttribute("Identifier", "/Views/Home/Index.cshtml")]
            @namespace.Children.Insert(classIndex, new RazorCompiledItemMetadataAttributeIntermediateNode
            {
                Key   = "Identifier",
                Value = identifier,
            });
        }
        public async Task AddEditsForCodeDocumentAsync(List <WorkspaceEditDocumentChange> documentChanges, IReadOnlyList <TagHelperDescriptor> originTagHelpers, string newName, DocumentSnapshot documentSnapshot, CancellationToken cancellationToken)
        {
            if (documentSnapshot is null)
            {
                return;
            }

            var codeDocument = await documentSnapshot.GetGeneratedOutputAsync().ConfigureAwait(false);

            if (codeDocument.IsUnsupported())
            {
                return;
            }

            if (!FileKinds.IsComponent(codeDocument.GetFileKind()))
            {
                return;
            }

            var uri = new UriBuilder
            {
                Path   = documentSnapshot.FilePath,
                Host   = string.Empty,
                Scheme = Uri.UriSchemeFile,
            }.Uri;

            AddEditsForCodeDocument(documentChanges, originTagHelpers, newName, uri, codeDocument);
        }
Exemplo n.º 4
0
        protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
        {
            var @class = documentNode.FindPrimaryClass();

            if (@class == null)
            {
                return;
            }

            var directiveNodes = new List <IntermediateNodeReference>();

            directiveNodes.AddRange(documentNode.FindDirectiveReferences(FunctionsDirective.Directive));

            if (FileKinds.IsComponent(codeDocument.GetFileKind()))
            {
                directiveNodes.AddRange(documentNode.FindDirectiveReferences(ComponentCodeDirective.Directive));
            }

            // Now we have all the directive nodes, we want to add them to the end of the class node in document order.
            var orderedDirectives = directiveNodes.OrderBy(n => n.Node.Source?.AbsoluteIndex);

            foreach (var directiveReference in orderedDirectives)
            {
                var node = directiveReference.Node;
                for (var i = 0; i < node.Children.Count; i++)
                {
                    @class.Children.Add(node.Children[i]);
                }

                // We don't want to keep the original directive node around anymore.
                // Otherwise this can cause unintended side effects in the subsequent passes.
                directiveReference.Remove();
            }
        }
Exemplo n.º 5
0
 /// <summary>
 /// Intializes a new instance of a <see cref="FileProviderRazorProjectItem"/>.
 /// </summary>
 /// <param name="fileInfo">The file info.</param>
 /// <param name="basePath">The base path.</param>
 /// <param name="filePath">The file path.</param>
 /// <param name="root">The root.</param>
 /// <param name="fileKind">The kind of file.</param>
 public FileProviderRazorProjectItem(IFileInfo fileInfo, string basePath, string filePath, string root, string fileKind)
 {
     FileInfo = fileInfo;
     BasePath = basePath;
     FilePath = filePath;
     FileKind = fileKind ?? FileKinds.GetFileKindFromFilePath(filePath);
     _root    = root;
 }
Exemplo n.º 6
0
        public override IReadOnlyList <RazorCompletionItem> GetCompletionItems(RazorSyntaxTree syntaxTree, TagHelperDocumentContext tagHelperDocumentContext, SourceSpan location)
        {
            if (syntaxTree is null)
            {
                throw new ArgumentNullException(nameof(syntaxTree));
            }

            if (tagHelperDocumentContext is null)
            {
                throw new ArgumentNullException(nameof(tagHelperDocumentContext));
            }

            if (!FileKinds.IsComponent(syntaxTree.Options.FileKind))
            {
                // Directive attributes are only supported in components
                return(NoDirectiveAttributeCompletionItems);
            }

            var change = new SourceChange(location, string.Empty);
            var owner  = syntaxTree.Root.LocateOwner(change);

            if (owner == null)
            {
                return(NoDirectiveAttributeCompletionItems);
            }

            if (!TryGetAttributeInfo(owner, out _, out var attributeName, out var attributeNameLocation, out _, out _))
            {
                // Either we're not in an attribute or the attribute is so malformed that we can't provide proper completions.
                return(NoDirectiveAttributeCompletionItems);
            }

            if (!attributeNameLocation.IntersectsWith(location.AbsoluteIndex))
            {
                // We're trying to retrieve completions on a portion of the name that is not supported (such as a parameter).
                return(NoDirectiveAttributeCompletionItems);
            }

            if (!TryGetElementInfo(owner.Parent.Parent, out var containingTagName, out var attributes))
            {
                // This should never be the case, it means that we're operating on an attribute that doesn't have a tag.
                return(NoDirectiveAttributeCompletionItems);
            }

            // At this point we've determined that completions have been requested for the name portion of the selected attribute.

            var completionItems = GetAttributeCompletions(attributeName, containingTagName, attributes, tagHelperDocumentContext);

            // We don't provide Directive Attribute completions when we're in the middle of
            // another unrelated (doesn't start with @) partially completed attribute.
            // <svg xml:| ></svg> (attributeName = "xml:") should not get any directive attribute completions.
            if (string.IsNullOrWhiteSpace(attributeName) || attributeName.StartsWith("@"))
            {
                return(completionItems);
            }

            return(NoDirectiveAttributeCompletionItems);
        }
Exemplo n.º 7
0
 public RemoteProjectItem(string filePath, string physicalPath, string fileKind)
 {
     FilePath             = filePath;
     PhysicalPath         = physicalPath;
     FileKind             = fileKind ?? FileKinds.GetFileKindFromFilePath(FilePath);
     RelativePhysicalPath = FilePath.StartsWith("/", StringComparison.Ordinal)
         ? FilePath.Substring(1)
         : FilePath;
 }
        // A Razor file has been processed, this portion is responsible for the decision of whether we need to create or update
        // the Razor documents background C# representation.
        public override void DocumentProcessed(OmniSharpDocumentSnapshot document)
        {
            if (document is null)
            {
                throw new ArgumentNullException(nameof(document));
            }

            _projectSnapshotManagerDispatcher.AssertDispatcherThread();

            lock (_workspaceChangedLock)
            {
                if (FileKinds.IsComponentImport(document.FileKind))
                {
                    // Razor component imports don't have any C# to generate anyways, don't do the work. This doesn't capture _ViewImports.cshtml because we never
                    // associated a FileKind with those files.
                    return;
                }

                var openVirtualFilePath = document.FilePath + ActiveVirtualDocumentSuffix;
                var openDocument        = _workspace.GetDocument(openVirtualFilePath);
                if (openDocument != null)
                {
                    // This document is open in the editor, no reason for us to populate anything in the workspace the editor will do that.
                    return;
                }

                var backgroundVirtualFilePath = document.FilePath + BackgroundVirtualDocumentSuffix;
                var currentDocument           = _workspace.GetDocument(backgroundVirtualFilePath);
                if (currentDocument == null)
                {
                    // Background document doesn't exist, we need to create it

                    var roslynProject = GetRoslynProject(document.Project);
                    if (roslynProject == null)
                    {
                        // There's no Roslyn project associated with the Razor document.
                        _logger.LogTrace($"Could not find a Roslyn project for Razor virtual document '{backgroundVirtualFilePath}'.");
                        return;
                    }

                    var documentId      = DocumentId.CreateNewId(roslynProject.Id);
                    var name            = Path.GetFileName(backgroundVirtualFilePath);
                    var emptyTextLoader = new EmptyTextLoader(backgroundVirtualFilePath);
                    var documentInfo    = DocumentInfo.Create(documentId, name, filePath: backgroundVirtualFilePath, loader: emptyTextLoader);
                    _workspace.AddDocument(documentInfo);
                    currentDocument = _workspace.GetDocument(backgroundVirtualFilePath);

                    Debug.Assert(currentDocument != null, "We just added the document, it should definitely be there.");
                }

                // Update document content

                var sourceText = document.GetGeneratedCodeSourceText();
                _workspace.OnDocumentChanged(currentDocument.Id, sourceText);
            }
        }
        // A Razor file has been processed, this portion is responsible for the decision of whether we need to create or update
        // the Razor documents background C# representation.
        public override void DocumentProcessed(OmniSharpDocumentSnapshot document)
        {
            if (document is null)
            {
                throw new ArgumentNullException(nameof(document));
            }

            _foregroundDispatcher.AssertForegroundThread();

            if (!FileKinds.IsComponent(document.FileKind) || FileKinds.IsComponentImport(document.FileKind))
            {
                // Today we only support publishing Razor component files to the workspace. We could choose to publish more but we're being
                // purposefuly restrictive.
                return;
            }

            var openVirtualFilePath = document.FilePath + ActiveVirtualDocumentSuffix;
            var openDocument        = _workspace.GetDocument(openVirtualFilePath);

            if (openDocument != null)
            {
                // This document is open in the editor, no reason for us to populate anything in the workspace the editor will do that.
                return;
            }

            var backgroundVirtualFilePath = document.FilePath + BackgroundVirtualDocumentSuffix;
            var currentDocument           = _workspace.GetDocument(backgroundVirtualFilePath);

            if (currentDocument == null)
            {
                // Background document doesn't exist, we need to create it

                var roslynProject = GetRoslynProject(document.Project);
                if (roslynProject == null)
                {
                    // There's no Roslyn project associated with the Razor document.
                    _logger.LogTrace($"Could not find a Roslyn project for Razor virtual document '{backgroundVirtualFilePath}'.");
                    return;
                }

                var documentId      = DocumentId.CreateNewId(roslynProject.Id);
                var name            = Path.GetFileName(backgroundVirtualFilePath);
                var emptyTextLoader = new EmptyTextLoader(backgroundVirtualFilePath);
                var documentInfo    = DocumentInfo.Create(documentId, name, filePath: backgroundVirtualFilePath, loader: emptyTextLoader);
                _workspace.AddDocument(documentInfo);
                currentDocument = _workspace.GetDocument(backgroundVirtualFilePath);

                Debug.Assert(currentDocument != null, "We just added the document, it should definitely be there.");
            }

            // Update document content

            var sourceText = document.GetGeneratedCodeSourceText();

            _workspace.OnDocumentChanged(currentDocument.Id, sourceText);
        }
        public override async Task <WorkspaceEdit> ResolveAsync(JObject data, CancellationToken cancellationToken)
        {
            if (data is null)
            {
                return(null);
            }

            var actionParams = data.ToObject <AddUsingsCodeActionParams>();

            if (actionParams is null)
            {
                return(null);
            }

            var path = actionParams.Uri.GetAbsoluteOrUNCPath();

            var document = await Task.Factory.StartNew(() =>
            {
                _documentResolver.TryResolveDocument(path, out var documentSnapshot);
                return(documentSnapshot);
            }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false);

            if (document is null)
            {
                return(null);
            }

            var text = await document.GetTextAsync().ConfigureAwait(false);

            if (text is null)
            {
                return(null);
            }

            var codeDocument = await document.GetGeneratedOutputAsync().ConfigureAwait(false);

            if (codeDocument.IsUnsupported())
            {
                return(null);
            }

            if (!FileKinds.IsComponent(codeDocument.GetFileKind()))
            {
                return(null);
            }

            var codeDocumentIdentifier = new VersionedTextDocumentIdentifier()
            {
                Uri = actionParams.Uri
            };

            return(CreateAddUsingWorkspaceEdit(actionParams.Namespace, codeDocument, codeDocumentIdentifier));
        }
Exemplo n.º 11
0
    public static RazorParserFeatureFlags Create(RazorLanguageVersion version, string fileKind)
    {
        if (fileKind == null)
        {
            throw new ArgumentNullException(nameof(fileKind));
        }

        var allowMinimizedBooleanTagHelperAttributes = false;
        var allowHtmlCommentsInTagHelpers            = false;
        var allowComponentFileKind             = false;
        var allowRazorInAllCodeBlocks          = false;
        var allowUsingVariableDeclarations     = false;
        var allowConditionalDataDashAttributes = false;
        var allowCSharpInMarkupAttributeArea   = true;
        var allowNullableForgivenessOperator   = false;

        if (version.CompareTo(RazorLanguageVersion.Version_2_1) >= 0)
        {
            // Added in 2.1
            allowMinimizedBooleanTagHelperAttributes = true;
            allowHtmlCommentsInTagHelpers            = true;
        }

        if (version.CompareTo(RazorLanguageVersion.Version_3_0) >= 0)
        {
            // Added in 3.0
            allowComponentFileKind           = true;
            allowRazorInAllCodeBlocks        = true;
            allowUsingVariableDeclarations   = true;
            allowNullableForgivenessOperator = true;
        }

        if (FileKinds.IsComponent(fileKind))
        {
            allowConditionalDataDashAttributes = true;
            allowCSharpInMarkupAttributeArea   = false;
        }

        if (version.CompareTo(RazorLanguageVersion.Experimental) >= 0)
        {
            allowConditionalDataDashAttributes = true;
        }

        return(new DefaultRazorParserFeatureFlags(
                   allowMinimizedBooleanTagHelperAttributes,
                   allowHtmlCommentsInTagHelpers,
                   allowComponentFileKind,
                   allowRazorInAllCodeBlocks,
                   allowUsingVariableDeclarations,
                   allowConditionalDataDashAttributes,
                   allowCSharpInMarkupAttributeArea,
                   allowNullableForgivenessOperator));
    }
Exemplo n.º 12
0
        private static (IReadOnlyList <RazorInputItem> razorFiles, IReadOnlyList <RazorInputItem> cshtmlFiles) GetRazorInputs(GeneratorExecutionContext context)
        {
            List <RazorInputItem> razorFiles  = null;
            List <RazorInputItem> cshtmlFiles = null;

            foreach (var item in context.AdditionalFiles)
            {
                var path        = item.Path;
                var isComponent = path.EndsWith(".razor", StringComparison.OrdinalIgnoreCase);
                var isRazorView = path.EndsWith(".cshtml", StringComparison.OrdinalIgnoreCase);

                if (!isComponent && !isRazorView)
                {
                    continue;
                }

                var options = context.AnalyzerConfigOptions.GetOptions(item);
                if (!options.TryGetValue("build_metadata.AdditionalFiles.TargetPath", out var relativePath))
                {
                    throw new InvalidOperationException($"TargetPath is not specified for additional file '{item.Path}.");
                }

                options.TryGetValue("build_metadata.AdditionalFiles.CssScope", out var cssScope);

                string generatedDeclarationPath = null;

                options.TryGetValue("build_metadata.AdditionalFiles.GeneratedOutputFullPath", out var generatedOutputPath);
                if (isComponent)
                {
                    options.TryGetValue("build_metadata.AdditionalFiles.GeneratedDeclarationFullPath", out generatedDeclarationPath);
                }

                var fileKind = isComponent ? FileKinds.GetComponentFileKindFromFilePath(item.Path) : FileKinds.Legacy;

                var inputItem = new RazorInputItem(item, relativePath, fileKind, generatedOutputPath, generatedDeclarationPath, cssScope);

                if (isComponent)
                {
                    razorFiles ??= new();
                    razorFiles.Add(inputItem);
                }
                else
                {
                    cshtmlFiles ??= new();
                    cshtmlFiles.Add(inputItem);
                }
            }

            return(
                (IReadOnlyList <RazorInputItem>)razorFiles ?? Array.Empty <RazorInputItem>(),
                (IReadOnlyList <RazorInputItem>)cshtmlFiles ?? Array.Empty <RazorInputItem>()
                );
        }
    public RazorSyntaxTree Execute(RazorCodeDocument codeDocument, RazorSyntaxTree syntaxTree)
    {
        if (FileKinds.IsComponent(codeDocument.GetFileKind()))
        {
            // Nothing to do here.
            return(syntaxTree);
        }

        var sectionVerifier = new NestedSectionVerifier(syntaxTree);

        return(sectionVerifier.Verify());
    }
Exemplo n.º 14
0
        private static (IReadOnlyList <RazorInputItem> razorFiles, IReadOnlyList <RazorInputItem> cshtmlFiles) GetRazorInputs(GeneratorExecutionContext context)
        {
            List <RazorInputItem> razorFiles  = new();
            List <RazorInputItem> cshtmlFiles = new();

            foreach (var item in context.AdditionalFiles)
            {
                var path        = item.Path;
                var isComponent = path.EndsWith(".razor", StringComparison.OrdinalIgnoreCase);
                var isRazorView = path.EndsWith(".cshtml", StringComparison.OrdinalIgnoreCase);

                if (!isComponent && !isRazorView)
                {
                    continue;
                }

                var options = context.AnalyzerConfigOptions.GetOptions(item);
                if (!options.TryGetValue("build_metadata.AdditionalFiles.TargetPath", out var relativePath))
                {
                    context.ReportDiagnostic(Diagnostic.Create(
                                                 RazorDiagnostics.TargetPathNotProvided,
                                                 Location.None,
                                                 item.Path));
                    continue;
                }

                options.TryGetValue("build_metadata.AdditionalFiles.CssScope", out var cssScope);

                if (!options.TryGetValue("build_metadata.AdditionalFiles.GeneratedOutputFullPath", out var generatedOutputPath))
                {
                    context.ReportDiagnostic(Diagnostic.Create(
                                                 RazorDiagnostics.GeneratedOutputFullPathNotProvided,
                                                 Location.None,
                                                 item.Path));
                }

                var fileKind = isComponent ? FileKinds.GetComponentFileKindFromFilePath(item.Path) : FileKinds.Legacy;

                var inputItem = new RazorInputItem(item, relativePath, fileKind, generatedOutputPath, cssScope);

                if (isComponent)
                {
                    razorFiles.Add(inputItem);
                }
                else
                {
                    cshtmlFiles.Add(inputItem);
                }
            }

            return(razorFiles, cshtmlFiles);
        }
Exemplo n.º 15
0
        private static bool ShouldFilterHtmlDiagnosticBasedOnErrorCode(Diagnostic diagnostic, SourceText sourceText, RazorSyntaxTree syntaxTree)
        {
            if (!diagnostic.Code.HasValue)
            {
                return(false);
            }

            return(diagnostic.Code.Value.String switch
            {
                HtmlErrorCodes.InvalidNestingErrorCode => IsInvalidNestingWarningWithinComponent(diagnostic, sourceText, syntaxTree),
                HtmlErrorCodes.MissingEndTagErrorCode => FileKinds.IsComponent(syntaxTree.Options.FileKind), // Redundant with RZ9980 in Components
                _ => false,
            });
Exemplo n.º 16
0
 public RemoteProjectItem(string filePath, string physicalPath, string fileKind)
 {
     FilePath     = filePath;
     PhysicalPath = physicalPath;
     FileKind     = fileKind ?? FileKinds.GetFileKindFromFilePath(FilePath);
     if (FilePath.StartsWith("/"))
     {
         RelativePhysicalPath = FilePath.Substring(1);
     }
     else
     {
         RelativePhysicalPath = FilePath;
     }
 }
Exemplo n.º 17
0
        public override IReadOnlyList <RazorCompletionItem> GetCompletionItems(RazorSyntaxTree syntaxTree, TagHelperDocumentContext tagHelperDocumentContext, SourceSpan location)
        {
            if (syntaxTree is null)
            {
                throw new ArgumentNullException(nameof(syntaxTree));
            }

            if (tagHelperDocumentContext is null)
            {
                throw new ArgumentNullException(nameof(tagHelperDocumentContext));
            }

            if (!FileKinds.IsComponent(syntaxTree.Options.FileKind))
            {
                // Directive attribute parameters are only supported in components
                return(Array.Empty <RazorCompletionItem>());
            }

            var change = new SourceChange(location, string.Empty);
            var owner  = syntaxTree.Root.LocateOwner(change);

            if (owner == null)
            {
                return(Array.Empty <RazorCompletionItem>());
            }

            if (!TryGetAttributeInfo(owner, out var attributeName, out _, out var parameterName, out var parameterNameLocation))
            {
                // Either we're not in an attribute or the attribute is so malformed that we can't provide proper completions.
                return(Array.Empty <RazorCompletionItem>());
            }

            if (!parameterNameLocation.IntersectsWith(location.AbsoluteIndex))
            {
                // We're trying to retrieve completions on a portion of the name that is not supported (such as the name, i.e., |@bind|:format).
                return(Array.Empty <RazorCompletionItem>());
            }

            if (!TryGetElementInfo(owner.Parent.Parent, out var containingTagName, out var attributes))
            {
                // This should never be the case, it means that we're operating on an attribute that doesn't have a tag.
                return(Array.Empty <RazorCompletionItem>());
            }

            var completions = GetAttributeParameterCompletions(attributeName, parameterName, containingTagName, attributes, tagHelperDocumentContext);

            return(completions);
        }
Exemplo n.º 18
0
        public HostDocument(string filePath, string targetPath, string fileKind)
        {
            if (filePath == null)
            {
                throw new ArgumentNullException(nameof(filePath));
            }

            if (targetPath == null)
            {
                throw new ArgumentNullException(nameof(targetPath));
            }

            FilePath   = filePath;
            TargetPath = targetPath;
            FileKind   = fileKind ?? FileKinds.GetFileKindFromFilePath(filePath);
            GeneratedDocumentContainer = new GeneratedDocumentContainer();
        }
        private static bool ShouldFilterHtmlDiagnosticBasedOnErrorCode(OmniSharpVSDiagnostic diagnostic, SourceText sourceText, RazorSyntaxTree syntaxTree, ILogger logger)
        {
            if (!diagnostic.Code.HasValue)
            {
                return(false);
            }

            return(diagnostic.Code.Value.String switch
            {
                CSSErrorCodes.MissingOpeningBrace => IsCSharpInStyleBlock(diagnostic, sourceText, syntaxTree, logger),
                CSSErrorCodes.MissingSelectorAfterCombinator => IsCSharpInStyleBlock(diagnostic, sourceText, syntaxTree, logger),
                CSSErrorCodes.MissingSelectorBeforeCombinatorCode => IsCSharpInStyleBlock(diagnostic, sourceText, syntaxTree, logger),
                HtmlErrorCodes.UnexpectedEndTagErrorCode => IsHtmlWithBangAndMatchingTags(diagnostic, sourceText, syntaxTree, logger),
                HtmlErrorCodes.InvalidNestingErrorCode => IsAnyFilteredInvalidNestingError(diagnostic, sourceText, syntaxTree, logger),
                HtmlErrorCodes.MissingEndTagErrorCode => FileKinds.IsComponent(syntaxTree.Options.FileKind), // Redundant with RZ9980 in Components
                HtmlErrorCodes.TooFewElementsErrorCode => IsAnyFilteredTooFewElementsError(diagnostic, sourceText, syntaxTree, logger),
                _ => false,
            });
Exemplo n.º 20
0
        public override IReadOnlyList <RazorCompletionItem> GetCompletionItems(RazorSyntaxTree syntaxTree, TagHelperDocumentContext tagHelperDocumentContext, SourceSpan location)
        {
            if (!FileKinds.IsComponent(syntaxTree.Options.FileKind))
            {
                // Directive attributes are only supported in components
                return(Array.Empty <RazorCompletionItem>());
            }

            var change = new SourceChange(location, string.Empty);
            var owner  = syntaxTree.Root.LocateOwner(change);

            if (owner == null)
            {
                return(Array.Empty <RazorCompletionItem>());
            }

            var attribute = owner.Parent;

            if (attribute is MarkupMiscAttributeContentSyntax)
            {
                // This represents a tag when there's no attribute content <InputText | />.
                return(Completions);
            }

            if (!TryGetAttributeInfo(owner, out var prefixLocation, out var attributeName, out var attributeNameLocation, out _, out _))
            {
                return(Array.Empty <RazorCompletionItem>());
            }

            if (attributeNameLocation.IntersectsWith(location.AbsoluteIndex) && attributeName.StartsWith("@", StringComparison.Ordinal))
            {
                // The transition is already provided for the attribute name
                return(Array.Empty <RazorCompletionItem>());
            }

            if (!IsValidCompletionPoint(location, prefixLocation, attributeNameLocation))
            {
                // Not operating in the attribute name area
                return(Array.Empty <RazorCompletionItem>());
            }

            // This represents a tag when there's no attribute content <InputText | />.
            return(Completions);
        }
        private HostDocument[] GetChangedAndRemovedDocuments(IProjectSubscriptionUpdate update)
        {
            IProjectChangeDescription rule = null;

            var documents = new List <HostDocument>();

            if (update.ProjectChanges.TryGetValue(Rules.RazorComponentWithTargetPath.SchemaName, out rule))
            {
                foreach (var key in rule.Difference.RemovedItems.Concat(rule.Difference.ChangedItems))
                {
                    if (rule.Before.Items.TryGetValue(key, out var value))
                    {
                        if (value.TryGetValue(Rules.RazorComponentWithTargetPath.TargetPathProperty, out var targetPath) &&
                            !string.IsNullOrWhiteSpace(key) &&
                            !string.IsNullOrWhiteSpace(targetPath))
                        {
                            var filePath = CommonServices.UnconfiguredProject.MakeRooted(key);
                            var fileKind = FileKinds.GetComponentFileKindFromFilePath(filePath);

                            documents.Add(new HostDocument(filePath, targetPath, fileKind));
                        }
                    }
                }
            }

            if (update.ProjectChanges.TryGetValue(Rules.RazorGenerateWithTargetPath.SchemaName, out rule))
            {
                foreach (var key in rule.Difference.RemovedItems.Concat(rule.Difference.ChangedItems))
                {
                    if (rule.Before.Items.TryGetValue(key, out var value))
                    {
                        if (value.TryGetValue(Rules.RazorGenerateWithTargetPath.TargetPathProperty, out var targetPath) &&
                            !string.IsNullOrWhiteSpace(key) &&
                            !string.IsNullOrWhiteSpace(targetPath))
                        {
                            var filePath = CommonServices.UnconfiguredProject.MakeRooted(key);
                            documents.Add(new HostDocument(filePath, targetPath, FileKinds.Legacy));
                        }
                    }
                }
            }

            return(documents.ToArray());
        }
Exemplo n.º 22
0
        public IReadOnlyList <RazorProjectItem> GetImports(RazorProjectItem projectItem)
        {
            if (projectItem == null)
            {
                throw new ArgumentNullException(nameof(projectItem));
            }

            // Don't add Component imports for a non-component.
            if (!FileKinds.IsComponent(projectItem.FileKind))
            {
                return(Array.Empty <RazorProjectItem>());
            }

            var imports = new List <RazorProjectItem>()
            {
                new VirtualProjectItem(DefaultUsingImportContent),
                new VirtualProjectItem(@"@addTagHelper ""*, Microsoft.AspNetCore.Components"""),
            };

            // Try and infer a namespace from the project directory. We don't yet have the ability to pass
            // the namespace through from the project.
            if (projectItem.PhysicalPath != null && projectItem.FilePath != null)
            {
                // Avoiding the path-specific APIs here, we want to handle all styles of paths
                // on all platforms
                var trimLength = projectItem.FilePath.Length + (projectItem.FilePath.StartsWith("/") ? 0 : 1);
                if (projectItem.PhysicalPath.Length > trimLength)
                {
                    var baseDirectory = projectItem.PhysicalPath.Substring(0, projectItem.PhysicalPath.Length - trimLength);
                    var lastSlash     = baseDirectory.LastIndexOfAny(PathSeparators);
                    var baseNamespace = lastSlash == -1 ? baseDirectory : baseDirectory.Substring(lastSlash + 1);
                    if (!string.IsNullOrEmpty(baseNamespace))
                    {
                        imports.Add(new VirtualProjectItem($@"@addTagHelper ""*, {baseNamespace}"""));
                    }
                }
            }

            // We add hierarchical imports second so any default directive imports can be overridden.
            imports.AddRange(GetHierarchicalImports(ProjectEngine.FileSystem, projectItem));

            return(imports);
        }
Exemplo n.º 23
0
        // Internal for testing
        internal static List <RazorCompletionItem> GetDirectiveCompletionItems(RazorSyntaxTree syntaxTree)
        {
            var defaultDirectives = FileKinds.IsComponent(syntaxTree.Options.FileKind) ? Array.Empty <DirectiveDescriptor>() : DefaultDirectives;
            var directives        = syntaxTree.Options.Directives.Concat(defaultDirectives);
            var completionItems   = new List <RazorCompletionItem>();

            foreach (var directive in directives)
            {
                var completionDisplayText = directive.DisplayName ?? directive.Directive;
                var completionItem        = new RazorCompletionItem(
                    completionDisplayText,
                    directive.Directive,
                    directive.Description,
                    RazorCompletionItemKind.Directive);
                completionItems.Add(completionItem);
            }

            return(completionItems);
        }
Exemplo n.º 24
0
        public IReadOnlyList <RazorProjectItem> GetImports(RazorProjectItem projectItem)
        {
            if (projectItem == null)
            {
                throw new ArgumentNullException(nameof(projectItem));
            }

            // Don't add MVC imports for a component - this shouldn't happen for v2, but just in case.
            if (FileKinds.IsComponent(projectItem.FileKind))
            {
                return(Array.Empty <RazorProjectItem>());
            }

            var imports = new List <RazorProjectItem>();

            AddDefaultDirectivesImport(imports);

            // We add hierarchical imports second so any default directive imports can be overridden.
            AddHierarchicalImports(projectItem, imports);

            return(imports);
        }
        // Internal for testing
        internal bool IsComponentFile(string relativeDocumentFilePath, string projectFilePath)
        {
            _foregroundDispatcher.AssertForegroundThread();

            var projectSnapshot = _projectManager.GetLoadedProject(projectFilePath);

            if (projectSnapshot == null)
            {
                return(false);
            }

            var documentSnapshot = projectSnapshot.GetDocument(relativeDocumentFilePath);

            if (documentSnapshot == null)
            {
                return(false);
            }

            var isComponentKind = FileKinds.IsComponent(documentSnapshot.FileKind);

            return(isComponentKind);
        }
        private HostDocument[] GetCurrentDocuments(IProjectSubscriptionUpdate update)
        {
            IProjectRuleSnapshot rule = null;

            var documents = new List <HostDocument>();

            if (update.CurrentState.TryGetValue(Rules.RazorComponentWithTargetPath.SchemaName, out rule))
            {
                foreach (var kvp in rule.Items)
                {
                    if (kvp.Value.TryGetValue(Rules.RazorComponentWithTargetPath.TargetPathProperty, out var targetPath) &&
                        !string.IsNullOrWhiteSpace(kvp.Key) &&
                        !string.IsNullOrWhiteSpace(targetPath))
                    {
                        var filePath = CommonServices.UnconfiguredProject.MakeRooted(kvp.Key);
                        var fileKind = FileKinds.GetComponentFileKindFromFilePath(filePath);

                        documents.Add(new HostDocument(filePath, targetPath, fileKind));
                    }
                }
            }

            if (update.CurrentState.TryGetValue(Rules.RazorGenerateWithTargetPath.SchemaName, out rule))
            {
                foreach (var kvp in rule.Items)
                {
                    if (kvp.Value.TryGetValue(Rules.RazorGenerateWithTargetPath.TargetPathProperty, out var targetPath) &&
                        !string.IsNullOrWhiteSpace(kvp.Key) &&
                        !string.IsNullOrWhiteSpace(targetPath))
                    {
                        var filePath = CommonServices.UnconfiguredProject.MakeRooted(kvp.Key);
                        documents.Add(new HostDocument(filePath, targetPath, FileKinds.Legacy));
                    }
                }
            }

            return(documents.ToArray());
        }
    public IReadOnlyList <RazorProjectItem> GetImports(RazorProjectItem projectItem)
    {
        if (projectItem == null)
        {
            throw new ArgumentNullException(nameof(projectItem));
        }

        // Don't add Component imports for a non-component.
        if (!FileKinds.IsComponent(projectItem.FileKind))
        {
            return(Array.Empty <RazorProjectItem>());
        }

        var imports = new List <RazorProjectItem>()
        {
            new VirtualProjectItem(DefaultUsingImportContent),
        };

        // We add hierarchical imports second so any default directive imports can be overridden.
        imports.AddRange(GetHierarchicalImports(ProjectEngine.FileSystem, projectItem));

        return(imports);
    }
Exemplo n.º 28
0
 public NotFoundProjectItem(string basePath, string path, string?fileKind)
 {
     BasePath = basePath;
     FilePath = path;
     FileKind = fileKind ?? FileKinds.GetFileKindFromFilePath(path);
 }
Exemplo n.º 29
0
    protected override void ExecuteCore(RazorCodeDocument codeDocument)
    {
        var syntaxTree = codeDocument.GetSyntaxTree();

        ThrowForMissingDocumentDependency(syntaxTree);

        var descriptors = codeDocument.GetTagHelpers();

        if (descriptors == null)
        {
            var feature = Engine.GetFeature <ITagHelperFeature>();
            if (feature == null)
            {
                // No feature, nothing to do.
                return;
            }

            descriptors = feature.GetDescriptors();
        }

        var parserOptions = codeDocument.GetParserOptions();

        // We need to find directives in all of the *imports* as well as in the main razor file
        //
        // The imports come logically before the main razor file and are in the order they
        // should be processed.
        DirectiveVisitor visitor;

        if (FileKinds.IsComponent(codeDocument.GetFileKind()) &&
            (parserOptions == null || parserOptions.FeatureFlags.AllowComponentFileKind))
        {
            codeDocument.TryComputeNamespace(fallbackToRootNamespace: true, out var currentNamespace);
            visitor = new ComponentDirectiveVisitor(codeDocument.Source.FilePath, descriptors, currentNamespace);
        }
        else
        {
            visitor = new TagHelperDirectiveVisitor(descriptors);
        }
        var imports = codeDocument.GetImportSyntaxTrees();

        if (imports != null)
        {
            for (var i = 0; i < imports.Count; i++)
            {
                var import = imports[i];
                visitor.Visit(import);
            }
        }

        visitor.Visit(syntaxTree);

        // This will always be null for a component document.
        var tagHelperPrefix = visitor.TagHelperPrefix;

        descriptors = visitor.Matches.ToArray();

        var context = TagHelperDocumentContext.Create(tagHelperPrefix, descriptors);

        codeDocument.SetTagHelperContext(context);

        if (descriptors.Count == 0)
        {
            // No descriptors, no-op.
            return;
        }

        var rewrittenSyntaxTree = TagHelperParseTreeRewriter.Rewrite(syntaxTree, tagHelperPrefix, descriptors);

        codeDocument.SetSyntaxTree(rewrittenSyntaxTree);
    }
Exemplo n.º 30
0
        public override async Task <WorkspaceEdit> ResolveAsync(JObject data, CancellationToken cancellationToken)
        {
            if (data is null)
            {
                return(null);
            }

            var actionParams = data.ToObject <AddUsingsCodeActionParams>();
            var path         = actionParams.Uri.GetAbsoluteOrUNCPath();

            var document = await Task.Factory.StartNew(() =>
            {
                _documentResolver.TryResolveDocument(path, out var documentSnapshot);
                return(documentSnapshot);
            }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false);

            if (document is null)
            {
                return(null);
            }

            var text = await document.GetTextAsync().ConfigureAwait(false);

            if (text is null)
            {
                return(null);
            }

            var codeDocument = await document.GetGeneratedOutputAsync().ConfigureAwait(false);

            if (codeDocument.IsUnsupported())
            {
                return(null);
            }

            if (!FileKinds.IsComponent(codeDocument.GetFileKind()))
            {
                return(null);
            }

            var codeDocumentIdentifier = new VersionedTextDocumentIdentifier()
            {
                Uri = actionParams.Uri
            };
            var documentChanges = new List <WorkspaceEditDocumentChange>();

            /* The heuristic is as follows:
             *
             * - If no @using, @namespace, or @page directives are present, insert the statements at the top of the
             *   file in alphabetical order.
             * - If a @namespace or @page are present, the statements are inserted after the last line-wise in
             *   alphabetical order.
             * - If @using directives are present and alphabetized with System directives at the top, the statements
             *   will be placed in the correct locations according to that ordering.
             * - Otherwise it's kinda undefined; it's only geared to insert based on alphabetization.
             *
             * This is generally sufficient for our current situation (inserting a single @using statement to include a
             * component), however it has holes if we eventually use it for other purposes. If we want to deal with
             * that now I can come up with a more sophisticated heuristic (something along the lines of checking if
             * there's already an ordering, etc.).
             */
            var usingDirectives = FindUsingDirectives(codeDocument);

            if (usingDirectives.Count > 0)
            {
                // Interpolate based on existing @using statements
                var edits = GenerateSingleUsingEditsInterpolated(codeDocument, codeDocumentIdentifier, actionParams.Namespace, usingDirectives);
                documentChanges.Add(edits);
            }
            else
            {
                // Just throw them at the top
                var edits = GenerateSingleUsingEditsAtTop(codeDocument, codeDocumentIdentifier, actionParams.Namespace);
                documentChanges.Add(edits);
            }

            return(new WorkspaceEdit()
            {
                DocumentChanges = documentChanges
            });
        }