Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ dotnet_diagnostic.SA1600.severity = none
dotnet_diagnostic.SA1601.severity = none
dotnet_diagnostic.SA1602.severity = none
dotnet_diagnostic.SA1611.severity = none
dotnet_diagnostic.SA1615.severity = none
dotnet_diagnostic.SA1623.severity = none
dotnet_diagnostic.SA1629.severity = none
dotnet_diagnostic.SA1615.severity = warning
dotnet_diagnostic.SA1623.severity = warning
dotnet_diagnostic.SA1629.severity = warning
Comment thread
daviburg marked this conversation as resolved.
dotnet_diagnostic.SA1633.severity = none

# StyleCop: disable member ordering rules (SA1201-SA1214)
Expand Down Expand Up @@ -110,3 +110,4 @@ dotnet_diagnostic.CA1307.severity = warning
dotnet_diagnostic.CA1310.severity = warning



2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Enforce LF line endings for all text files (matches .editorconfig end_of_line = lf)
* text=auto eol=lf
2 changes: 1 addition & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ public async Task<Response> ProcessAsync(Request request)
**Rules:**

- End descriptions with period
- Do NOT document return values (`<returns>` tag)
- Document return values with `<returns>` tags on all public methods that return a value (non-void)
- Use `<see cref="ClassName"/>` for type references

### Exception Handling
Expand Down
1 change: 1 addition & 0 deletions Server/BufferManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public bool RemoveBuffer(string documentPath)
/// Gets all currently tracked document URIs and their contents.
/// Used to re-trigger diagnostics when external state (e.g., connections) changes.
/// </summary>
/// <returns>A snapshot of all tracked document URIs and their contents.</returns>
public IReadOnlyDictionary<string, string> GetAllBuffers()
{
return new Dictionary<string, string>(this.buffers, this.buffers.Comparer);
Expand Down
1 change: 1 addition & 0 deletions Server/Diagnostics/DiagnosticPublisher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ public DiagnosticPublisher(
/// <param name="documentUri">The URI of the document to validate.</param>
/// <param name="documentText">The full text of the document.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>A task that represents the asynchronous publish operation.</returns>
public async Task PublishDiagnosticsAsync(
DocumentUri documentUri,
string documentText,
Expand Down
1 change: 1 addition & 0 deletions Server/Diagnostics/IDiagnosticValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ internal interface IDiagnosticValidator
/// <param name="documentText">The full text content of the document.</param>
/// <param name="sdkIndex">The SDK index for type and assembly lookups. May be null if the SDK failed to load.</param>
/// <param name="cancellationToken">Cancellation token to abort analysis.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the list of diagnostics found.</returns>
Task<IReadOnlyList<OmniSharp.Extensions.LanguageServer.Protocol.Models.Diagnostic>> ValidateAsync(
DocumentUri documentUri,
string documentText,
Expand Down
1 change: 1 addition & 0 deletions Server/Diagnostics/LevenshteinDistance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ internal static class LevenshteinDistance
/// </summary>
/// <param name="source">The source string.</param>
/// <param name="target">The target string.</param>
/// <returns>The Levenshtein distance between the two strings.</returns>
public static int Compute(string source, string target)
{
if (string.IsNullOrEmpty(source))
Expand Down
8 changes: 8 additions & 0 deletions Server/Diagnostics/Validators/ValidatorHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ internal static class ValidatorHelpers
/// <summary>
/// Finds a named argument in an attribute by parameter name.
/// </summary>
/// <returns>The matching attribute argument, or <see langword="null"/> if not found.</returns>
public static AttributeArgumentSyntax? FindNamedArgument(AttributeSyntax attribute, string parameterName)
{
if (attribute.ArgumentList is null)
Expand All @@ -42,6 +43,7 @@ argument.NameEquals is not null &&
/// For bare identifiers, returns the identifier text. This is a purely syntactic
/// extraction — no semantic constant evaluation is performed.
/// </summary>
/// <returns>The extracted string value, or <see langword="null"/> if the expression is not a recognized form.</returns>
public static string? ExtractStringValue(AttributeArgumentSyntax argument)
{
if (argument.Expression is LiteralExpressionSyntax literal &&
Expand All @@ -68,6 +70,7 @@ argument.NameEquals is not null &&
/// For example, "MyNamespace.ConnectorTriggerMetadata" and
/// "global::ConnectorTriggerMetadata" both return "ConnectorTriggerMetadata".
/// </summary>
/// <returns>The rightmost identifier portion of the attribute name.</returns>
public static string ExtractRightmostIdentifier(string attributeName)
{
int lastDot = attributeName.LastIndexOf('.');
Expand All @@ -87,6 +90,7 @@ public static string ExtractRightmostIdentifier(string attributeName)
/// <summary>
/// Determines whether the attribute name matches [ConnectorTriggerMetadata] or [ConnectorTrigger].
/// </summary>
/// <returns><see langword="true"/> if the attribute name matches a trigger metadata attribute; otherwise, <see langword="false"/>.</returns>
public static bool IsTriggerMetadataAttribute(string attributeName)
{
string identifier = ValidatorHelpers.ExtractRightmostIdentifier(attributeName);
Expand All @@ -99,6 +103,7 @@ public static bool IsTriggerMetadataAttribute(string attributeName)
/// <summary>
/// Converts a Roslyn <see cref="TextSpan"/> to an LSP <see cref="LspRange"/>.
/// </summary>
/// <returns>The equivalent LSP range.</returns>
public static LspRange ToLspRange(TextSpan span, SourceText sourceText)
{
LinePosition start = sourceText.Lines.GetLinePosition(span.Start);
Expand All @@ -112,6 +117,7 @@ public static LspRange ToLspRange(TextSpan span, SourceText sourceText)
/// <summary>
/// Gets the LSP range covering the attribute name for diagnostic placement.
/// </summary>
/// <returns>The LSP range covering the attribute name.</returns>
public static LspRange GetAttributeNameRange(AttributeSyntax attribute, SourceText sourceText)
{
TextSpan span = attribute.Name.Span;
Expand All @@ -121,6 +127,7 @@ public static LspRange GetAttributeNameRange(AttributeSyntax attribute, SourceTe
/// <summary>
/// Gets the LSP range covering the argument value expression for diagnostic placement.
/// </summary>
/// <returns>The LSP range covering the argument value expression.</returns>
public static LspRange GetArgumentValueRange(AttributeArgumentSyntax argument, SourceText sourceText)
{
TextSpan span = argument.Expression.Span;
Expand All @@ -130,6 +137,7 @@ public static LspRange GetArgumentValueRange(AttributeArgumentSyntax argument, S
/// <summary>
/// Creates an LSP diagnostic with standard source.
/// </summary>
/// <returns>A new LSP diagnostic with the specified properties.</returns>
public static LspDiagnostic CreateDiagnostic(
LspRange range,
LspDiagnosticSeverity severity,
Expand Down
3 changes: 3 additions & 0 deletions Server/DynamicValuesHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ internal static class DynamicValuesHelper
/// Gets the count of connections matching a connector type.
/// Used for diagnostic logging when resolution fails due to multiple matches.
/// </summary>
/// <returns>The number of matching connections.</returns>
public static int GetConnectionCountForConnector(ConnectionsService connectionsService, string connectorName)
{
ConnectionsConfig? connections = connectionsService.GetConnections();
Expand All @@ -45,6 +46,7 @@ public static int GetConnectionCountForConnector(ConnectionsService connectionsS
/// Checks if a connection name is a valid connection key in the connections config.
/// Returns false for values that look like method arguments (URLs, IDs) rather than connection keys.
/// </summary>
/// <returns><see langword="true"/> if the connection name is a valid key; otherwise, <see langword="false"/>.</returns>
public static bool IsValidConnectionKey(ConnectionsService connectionsService, string connectionName)
{
ConnectionsConfig? connections = connectionsService.GetConnections();
Expand Down Expand Up @@ -93,6 +95,7 @@ public static (string? Url, bool IsDirectClient) BuildApiUrl(
/// Infers the connector name from a method's containing type by stripping known suffixes.
/// For example: SharePointOnlineClient -> sharepointonline, TeamsClient -> teams.
/// </summary>
/// <returns>The inferred connector name in lowercase, or <see langword="null"/> if it cannot be determined.</returns>
public static string? InferConnectorFromContainingType(string? containingTypeName)
{
if (string.IsNullOrEmpty(containingTypeName))
Expand Down
1 change: 1 addition & 0 deletions Server/ExceptionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ internal static class ExceptionExtensions
/// Determines whether the exception is fatal and should not be caught.
/// </summary>
/// <param name="exception">The exception to check.</param>
/// <returns><see langword="true"/> if the exception is fatal; otherwise, <see langword="false"/>.</returns>
public static bool IsFatal(this Exception exception)
{
ArgumentNullException.ThrowIfNull(exception);
Expand Down
2 changes: 2 additions & 0 deletions Server/Handlers/CodeActionHandler/DynamicSchemaCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ internal static class DynamicSchemaCache
/// <summary>
/// Builds a complete cache from all SDK assemblies: type name → operationId.
/// </summary>
/// <returns>A dictionary mapping type names to operation IDs.</returns>
public static Dictionary<string, string> Build(IEnumerable<string> assemblyPaths)
{
var result = new Dictionary<string, string>(StringComparer.Ordinal);
Expand All @@ -34,6 +35,7 @@ public static Dictionary<string, string> Build(IEnumerable<string> assemblyPaths
/// Scans a single assembly for types with [DynamicSchema("operationId")] and returns
/// a dictionary of simple type name → operationId.
/// </summary>
/// <returns>A dictionary mapping type names to operation IDs from the assembly.</returns>
public static Dictionary<string, string> ScanAssemblyForDynamicSchema(string assemblyPath)
{
var result = new Dictionary<string, string>(StringComparer.Ordinal);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ protected override CodeActionRegistrationOptions CreateRegistrationOptions(
/// Uses syntax tree parsing and a cached SdkIndex type name + [DynamicSchema] operationId lookup.
/// Schema fetch and code generation happen in GenerateDynamicSchemaCommandHandler when clicked.
/// </summary>
/// <returns>The detected dynamic schema type info, or <see langword="null"/> if the cursor is not on a dynamic type.</returns>
internal DynamicSchemaTypeInfo? DetectDynamicSchemaType(
string documentText,
OmniSharp.Extensions.LanguageServer.Protocol.Models.Range range,
Expand Down Expand Up @@ -305,6 +306,7 @@ private static Dictionary<string, string> BuildCacheFromSdkIndex(SdkIndex? sdkIn
/// Generates a clean class name from the dynamic type name.
/// E.g., "DynamicPostMessageRequest" → "PostMessageInput".
/// </summary>
/// <returns>The generated class name.</returns>
internal static string GenerateClassName(string dynamicTypeName)
{
string name = dynamicTypeName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ protected override ExecuteCommandRegistrationOptions CreateRegistrationOptions(
/// <c>new GeneratedClassName()</c> in the source document. Does not modify
/// AdditionalProperties access — those still work via inheritance.
/// </summary>
/// <returns>The updated document text with dynamic type instantiations replaced.</returns>
internal static string ApplySourceCodeUpdate(
string documentText,
string dynamicTypeName,
Expand Down
3 changes: 3 additions & 0 deletions Server/Handlers/CodeActionHandler/SchemaToClassGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ internal static class SchemaToClassGenerator
/// <param name="baseClassNamespace">The namespace of the base class.</param>
/// <param name="schema">The JSON Schema describing the properties.</param>
/// <param name="targetNamespace">The namespace for the generated class.</param>
/// <returns>The generated C# class source code.</returns>
public static string GenerateClass(
string className,
string baseClassName,
Expand Down Expand Up @@ -116,6 +117,7 @@ internal static void GenerateClassBody(
/// Maps a JSON Schema type to a C# type string. For nested objects with properties,
/// generates a new class and returns its name.
/// </summary>
/// <returns>The C# type string corresponding to the JSON Schema type.</returns>
internal static string ResolveCSharpType(JsonElement schema, string propertyName, List<string> nestedClasses)
{
string? schemaType = null;
Expand Down Expand Up @@ -196,6 +198,7 @@ private static string ResolveArrayType(JsonElement schema, string propertyName,
/// <summary>
/// Converts a camelCase or snake_case JSON property name to PascalCase.
/// </summary>
/// <returns>The PascalCase string.</returns>
internal static string ToPascalCase(string jsonName)
{
if (string.IsNullOrEmpty(jsonName))
Expand Down
2 changes: 2 additions & 0 deletions Server/Handlers/CompletionHandler/CompletionHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,7 @@ private static bool TryExtractAttributeParameterName(string linePrefix, out stri
/// Reads a sibling parameter value from an AttributeSyntax.
/// For example, reading "ConnectorName" when the cursor is at "OperationName".
/// </summary>
/// <returns>The parameter value, or <see langword="null"/> if not found.</returns>
internal static string? ReadSiblingAttributeParameterValue(AttributeSyntax attribute, string parameterName)
{
if (attribute.ArgumentList is null)
Expand Down Expand Up @@ -978,6 +979,7 @@ private static bool TryExtractAttributeParameterName(string linePrefix, out stri
/// When the context window contains multiple attributes (e.g., stacked trigger methods),
/// narrows the search to the last attribute to avoid reading values from the wrong one.
/// </summary>
/// <returns>The extracted parameter value, or <see langword="null"/> if not found.</returns>
internal static string? ExtractParameterValueFromText(string contextText, string parameterName)
{
// Narrow to the last attribute in the context so we don't match
Expand Down
2 changes: 1 addition & 1 deletion Server/Handlers/HoverHandler/HoverHandlerTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ internal class DynamicInvokeRequest

/// <summary>
/// Generic response from API Hub runtime endpoints that return a list of items.
/// Shape: { "value": [ { "Name": "...", "DisplayName": "..." }, ... ] }
/// Shape: { "value": [ { "Name": "...", "DisplayName": "..." }, ... ] }.
/// </summary>
internal class DynamicValuesListResponse
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,7 @@ private static string GetFullTypeName(INamedTypeSymbol typeSymbol)
/// Looks up operation metadata directly from the JSON configuration file.
/// Used by DynamicOperationsRegistry as a fallback when SDK discovery doesn't find an operation.
/// </summary>
/// <returns>The operation metadata, or <see langword="null"/> if not found in the configuration.</returns>
public static DynamicOperationMetadata? GetOperationFromConfig(string connectorName, string operationName)
{
string key = $"{connectorName.ToLowerInvariant()}:{operationName}";
Expand Down
1 change: 1 addition & 0 deletions Server/LogSanitizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ internal static partial class LogSanitizer
/// Redacts sensitive segments from URLs and identifiers commonly found in
/// Azure API Hub URLs, ARM resource paths, and connection runtime URLs.
/// </summary>
/// <returns>The sanitized URL with sensitive segments redacted.</returns>
public static string SanitizeUrl(string url)
{
// Redact subscription IDs: /subscriptions/{guid-or-id}/
Expand Down
5 changes: 5 additions & 0 deletions Server/SdkIndex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ private SdkIndex(
/// Creates an <see cref="SdkIndex"/> with explicit connector names and trigger operations.
/// Intended for unit testing only.
/// </summary>
/// <returns>A new <see cref="SdkIndex"/> instance for testing.</returns>
internal static SdkIndex CreateForTesting(
IEnumerable<SdkConstant> connectorNames,
IDictionary<string, ImmutableArray<SdkConstant>> triggerOperations,
Expand All @@ -125,6 +126,7 @@ internal static SdkIndex CreateForTesting(
/// <summary>
/// Gets trigger operations for a specific connector name (case-insensitive).
/// </summary>
/// <returns>The trigger operations for the connector, or an empty array if none exist.</returns>
public ImmutableArray<SdkConstant> GetTriggerOperations(string connectorName)
{
return TriggerOperationsByConnector.TryGetValue(connectorName, out ImmutableArray<SdkConstant> operations)
Expand All @@ -135,6 +137,7 @@ public ImmutableArray<SdkConstant> GetTriggerOperations(string connectorName)
/// <summary>
/// Gets all trigger operations from all connectors.
/// </summary>
/// <returns>All trigger operations across all connectors.</returns>
public IEnumerable<SdkConstant> GetAllTriggerOperations()
{
return TriggerOperationsByConnector.Values.SelectMany(operations => operations);
Expand All @@ -144,6 +147,7 @@ public IEnumerable<SdkConstant> GetAllTriggerOperations()
/// Maps an operation name to its corresponding TriggerPayload type name.
/// Convention: {Connector}{OperationName}TriggerPayload.
/// </summary>
/// <returns>The payload type name, or <see langword="null"/> if the operation is not found.</returns>
public string? GetPayloadTypeForOperation(string connectorName, string operationName)
{
if (!TriggerOperationsByConnector.TryGetValue(connectorName, out ImmutableArray<SdkConstant> operations) || operations.IsEmpty)
Expand Down Expand Up @@ -202,6 +206,7 @@ public IEnumerable<SdkConstant> GetAllTriggerOperations()
/// are read directly via MetadataLoadContext.
/// </summary>
/// <param name="assemblyPaths">One or more paths to SDK assembly DLLs.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the created <see cref="SdkIndex"/>, or <see langword="null"/> if creation failed.</returns>
public static async Task<SdkIndex?> TryCreateFromAssembliesAsync(params string[] assemblyPaths)
{
if (assemblyPaths is null || assemblyPaths.Length == 0)
Expand Down
2 changes: 1 addition & 1 deletion Server/Services/Api/ApiServiceConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class ApiServiceConfig
public string ApiVersion { get; set; } = string.Empty;

/// <summary>
/// Returns the API version to use: the configured value, or the default if not set.
/// Gets the API version to use: the configured value, or the default if not set.
/// </summary>
[JsonIgnore]
public string EffectiveApiVersion =>
Expand Down
2 changes: 1 addition & 1 deletion Server/Services/CodeLens/CodeLensConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace SdkLspServer.Services.CodeLens;
public class CodeLensConfig
{
/// <summary>
/// The VS Code command name invoked when the user clicks a "Create connection" CodeLens.
/// Gets or sets the VS Code command name invoked when the user clicks a "Create connection" CodeLens.
/// Defaults to a generic command name; the client extension should register this command.
/// </summary>
[JsonPropertyName("openConnectionViewCommand")]
Expand Down
Loading
Loading