Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added basic extract to component functionality on cursor over html tag #10578

Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.

using System;
using System.Text.Json.Serialization;

namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions.Models;

internal sealed class ExtractToNewComponentCodeActionParams
{
[JsonPropertyName("uri")]
public required Uri Uri { get; set; }
[JsonPropertyName("extractStart")]
public int ExtractStart { get; set; }
[JsonPropertyName("extractEnd")]
public int ExtractEnd { get; set; }
[JsonPropertyName("namespace")]
public required string Namespace { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Components;
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Microsoft.AspNetCore.Razor.Language.Syntax;
using Microsoft.AspNetCore.Razor.LanguageServer.CodeActions.Models;
using Microsoft.AspNetCore.Razor.Threading;
using Microsoft.CodeAnalysis.Razor.Logging;
using Microsoft.CodeAnalysis.Razor.Workspaces;

namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions.Razor;
internal sealed class ExtractToNewComponentCodeActionProvider : IRazorCodeActionProvider
{
private readonly ILogger _logger;

public ExtractToNewComponentCodeActionProvider(ILoggerFactory loggerFactory)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider changing to a primary constructor (but keep the fields). There's a code action for that in Visual Studio.

{
_logger = loggerFactory.GetOrCreateLogger<ExtractToNewComponentCodeActionProvider>();
}

public Task<IReadOnlyList<RazorVSInternalCodeAction>?> ProvideAsync(RazorCodeActionContext context, CancellationToken cancellationToken)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that the signature of IRazorCodeActionProvider.ProvideAsync(...) changed in #10598. So, you'll need to merge main into your branch and fix up conflicts.

{
if (context is null)
{
return SpecializedTasks.Null<IReadOnlyList<RazorVSInternalCodeAction>>();
}

if (!context.SupportsFileCreation)
{
return SpecializedTasks.Null<IReadOnlyList<RazorVSInternalCodeAction>>();
}

if (!FileKinds.IsComponent(context.CodeDocument.GetFileKind()))
{
return SpecializedTasks.Null<IReadOnlyList<RazorVSInternalCodeAction>>();
}

var syntaxTree = context.CodeDocument.GetSyntaxTree();
if (syntaxTree?.Root is null)
{
return SpecializedTasks.Null<IReadOnlyList<RazorVSInternalCodeAction>>();
}

var owner = syntaxTree.Root.FindInnermostNode(context.Location.AbsoluteIndex, true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add names for boolean literal arguments for readability. In this case, I guess it would be includeWhitespace: true, but I'm not 100% sure. Without opening your branch in Visual Studio and hovering over FindInnermostNode(...), it's impossible to know.

if (owner is null)
{
_logger.LogWarning($"Owner should never be null.");
return SpecializedTasks.Null<IReadOnlyList<RazorVSInternalCodeAction>>();
}

var componentNode = owner.FirstAncestorOrSelf<MarkupElementSyntax>();

// Make sure we've found tag
if (componentNode is null)
{
return SpecializedTasks.Null<IReadOnlyList<RazorVSInternalCodeAction>>();
}

// Do not provide code action if the cursor is inside proper html content (i.e. page text)
if (context.Location.AbsoluteIndex > componentNode.StartTag.Span.End &&
context.Location.AbsoluteIndex < componentNode.EndTag.SpanStart)
{
return SpecializedTasks.Null<IReadOnlyList<RazorVSInternalCodeAction>>();
}

if (!TryGetNamespace(context.CodeDocument, out var @namespace))
{
return SpecializedTasks.Null<IReadOnlyList<RazorVSInternalCodeAction>>();
}

var actionParams = new ExtractToNewComponentCodeActionParams()
{
Uri = context.Request.TextDocument.Uri,
ExtractStart = componentNode.Span.Start,
ExtractEnd = componentNode.Span.End,
Namespace = @namespace
};

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

var codeAction = RazorCodeActionFactory.CreateExtractToNewComponent(resolutionParams);
var codeActions = new List<RazorVSInternalCodeAction> { codeAction };

return Task.FromResult<IReadOnlyList<RazorVSInternalCodeAction>?>(codeActions);
}

private static bool TryGetNamespace(RazorCodeDocument codeDocument, [NotNullWhen(returnValue: true)] out string? @namespace)
// If the compiler can't provide a computed namespace it will fallback to "__GeneratedComponent" or
// similar for the NamespaceNode. This would end up with extracting to a wrong namespace
// and causing compiler errors. Avoid offering this refactoring if we can't accurately get a
// good namespace to extract to
=> codeDocument.TryComputeNamespace(fallbackToRootNamespace: true, out @namespace);

//private static bool HasUnsupportedChildren(Language.Syntax.SyntaxNode node)
//{
// return node.DescendantNodes().Any(static n => n is MarkupBlockSyntax or CSharpTransitionSyntax or RazorCommentBlockSyntax);
//}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this commented code be deleted?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was keeping it around in case I was to use it but I think I won't 😄

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.LanguageServer.CodeActions.Models;
using Microsoft.AspNetCore.Razor.LanguageServer.Hosting;
using Microsoft.AspNetCore.Razor.Utilities;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.CodeAnalysis.Razor.Protocol;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using Newtonsoft.Json.Linq;
using System.Globalization;
using System.Text.Json;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: sort using directives. (System using directives should go first).


namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions.Razor;
internal sealed class ExtractToNewComponentCodeActionResolver : IRazorCodeActionResolver
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Please add a blank line between the namespace and the class declaration.

{
private static readonly Workspace s_workspace = new AdhocWorkspace();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this static field. It's not used, and it's actually quite expensive.


private readonly IDocumentContextFactory _documentContextFactory;
private readonly LanguageServerFeatureOptions _languageServerFeatureOptions;
private readonly IClientConnection _clientConnection;
public ExtractToNewComponentCodeActionResolver(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Please add a blank line between the fields and the constructor.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider changing to a primary constructor (but keep the fields). There's a code action for that in Visual Studio.

IDocumentContextFactory documentContextFactory,
LanguageServerFeatureOptions languageServerFeatureOptions,
IClientConnection clientConnection)
{
_documentContextFactory = documentContextFactory ?? throw new ArgumentNullException(nameof(documentContextFactory));
_languageServerFeatureOptions = languageServerFeatureOptions ?? throw new ArgumentNullException(nameof(languageServerFeatureOptions));
_clientConnection = clientConnection ?? throw new ArgumentNullException(nameof(clientConnection));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These throw new ArgumentNullException(...) expressions can be removed. The DI container won't ever pass null when constructing this class.

}

public string Action => LanguageServerConstants.CodeActions.ExtractToNewComponentAction;

public async Task<WorkspaceEdit?> ResolveAsync(JsonElement data, CancellationToken cancellationToken)
{
if (data.ValueKind == JsonValueKind.Undefined)
{
return null;
}

var actionParams = JsonSerializer.Deserialize<ExtractToNewComponentCodeActionParams>(data.GetRawText());
if (actionParams is null)
{
return null;
}

if (!_documentContextFactory.TryCreate(actionParams.Uri, out var documentContext))
{
return null;
}

var componentDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false);
if (componentDocument.IsUnsupported())
{
return null;
}

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

var path = FilePathNormalizer.Normalize(actionParams.Uri.GetAbsoluteOrUNCPath());
var templatePath = Path.Combine(Path.GetDirectoryName(path), "Component");

Check failure on line 76 in src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs

View check run for this annotation

Azure Pipelines / razor-tooling-ci (Build macOS debug)

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs#L76

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs(76,41): error CS8604: (NETCORE_ENGINEERING_TELEMETRY=Build) Possible null reference argument for parameter 'path1' in 'string Path.Combine(string path1, string path2)'.

Check failure on line 76 in src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs

View check run for this annotation

Azure Pipelines / razor-tooling-ci (Build macOS release)

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs#L76

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs(76,41): error CS8604: (NETCORE_ENGINEERING_TELEMETRY=Build) Possible null reference argument for parameter 'path1' in 'string Path.Combine(string path1, string path2)'.

Check failure on line 76 in src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs

View check run for this annotation

Azure Pipelines / razor-tooling-ci (Build Linux debug)

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs#L76

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs(76,41): error CS8604: (NETCORE_ENGINEERING_TELEMETRY=Build) Possible null reference argument for parameter 'path1' in 'string Path.Combine(string path1, string path2)'.

Check failure on line 76 in src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs

View check run for this annotation

Azure Pipelines / razor-tooling-ci (Build Linux release)

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs#L76

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs(76,41): error CS8604: (NETCORE_ENGINEERING_TELEMETRY=Build) Possible null reference argument for parameter 'path1' in 'string Path.Combine(string path1, string path2)'.

Check failure on line 76 in src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs

View check run for this annotation

Azure Pipelines / razor-tooling-ci

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs#L76

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs(76,41): error CS8604: (NETCORE_ENGINEERING_TELEMETRY=Build) Possible null reference argument for parameter 'path1' in 'string Path.Combine(string path1, string path2)'.
var componentPath = FileUtilities.GenerateUniquePath(templatePath, ".razor");

// VS Code in Windows expects path to start with '/'
var updatedComponentPath = _languageServerFeatureOptions.ReturnCodeActionAndRenamePathsWithPrefixedSlash && !componentPath.StartsWith("/")
? '/' + componentPath
: componentPath;

var newComponentUri = new UriBuilder
{
Scheme = Uri.UriSchemeFile,
Path = updatedComponentPath,
Host = string.Empty,
}.Uri;
Comment on lines +78 to +83
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this UriBuilder pattern is used all over the Razor code base to produce file-schema URIs. If it were me, I would create a global helper and update all the places this pattern is used. However, that's definitely outside of the scope of this PR. Would you mind filing an issue on the repo to clean that tech-debt up?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for filing


var text = await documentContext.GetSourceTextAsync(cancellationToken).ConfigureAwait(false);
if (text is null)
{
return null;
}

var componentName = Path.GetFileNameWithoutExtension(componentPath);
var newComponentContent = text.GetSubTextString(new CodeAnalysis.Text.TextSpan(actionParams.ExtractStart, actionParams.ExtractEnd - actionParams.ExtractStart)).Trim();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to add a using directive for Microsoft.CodeAnalysis.Text rather than partially qualifying here?


var start = componentDocument.Source.Text.Lines.GetLinePosition(actionParams.ExtractStart);
var end = componentDocument.Source.Text.Lines.GetLinePosition(actionParams.ExtractEnd);
var removeRange = new Range
{
Start = new Position(start.Line, start.Character),
End = new Position(end.Line, end.Character)
};

var componentDocumentIdentifier = new OptionalVersionedTextDocumentIdentifier { Uri = actionParams.Uri };
var newComponentDocumentIdentifier = new OptionalVersionedTextDocumentIdentifier { Uri = newComponentUri };

var documentChanges = new SumType<TextDocumentEdit, CreateFile, RenameFile, DeleteFile>[]
{
new CreateFile { Uri = newComponentUri },
new TextDocumentEdit
{
TextDocument = componentDocumentIdentifier,
Edits = new[]
{
new TextEdit
{
NewText = $"<{componentName} />",
Range = removeRange,
}
},
},
new TextDocumentEdit
{
TextDocument = newComponentDocumentIdentifier,
Edits = new[]
{
new TextEdit
{
NewText = newComponentContent,
Range = new Range { Start = new Position(0, 0), End = new Position(0, 0) },
}
},
}
};

return new WorkspaceEdit
{
DocumentChanges = documentChanges,
};
}

/// <summary>
/// Generate a file path with adjacent to our input path that has the
/// correct code-behind extension, using numbers to differentiate from
/// any collisions.
/// </summary>
/// <param name="path">The origin file path.</param>
/// <returns>A non-existent file path with the same base name and a code-behind extension.</returns>
private static string GenerateComponentBehindPath(string path)

Check failure on line 153 in src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs

View check run for this annotation

Azure Pipelines / razor-tooling-ci (Build macOS debug)

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs#L153

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs(153,27): error IDE0051: (NETCORE_ENGINEERING_TELEMETRY=Build) Private member 'ExtractToNewComponentCodeActionResolver.GenerateComponentBehindPath' is unused (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0051)

Check failure on line 153 in src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs

View check run for this annotation

Azure Pipelines / razor-tooling-ci (Build macOS debug)

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs#L153

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs(153,27): error IDE0051: (NETCORE_ENGINEERING_TELEMETRY=Build) Private member 'ExtractToNewComponentCodeActionResolver.GenerateComponentBehindPath' is unused (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0051)

Check failure on line 153 in src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs

View check run for this annotation

Azure Pipelines / razor-tooling-ci (Build macOS release)

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs#L153

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs(153,27): error IDE0051: (NETCORE_ENGINEERING_TELEMETRY=Build) Private member 'ExtractToNewComponentCodeActionResolver.GenerateComponentBehindPath' is unused (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0051)

Check failure on line 153 in src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs

View check run for this annotation

Azure Pipelines / razor-tooling-ci (Build macOS release)

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs#L153

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs(153,27): error IDE0051: (NETCORE_ENGINEERING_TELEMETRY=Build) Private member 'ExtractToNewComponentCodeActionResolver.GenerateComponentBehindPath' is unused (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0051)

Check failure on line 153 in src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs

View check run for this annotation

Azure Pipelines / razor-tooling-ci (Build Linux debug)

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs#L153

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs(153,27): error IDE0051: (NETCORE_ENGINEERING_TELEMETRY=Build) Private member 'ExtractToNewComponentCodeActionResolver.GenerateComponentBehindPath' is unused (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0051)

Check failure on line 153 in src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs

View check run for this annotation

Azure Pipelines / razor-tooling-ci (Build Linux debug)

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs#L153

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs(153,27): error IDE0051: (NETCORE_ENGINEERING_TELEMETRY=Build) Private member 'ExtractToNewComponentCodeActionResolver.GenerateComponentBehindPath' is unused (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0051)

Check failure on line 153 in src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs

View check run for this annotation

Azure Pipelines / razor-tooling-ci (Build Linux release)

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs#L153

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs(153,27): error IDE0051: (NETCORE_ENGINEERING_TELEMETRY=Build) Private member 'ExtractToNewComponentCodeActionResolver.GenerateComponentBehindPath' is unused (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0051)

Check failure on line 153 in src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs

View check run for this annotation

Azure Pipelines / razor-tooling-ci (Build Linux release)

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs#L153

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs(153,27): error IDE0051: (NETCORE_ENGINEERING_TELEMETRY=Build) Private member 'ExtractToNewComponentCodeActionResolver.GenerateComponentBehindPath' is unused (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0051)

Check failure on line 153 in src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs

View check run for this annotation

Azure Pipelines / razor-tooling-ci

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs#L153

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs(153,27): error IDE0051: (NETCORE_ENGINEERING_TELEMETRY=Build) Private member 'ExtractToNewComponentCodeActionResolver.GenerateComponentBehindPath' is unused (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0051)

Check failure on line 153 in src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs

View check run for this annotation

Azure Pipelines / razor-tooling-ci

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs#L153

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs(153,27): error IDE0051: (NETCORE_ENGINEERING_TELEMETRY=Build) Private member 'ExtractToNewComponentCodeActionResolver.GenerateComponentBehindPath' is unused (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0051)

Check failure on line 153 in src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs

View check run for this annotation

Azure Pipelines / razor-tooling-ci

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs#L153

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToNewComponentCodeActionResolver.cs(153,27): error IDE0051: (NETCORE_ENGINEERING_TELEMETRY=Build) Private member 'ExtractToNewComponentCodeActionResolver.GenerateComponentBehindPath' is unused (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0051)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably should move this to a helper class. I'm assuming extract to code behind also does this?

{
var directoryName = Path.GetDirectoryName(path);

var n = 0;
string componentBehindPath;
do
{
var identifier = n > 0 ? n.ToString(CultureInfo.InvariantCulture) : string.Empty; // Make it look nice
Assumes.NotNull(directoryName);

componentBehindPath = Path.Combine(
directoryName,
$"Component{identifier}.razor");
n++;
}
while (File.Exists(componentBehindPath));

return componentBehindPath;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ internal static class RazorCodeActionFactory
private readonly static Guid s_fullyQualifyComponentTelemetryId = new("3d9abe36-7d10-4e08-8c18-ad88baa9a923");
private readonly static Guid s_createComponentFromTagTelemetryId = new("a28e0baa-a4d5-4953-a817-1db586035841");
private readonly static Guid s_createExtractToCodeBehindTelemetryId = new("f63167f7-fdc6-450f-8b7b-b240892f4a27");
private readonly static Guid s_createExtractToNewComponentTelemetryId = new("af67b0a3-f84b-4808-97a7-b53e85b22c64");
private readonly static Guid s_generateMethodTelemetryId = new("c14fa003-c752-45fc-bb29-3a123ae5ecef");
private readonly static Guid s_generateAsyncMethodTelemetryId = new("9058ca47-98e2-4f11-bf7c-a16a444dd939");

Expand Down Expand Up @@ -67,6 +68,19 @@ public static RazorVSInternalCodeAction CreateExtractToCodeBehind(RazorCodeActio
return codeAction;
}

public static RazorVSInternalCodeAction CreateExtractToNewComponent(RazorCodeActionResolutionParams resolutionParams)
{
var title = SR.ExtractTo_NewComponent_Title;
var data = JsonSerializer.SerializeToElement(resolutionParams);
var codeAction = new RazorVSInternalCodeAction()
{
Title = title,
Data = data,
TelemetryId = s_createExtractToNewComponentTelemetryId,
};
return codeAction;
}

public static RazorVSInternalCodeAction CreateGenerateMethod(Uri uri, string methodName, string eventName)
{
var @params = new GenerateMethodCodeActionParams
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ public static void AddCodeActionsServices(this IServiceCollection services)
// Razor Code actions
services.AddSingleton<IRazorCodeActionProvider, ExtractToCodeBehindCodeActionProvider>();
services.AddSingleton<IRazorCodeActionResolver, ExtractToCodeBehindCodeActionResolver>();
services.AddSingleton<IRazorCodeActionProvider, ExtractToNewComponentCodeActionProvider>();
services.AddSingleton<IRazorCodeActionResolver ,ExtractToNewComponentCodeActionResolver>();
services.AddSingleton<IRazorCodeActionProvider, ComponentAccessibilityCodeActionProvider>();
services.AddSingleton<IRazorCodeActionResolver, CreateComponentCodeActionResolver>();
services.AddSingleton<IRazorCodeActionResolver, AddUsingsCodeActionResolver>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,4 +183,7 @@
<data name="Statement" xml:space="preserve">
<value>statement</value>
</data>
<data name="ExtractTo_NewComponent_Title" xml:space="preserve">
<value>Extract element to new component</value>
</data>
</root>

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading