public async Task Handle_ResolveEditBasedCodeActionCommand()
        {
            // Arrange
            var codeActionEndpoint = new CodeActionResolutionEndpoint(
                Array.Empty <RazorCodeActionResolver>(),
                new CSharpCodeActionResolver[] {
                new MockCSharpCodeActionResolver("Test"),
            },
                LoggerFactory);
            var requestParams = new RazorCodeActionResolutionParams()
            {
                Action   = LanguageServerConstants.CodeActions.EditBasedCodeActionCommand,
                Language = LanguageServerConstants.CodeActions.Languages.Razor,
                Data     = JToken.FromObject(new WorkspaceEdit())
            };

            var request = new CodeAction()
            {
                Title = "Valid request",
                Data  = JToken.FromObject(requestParams)
            };

            // Act
            var razorCodeAction = await codeActionEndpoint.Handle(request, default);

            // Assert
            Assert.NotNull(razorCodeAction.Edit);
        }
        internal static bool TryCreateAddUsingResolutionParams(string fullyQualifiedName, DocumentUri uri, out string @namespace, out RazorCodeActionResolutionParams resolutionParams)
        {
            @namespace = GetNamespaceFromFQN(fullyQualifiedName);
            if (string.IsNullOrEmpty(@namespace))
            {
                @namespace       = null;
                resolutionParams = null;
                return(false);
            }

            var actionParams = new AddUsingsCodeActionParams
            {
                Uri       = uri,
                Namespace = @namespace
            };

            resolutionParams = new RazorCodeActionResolutionParams
            {
                Action   = LanguageServerConstants.CodeActions.AddUsing,
                Language = LanguageServerConstants.CodeActions.Languages.Razor,
                Data     = actionParams,
            };

            return(true);
        }
        public async Task Handle_Valid_CSharpCodeAction_WithMultipleLanguageResolvers()
        {
            // Arrange
            var codeActionEndpoint = new CodeActionResolutionEndpoint(
                new RazorCodeActionResolver[] {
                new MockRazorCodeActionResolver("TestRazor"),
            },
                new CSharpCodeActionResolver[] {
                new MockCSharpCodeActionResolver("TestCSharp"),
            },
                LoggerFactory);
            var requestParams = new RazorCodeActionResolutionParams()
            {
                Action   = "TestCSharp",
                Language = LanguageServerConstants.CodeActions.Languages.CSharp,
                Data     = JObject.FromObject(new CSharpCodeActionParams())
            };
            var request = new CodeAction()
            {
                Title = "Valid request",
                Data  = JToken.FromObject(requestParams)
            };

            // Act
            var razorCodeAction = await codeActionEndpoint.Handle(request, default);

            // Assert
            Assert.NotNull(razorCodeAction.Edit);
        }
        internal static CodeAction CreateAddUsingCodeAction(string fullyQualifiedName, DocumentUri uri)
        {
            var @namespace = GetNamespaceFromFQN(fullyQualifiedName);

            if (string.IsNullOrEmpty(@namespace))
            {
                return(null);
            }

            var actionParams = new AddUsingsCodeActionParams
            {
                Uri       = uri,
                Namespace = @namespace
            };

            var resolutionParams = new RazorCodeActionResolutionParams
            {
                Action   = LanguageServerConstants.CodeActions.AddUsing,
                Language = LanguageServerConstants.CodeActions.Languages.Razor,
                Data     = actionParams,
            };

            return(new CodeAction()
            {
                Title = $"@using {@namespace}",
                Data = JToken.FromObject(resolutionParams)
            });
        }
Exemple #5
0
        private void AddCreateComponentFromTag(RazorCodeActionContext context, MarkupStartTagSyntax startTag, List <RazorCodeAction> container)
        {
            var path = context.Request.TextDocument.Uri.GetAbsoluteOrUNCPath();

            path = _filePathNormalizer.Normalize(path);
            var newComponentPath = Path.Combine(Path.GetDirectoryName(path), $"{startTag.Name.Content}.razor");

            if (File.Exists(newComponentPath))
            {
                return;
            }

            var actionParams = new CreateComponentCodeActionParams
            {
                Uri  = context.Request.TextDocument.Uri,
                Path = newComponentPath,
            };

            var resolutionParams = new RazorCodeActionResolutionParams
            {
                Action = LanguageServerConstants.CodeActions.CreateComponentFromTag,
                Data   = actionParams,
            };

            container.Add(new RazorCodeAction()
            {
                Title = CreateComponentFromTagTitle,
                Data  = resolutionParams
            });
        }
        // Internal for testing
        internal async Task <CodeAction> ResolveCSharpCodeActionAsync(
            CodeAction codeAction,
            RazorCodeActionResolutionParams resolutionParams,
            CancellationToken cancellationToken)
        {
            if (!(resolutionParams.Data is JObject csharpParamsObj))
            {
                Debug.Fail($"Invalid CSharp CodeAction Received.");
                return(codeAction);
            }

            var csharpParams = csharpParamsObj.ToObject <CSharpCodeActionParams>();

            codeAction.Data = csharpParams.Data as JToken;

            if (!_csharpCodeActionResolvers.TryGetValue(resolutionParams.Action, out var resolver))
            {
                Debug.Fail($"No resolver registered for {GetCodeActionId(resolutionParams)}.");
                return(codeAction);
            }

            var resolvedCodeAction = await resolver.ResolveAsync(csharpParams, codeAction, cancellationToken);

            return(resolvedCodeAction);
        }
Exemple #7
0
        internal async Task <CodeAction> ResolveCSharpCodeActionAsync(
            CodeAction codeAction,
            RazorCodeActionResolutionParams resolutionParams,
            CancellationToken cancellationToken)
        {
            if (resolutionParams.Data is not JObject csharpParamsObj)
            {
                _logger.LogError("Invalid CodeAction Received.");
                Debug.Fail($"Invalid CSharp CodeAction Received.");
                return(codeAction);
            }

            var csharpParams = csharpParamsObj.ToObject <CSharpCodeActionParams>();

            codeAction = codeAction with {
                Data = csharpParams.Data as JToken
            };

            if (!_csharpCodeActionResolvers.TryGetValue(resolutionParams.Action, out var resolver))
            {
                var codeActionId = GetCodeActionId(resolutionParams);
                _logger.LogWarning("No resolver registered for {codeActionId}", codeActionId);
                Debug.Fail($"No resolver registered for {codeActionId}.");
                return(codeAction);
            }

            var resolvedCodeAction = await resolver.ResolveAsync(csharpParams, codeAction, cancellationToken);

            return(resolvedCodeAction);
        }
Exemple #8
0
        private void AddCreateComponentFromTag(RazorCodeActionContext context, MarkupStartTagSyntax startTag, List <CommandOrCodeAction> container)
        {
            var path = context.Request.TextDocument.Uri.GetAbsoluteOrUNCPath();

            path = _filePathNormalizer.Normalize(path);
            var newComponentPath = Path.Combine(Path.GetDirectoryName(path), $"{startTag.Name.Content}.razor");

            if (File.Exists(newComponentPath))
            {
                return;
            }

            var actionParams = new CreateComponentCodeActionParams
            {
                Uri  = context.Request.TextDocument.Uri,
                Path = newComponentPath,
            };
            var data = JObject.FromObject(actionParams);

            var resolutionParams = new RazorCodeActionResolutionParams
            {
                Action = LanguageServerConstants.CodeActions.CreateComponentFromTag,
                Data   = data,
            };
            var serializedParams = JToken.FromObject(resolutionParams);
            var arguments        = new JArray(serializedParams);

            container.Add(new CommandOrCodeAction(new Command
            {
                Title     = "Create component from tag",
                Name      = LanguageServerConstants.RazorCodeActionRunnerCommand,
                Arguments = arguments,
            }));
        }
        public async Task Handle_Valid_RazorCodeAction_WithoutResolver()
        {
            // Arrange
            var codeActionEndpoint = new CodeActionResolutionEndpoint(
                Array.Empty <RazorCodeActionResolver>(),
                Array.Empty <CSharpCodeActionResolver>(),
                LoggerFactory);
            var requestParams = new RazorCodeActionResolutionParams()
            {
                Action   = "Test",
                Language = LanguageServerConstants.CodeActions.Languages.Razor,
                Data     = new AddUsingsCodeActionParams()
            };
            var request = new CodeAction()
            {
                Title = "Valid request",
                Data  = JToken.FromObject(requestParams)
            };

#if DEBUG
            // Act & Assert (Throws due to debug assert on no Razor.Test resolver)
            await Assert.ThrowsAnyAsync <Exception>(async() => await codeActionEndpoint.Handle(request, default));
#else
            // Act
            var resolvedCodeAction = await codeActionEndpoint.Handle(request, default);

            // Assert
            Assert.Null(resolvedCodeAction.Edit);
#endif
        }
        public async Task Handle_Valid_RazorCodeAction_WithResolver()
        {
            // Arrange
            var codeActionEndpoint = new CodeActionResolutionEndpoint(
                new RazorCodeActionResolver[] {
                new MockRazorCodeActionResolver("Test"),
            },
                Array.Empty <CSharpCodeActionResolver>(),
                LoggerFactory);
            var requestParams = new RazorCodeActionResolutionParams()
            {
                Action   = "Test",
                Language = LanguageServerConstants.CodeActions.Languages.Razor,
                Data     = new AddUsingsCodeActionParams()
            };
            var request = new CodeAction()
            {
                Title = "Valid request",
                Data  = JToken.FromObject(requestParams)
            };

            // Act
            var razorCodeAction = await codeActionEndpoint.Handle(request, default);

            // Assert
            Assert.NotNull(razorCodeAction.Edit);
        }
        public async Task Handle_Valid_CSharpCodeAction_WithRazorResolver_ResolvesNull()
        {
            // Arrange
            var codeActionEndpoint = new CodeActionResolutionEndpoint(
                new RazorCodeActionResolver[] {
                new MockRazorCodeActionResolver("Test"),
            },
                Array.Empty <CSharpCodeActionResolver>(),
                LoggerFactory);
            var requestParams = new RazorCodeActionResolutionParams()
            {
                Action   = "Test",
                Language = LanguageServerConstants.CodeActions.Languages.CSharp,
                Data     = JObject.FromObject(new CSharpCodeActionParams())
            };
            var request = new CodeAction()
            {
                Title = "Valid request",
                Data  = JToken.FromObject(requestParams)
            };

#if DEBUG
            // Act & Assert (Throws due to debug asserts)
            await Assert.ThrowsAnyAsync <Exception>(async() => await codeActionEndpoint.Handle(request, default));
#else
            // Act
            var resolvedCodeAction = await codeActionEndpoint.Handle(request, default);

            // Assert
            Assert.Null(resolvedCodeAction.Edit);
#endif
        }
        public async Task ResolveCSharpCodeAction_ResolveMultipleLanguageProviders()
        {
            // Arrange
            var codeActionEndpoint = new CodeActionResolutionEndpoint(
                new RazorCodeActionResolver[] {
                new MockRazorNullCodeActionResolver("A"),
                new MockRazorCodeActionResolver("B"),
            },
                new CSharpCodeActionResolver[] {
                new MockCSharpNullCodeActionResolver("C"),
                new MockCSharpCodeActionResolver("D"),
            },
                LoggerFactory);
            var codeAction = new CodeAction();
            var request    = new RazorCodeActionResolutionParams()
            {
                Action   = "D",
                Language = LanguageServerConstants.CodeActions.Languages.CSharp,
                Data     = JObject.FromObject(new CSharpCodeActionParams())
            };

            // Act
            var resolvedCodeAction = await codeActionEndpoint.ResolveCSharpCodeActionAsync(codeAction, request, default);

            // Assert
            Assert.NotNull(resolvedCodeAction.Edit);
        }
Exemple #13
0
        // Internal for testing
        internal async Task <WorkspaceEdit> GetWorkspaceEditAsync(RazorCodeActionResolutionParams resolutionParams, CancellationToken cancellationToken)
        {
            _logger.LogInformation($"Resolving workspace edit for action `{resolutionParams.Action}`.");

            if (!_resolvers.TryGetValue(resolutionParams.Action, out var resolver))
            {
                Debug.Fail($"No resolver registered for {resolutionParams.Action}.");
                return(default);
        // Internal for testing
        internal async Task <CodeAction> ResolveRazorCodeActionAsync(
            CodeAction codeAction,
            RazorCodeActionResolutionParams resolutionParams,
            CancellationToken cancellationToken)
        {
            if (!_razorCodeActionResolvers.TryGetValue(resolutionParams.Action, out var resolver))
            {
                Debug.Fail($"No resolver registered for {GetCodeActionId(resolutionParams)}.");
                return(codeAction);
            }

            codeAction.Edit = await resolver.ResolveAsync(resolutionParams.Data as JObject, cancellationToken).ConfigureAwait(false);

            return(codeAction);
        }
Exemple #15
0
        private void AddComponentAccessFromTag(RazorCodeActionContext context, MarkupStartTagSyntax startTag, List <CommandOrCodeAction> container)
        {
            var matching = FindMatchingTagHelpers(context, startTag);

            // For all the matches, add options for add @using and fully qualify
            foreach (var tagHelperPair in matching.Values)
            {
                if (tagHelperPair.FullyQualified is null)
                {
                    continue;
                }

                var fullyQualifiedComponentName = tagHelperPair.Short.Name;  // We assume .Name is the fully qualified component name
                DefaultRazorTagHelperBinderPhase.ComponentDirectiveVisitor.TrySplitNamespaceAndType(fullyQualifiedComponentName, out var namespaceSpan, out var _);
                var namespaceName = tagHelperPair.Short.Name.Substring(namespaceSpan.Start, namespaceSpan.Length);
                var actionParams  = new AddUsingsCodeActionParams
                {
                    Uri       = context.Request.TextDocument.Uri,
                    Namespace = namespaceName,
                };
                var data = JObject.FromObject(actionParams);

                var resolutionParams = new RazorCodeActionResolutionParams
                {
                    Action = LanguageServerConstants.CodeActions.AddUsing,
                    Data   = data,
                };
                var serializedParams = JToken.FromObject(resolutionParams);
                var arguments        = new JArray(serializedParams);

                // Insert @using
                container.Add(new CommandOrCodeAction(new Command
                {
                    Title     = $"@using {namespaceName}",
                    Name      = LanguageServerConstants.RazorCodeActionRunnerCommand,
                    Arguments = arguments,
                }));

                // Fully qualify
                container.Add(new CommandOrCodeAction(new CodeAction
                {
                    Title = $"{tagHelperPair.Short.Name}",
                    Edit  = CreateRenameTagEdit(context, startTag, tagHelperPair.Short.Name),
                }));
            }
        }
Exemple #16
0
        public async Task Handle_Resolve()
        {
            // Arrange
            var codeActionEndpoint = new CodeActionResolutionEndpoint(new RazorCodeActionResolver[] {
                new MockCodeActionResolver("Test"),
            }, LoggerFactory);
            var request = new RazorCodeActionResolutionParams()
            {
                Action = "Test",
                Data   = null
            };

            // Act
            var workspaceEdit = await codeActionEndpoint.Handle(request, default);

            // Assert
            Assert.NotNull(workspaceEdit);
        }
Exemple #17
0
        public async Task Handle_ResolveMultipleProviders_SecondMatches()
        {
            // Arrange
            var codeActionEndpoint = new CodeActionResolutionEndpoint(new RazorCodeActionResolver[] {
                new NullMockCodeActionResolver("A"),
                new MockCodeActionResolver("B"),
            }, LoggerFactory);
            var request = new RazorCodeActionResolutionParams()
            {
                Action = "B",
                Data   = null
            };

            // Act
            var workspaceEdit = await codeActionEndpoint.Handle(request, default);

            // Assert
            Assert.NotNull(workspaceEdit);
        }
Exemple #18
0
        public async Task GetWorkspaceEditAsync_ResolveMultipleProviders_FirstMatches()
        {
            // Arrange
            var codeActionEndpoint = new CodeActionResolutionEndpoint(new RazorCodeActionResolver[] {
                new MockCodeActionResolver("A"),
                new NullMockCodeActionResolver("B"),
            }, LoggerFactory);
            var request = new RazorCodeActionResolutionParams()
            {
                Action = "A",
                Data   = new AddUsingsCodeActionParams()
            };

            // Act
            var workspaceEdit = await codeActionEndpoint.GetWorkspaceEditAsync(request, default);

            // Assert
            Assert.NotNull(workspaceEdit);
        }
Exemple #19
0
        internal async Task <CodeAction> ResolveRazorCodeActionAsync(
            CodeAction codeAction,
            RazorCodeActionResolutionParams resolutionParams,
            CancellationToken cancellationToken)
        {
            if (!_razorCodeActionResolvers.TryGetValue(resolutionParams.Action, out var resolver))
            {
                var codeActionId = GetCodeActionId(resolutionParams);
                _logger.LogWarning("No resolver registered for {codeActionId}", codeActionId);
                Debug.Fail($"No resolver registered for {codeActionId}.");
                return(codeAction);
            }

            var edit = await resolver.ResolveAsync(resolutionParams.Data as JObject, cancellationToken).ConfigureAwait(false);

            codeAction = codeAction with {
                Edit = edit
            };
            return(codeAction);
        }
        private void AddCreateComponentFromTag(RazorCodeActionContext context, MarkupStartTagSyntax startTag, List <RazorCodeAction> container)
        {
            if (context is null)
            {
                return;
            }

            if (!context.SupportsFileCreation)
            {
                return;
            }

            var path = context.Request.TextDocument.Uri.GetAbsoluteOrUNCPath();

            path = _filePathNormalizer.Normalize(path);
            var newComponentPath = Path.Combine(Path.GetDirectoryName(path), $"{startTag.Name.Content}.razor");

            if (File.Exists(newComponentPath))
            {
                return;
            }

            var actionParams = new CreateComponentCodeActionParams
            {
                Uri  = context.Request.TextDocument.Uri,
                Path = newComponentPath,
            };

            var resolutionParams = new RazorCodeActionResolutionParams
            {
                Action   = LanguageServerConstants.CodeActions.CreateComponentFromTag,
                Language = LanguageServerConstants.CodeActions.Languages.Razor,
                Data     = actionParams,
            };

            container.Add(new RazorCodeAction()
            {
                Title = RazorLS.Resources.Create_Component_FromTag_Title,
                Data  = JToken.FromObject(resolutionParams)
            });
        }
Exemple #21
0
        public async Task <RazorCodeActionResolutionResponse> Handle(RazorCodeActionResolutionParams request, CancellationToken cancellationToken)
        {
            if (request is null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            _logger.LogDebug($"Resolving action {request.Action} with data {request.Data}.");

            if (!_resolvers.TryGetValue(request.Action, out var resolver))
            {
                Debug.Fail($"No resolver registered for {request.Action}.");
                return(new RazorCodeActionResolutionResponse());
            }

            var edit = await resolver.ResolveAsync(request.Data, cancellationToken).ConfigureAwait(false);

            return(new RazorCodeActionResolutionResponse()
            {
                Edit = edit
            });
        }
Exemple #22
0
        public async Task Handle_Valid_RazorCodeAction_Resolve()
        {
            // Arrange
            var codeActionEndpoint = new CodeActionResolutionEndpoint(new RazorCodeActionResolver[] {
                new MockCodeActionResolver("Test"),
            }, LoggerFactory);
            var requestParams = new RazorCodeActionResolutionParams()
            {
                Action = "Test",
                Data   = new AddUsingsCodeActionParams()
            };
            var request = new RazorCodeAction()
            {
                Title = "Valid request",
                Data  = JObject.FromObject(requestParams)
            };

            // Act
            var razorCodeAction = await codeActionEndpoint.Handle(request, default);

            // Assert
            Assert.NotNull(razorCodeAction.Edit);
        }
        public async Task ResolveRazorCodeAction_ResolveMultipleRazorProviders_SecondMatches()
        {
            // Arrange
            var codeActionEndpoint = new CodeActionResolutionEndpoint(
                new RazorCodeActionResolver[] {
                new MockRazorNullCodeActionResolver("A"),
                new MockRazorCodeActionResolver("B"),
            },
                Array.Empty <CSharpCodeActionResolver>(),
                LoggerFactory);
            var codeAction = new CodeAction();
            var request    = new RazorCodeActionResolutionParams()
            {
                Action   = "B",
                Language = LanguageServerConstants.CodeActions.Languages.Razor,
                Data     = new AddUsingsCodeActionParams()
            };

            // Act
            var resolvedCodeAction = await codeActionEndpoint.ResolveRazorCodeActionAsync(codeAction, request, default);

            // Assert
            Assert.NotNull(resolvedCodeAction.Edit);
        }
 private static string GetCodeActionId(RazorCodeActionResolutionParams resolutionParams) =>
 $"`{resolutionParams.Language}.{resolutionParams.Action}`";
Exemple #25
0
        override public Task <CommandOrCodeActionContainer> ProvideAsync(RazorCodeActionContext context, CancellationToken cancellationToken)
        {
            if (context is null)
            {
                return(EmptyResult);
            }

            if (!FileKinds.IsComponent(context.CodeDocument.GetFileKind()))
            {
                return(EmptyResult);
            }

            var change     = new SourceChange(context.Location.AbsoluteIndex, length: 0, newText: string.Empty);
            var syntaxTree = context.CodeDocument.GetSyntaxTree();

            if (syntaxTree?.Root is null)
            {
                return(EmptyResult);
            }

            var owner = syntaxTree.Root.LocateOwner(change);
            var node  = owner.Ancestors().FirstOrDefault(n => n.Kind == SyntaxKind.RazorDirective);

            if (node == null || !(node is RazorDirectiveSyntax directiveNode))
            {
                return(EmptyResult);
            }

            // Make sure we've found a @code or @functions
            if (directiveNode.DirectiveDescriptor != ComponentCodeDirective.Directive && directiveNode.DirectiveDescriptor != FunctionsDirective.Directive)
            {
                return(EmptyResult);
            }

            // No code action if malformed
            if (directiveNode.GetDiagnostics().Any(d => d.Severity == RazorDiagnosticSeverity.Error))
            {
                return(EmptyResult);
            }

            var cSharpCodeBlockNode = directiveNode.Body.DescendantNodes().FirstOrDefault(n => n is CSharpCodeBlockSyntax);

            if (cSharpCodeBlockNode is null)
            {
                return(EmptyResult);
            }

            if (HasUnsupportedChildren(cSharpCodeBlockNode))
            {
                return(EmptyResult);
            }

            // Do not provide code action if the cursor is inside the code block
            if (context.Location.AbsoluteIndex > cSharpCodeBlockNode.SpanStart)
            {
                return(EmptyResult);
            }

            var actionParams = new ExtractToCodeBehindCodeActionParams()
            {
                Uri          = context.Request.TextDocument.Uri,
                ExtractStart = cSharpCodeBlockNode.Span.Start,
                ExtractEnd   = cSharpCodeBlockNode.Span.End,
                RemoveStart  = directiveNode.Span.Start,
                RemoveEnd    = directiveNode.Span.End
            };
            var data = JObject.FromObject(actionParams);

            var resolutionParams = new RazorCodeActionResolutionParams()
            {
                Action = LanguageServerConstants.CodeActions.ExtractToCodeBehindAction,
                Data   = data,
            };
            var serializedParams = JToken.FromObject(resolutionParams);
            var arguments        = new JArray(serializedParams);

            var container = new List <CommandOrCodeAction>
            {
                new Command()
                {
                    Title     = "Extract block to code behind",
                    Name      = LanguageServerConstants.RazorCodeActionRunnerCommand,
                    Arguments = arguments,
                }
            };

            return(Task.FromResult((CommandOrCodeActionContainer)container));
        }
        public override Task <RazorCodeAction[]> ProvideAsync(RazorCodeActionContext context, CancellationToken cancellationToken)
        {
            if (context is null)
            {
                return(EmptyResult);
            }

            if (!FileKinds.IsComponent(context.CodeDocument.GetFileKind()))
            {
                return(EmptyResult);
            }

            var change     = new SourceChange(context.Location.AbsoluteIndex, length: 0, newText: string.Empty);
            var syntaxTree = context.CodeDocument.GetSyntaxTree();

            if (syntaxTree?.Root is null)
            {
                return(EmptyResult);
            }

            var owner = syntaxTree.Root.LocateOwner(change);

            if (owner == null)
            {
                Debug.Fail("Owner should never be null.");
                return(EmptyResult);
            }

            var node = owner.Ancestors().FirstOrDefault(n => n.Kind == SyntaxKind.RazorDirective);

            if (node == null || !(node is RazorDirectiveSyntax directiveNode))
            {
                return(EmptyResult);
            }

            // Make sure we've found a @code or @functions
            if (directiveNode.DirectiveDescriptor != ComponentCodeDirective.Directive &&
                directiveNode.DirectiveDescriptor != FunctionsDirective.Directive)
            {
                return(EmptyResult);
            }

            // No code action if malformed
            if (directiveNode.GetDiagnostics().Any(d => d.Severity == RazorDiagnosticSeverity.Error))
            {
                return(EmptyResult);
            }

            var csharpCodeBlockNode = directiveNode.Body.DescendantNodes().FirstOrDefault(n => n is CSharpCodeBlockSyntax);

            if (csharpCodeBlockNode is null)
            {
                return(EmptyResult);
            }

            if (HasUnsupportedChildren(csharpCodeBlockNode))
            {
                return(EmptyResult);
            }

            // Do not provide code action if the cursor is inside the code block
            if (context.Location.AbsoluteIndex > csharpCodeBlockNode.SpanStart)
            {
                return(EmptyResult);
            }

            var actionParams = new ExtractToCodeBehindCodeActionParams()
            {
                Uri          = context.Request.TextDocument.Uri,
                ExtractStart = csharpCodeBlockNode.Span.Start,
                ExtractEnd   = csharpCodeBlockNode.Span.End,
                RemoveStart  = directiveNode.Span.Start,
                RemoveEnd    = directiveNode.Span.End
            };

            var resolutionParams = new RazorCodeActionResolutionParams()
            {
                Action = LanguageServerConstants.CodeActions.ExtractToCodeBehindAction,
                Data   = actionParams,
            };

            var codeAction = new RazorCodeAction()
            {
                Title = Title,
                Data  = resolutionParams
            };

            return(Task.FromResult(new[] { codeAction }));
        }