diff --git a/.editorconfig b/.editorconfig index c2fa1dd..d01b3fc 100644 --- a/.editorconfig +++ b/.editorconfig @@ -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 dotnet_diagnostic.SA1633.severity = none # StyleCop: disable member ordering rules (SA1201-SA1214) @@ -110,3 +110,4 @@ dotnet_diagnostic.CA1307.severity = warning dotnet_diagnostic.CA1310.severity = warning + diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..559f3b5 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Enforce LF line endings for all text files (matches .editorconfig end_of_line = lf) +* text=auto eol=lf diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 7e22032..7523fac 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -146,7 +146,7 @@ public async Task ProcessAsync(Request request) **Rules:** - End descriptions with period -- Do NOT document return values (`` tag) +- Document return values with `` tags on all public methods that return a value (non-void) - Use `` for type references ### Exception Handling diff --git a/Server/BufferManager.cs b/Server/BufferManager.cs index 31e9170..af95cfb 100644 --- a/Server/BufferManager.cs +++ b/Server/BufferManager.cs @@ -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. /// + /// A snapshot of all tracked document URIs and their contents. public IReadOnlyDictionary GetAllBuffers() { return new Dictionary(this.buffers, this.buffers.Comparer); diff --git a/Server/Diagnostics/DiagnosticPublisher.cs b/Server/Diagnostics/DiagnosticPublisher.cs index 5ccb724..a2937ad 100644 --- a/Server/Diagnostics/DiagnosticPublisher.cs +++ b/Server/Diagnostics/DiagnosticPublisher.cs @@ -82,6 +82,7 @@ public DiagnosticPublisher( /// The URI of the document to validate. /// The full text of the document. /// Cancellation token. + /// A task that represents the asynchronous publish operation. public async Task PublishDiagnosticsAsync( DocumentUri documentUri, string documentText, diff --git a/Server/Diagnostics/IDiagnosticValidator.cs b/Server/Diagnostics/IDiagnosticValidator.cs index f7e0277..bfd42eb 100644 --- a/Server/Diagnostics/IDiagnosticValidator.cs +++ b/Server/Diagnostics/IDiagnosticValidator.cs @@ -20,6 +20,7 @@ internal interface IDiagnosticValidator /// The full text content of the document. /// The SDK index for type and assembly lookups. May be null if the SDK failed to load. /// Cancellation token to abort analysis. + /// A task that represents the asynchronous operation. The task result contains the list of diagnostics found. Task> ValidateAsync( DocumentUri documentUri, string documentText, diff --git a/Server/Diagnostics/LevenshteinDistance.cs b/Server/Diagnostics/LevenshteinDistance.cs index 69d0896..611c83f 100644 --- a/Server/Diagnostics/LevenshteinDistance.cs +++ b/Server/Diagnostics/LevenshteinDistance.cs @@ -17,6 +17,7 @@ internal static class LevenshteinDistance /// /// The source string. /// The target string. + /// The Levenshtein distance between the two strings. public static int Compute(string source, string target) { if (string.IsNullOrEmpty(source)) diff --git a/Server/Diagnostics/Validators/ValidatorHelpers.cs b/Server/Diagnostics/Validators/ValidatorHelpers.cs index a5f8cda..4764364 100644 --- a/Server/Diagnostics/Validators/ValidatorHelpers.cs +++ b/Server/Diagnostics/Validators/ValidatorHelpers.cs @@ -23,6 +23,7 @@ internal static class ValidatorHelpers /// /// Finds a named argument in an attribute by parameter name. /// + /// The matching attribute argument, or if not found. public static AttributeArgumentSyntax? FindNamedArgument(AttributeSyntax attribute, string parameterName) { if (attribute.ArgumentList is null) @@ -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. /// + /// The extracted string value, or if the expression is not a recognized form. public static string? ExtractStringValue(AttributeArgumentSyntax argument) { if (argument.Expression is LiteralExpressionSyntax literal && @@ -68,6 +70,7 @@ argument.NameEquals is not null && /// For example, "MyNamespace.ConnectorTriggerMetadata" and /// "global::ConnectorTriggerMetadata" both return "ConnectorTriggerMetadata". /// + /// The rightmost identifier portion of the attribute name. public static string ExtractRightmostIdentifier(string attributeName) { int lastDot = attributeName.LastIndexOf('.'); @@ -87,6 +90,7 @@ public static string ExtractRightmostIdentifier(string attributeName) /// /// Determines whether the attribute name matches [ConnectorTriggerMetadata] or [ConnectorTrigger]. /// + /// if the attribute name matches a trigger metadata attribute; otherwise, . public static bool IsTriggerMetadataAttribute(string attributeName) { string identifier = ValidatorHelpers.ExtractRightmostIdentifier(attributeName); @@ -99,6 +103,7 @@ public static bool IsTriggerMetadataAttribute(string attributeName) /// /// Converts a Roslyn to an LSP . /// + /// The equivalent LSP range. public static LspRange ToLspRange(TextSpan span, SourceText sourceText) { LinePosition start = sourceText.Lines.GetLinePosition(span.Start); @@ -112,6 +117,7 @@ public static LspRange ToLspRange(TextSpan span, SourceText sourceText) /// /// Gets the LSP range covering the attribute name for diagnostic placement. /// + /// The LSP range covering the attribute name. public static LspRange GetAttributeNameRange(AttributeSyntax attribute, SourceText sourceText) { TextSpan span = attribute.Name.Span; @@ -121,6 +127,7 @@ public static LspRange GetAttributeNameRange(AttributeSyntax attribute, SourceTe /// /// Gets the LSP range covering the argument value expression for diagnostic placement. /// + /// The LSP range covering the argument value expression. public static LspRange GetArgumentValueRange(AttributeArgumentSyntax argument, SourceText sourceText) { TextSpan span = argument.Expression.Span; @@ -130,6 +137,7 @@ public static LspRange GetArgumentValueRange(AttributeArgumentSyntax argument, S /// /// Creates an LSP diagnostic with standard source. /// + /// A new LSP diagnostic with the specified properties. public static LspDiagnostic CreateDiagnostic( LspRange range, LspDiagnosticSeverity severity, diff --git a/Server/DynamicValuesHelper.cs b/Server/DynamicValuesHelper.cs index 74b867a..f875150 100644 --- a/Server/DynamicValuesHelper.cs +++ b/Server/DynamicValuesHelper.cs @@ -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. /// + /// The number of matching connections. public static int GetConnectionCountForConnector(ConnectionsService connectionsService, string connectorName) { ConnectionsConfig? connections = connectionsService.GetConnections(); @@ -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. /// + /// if the connection name is a valid key; otherwise, . public static bool IsValidConnectionKey(ConnectionsService connectionsService, string connectionName) { ConnectionsConfig? connections = connectionsService.GetConnections(); @@ -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. /// + /// The inferred connector name in lowercase, or if it cannot be determined. public static string? InferConnectorFromContainingType(string? containingTypeName) { if (string.IsNullOrEmpty(containingTypeName)) diff --git a/Server/ExceptionExtensions.cs b/Server/ExceptionExtensions.cs index 8ef2e0f..c8a681b 100644 --- a/Server/ExceptionExtensions.cs +++ b/Server/ExceptionExtensions.cs @@ -15,6 +15,7 @@ internal static class ExceptionExtensions /// Determines whether the exception is fatal and should not be caught. /// /// The exception to check. + /// if the exception is fatal; otherwise, . public static bool IsFatal(this Exception exception) { ArgumentNullException.ThrowIfNull(exception); diff --git a/Server/Handlers/CodeActionHandler/DynamicSchemaCache.cs b/Server/Handlers/CodeActionHandler/DynamicSchemaCache.cs index 9e39f98..87cdaa2 100644 --- a/Server/Handlers/CodeActionHandler/DynamicSchemaCache.cs +++ b/Server/Handlers/CodeActionHandler/DynamicSchemaCache.cs @@ -14,6 +14,7 @@ internal static class DynamicSchemaCache /// /// Builds a complete cache from all SDK assemblies: type name → operationId. /// + /// A dictionary mapping type names to operation IDs. public static Dictionary Build(IEnumerable assemblyPaths) { var result = new Dictionary(StringComparer.Ordinal); @@ -34,6 +35,7 @@ public static Dictionary Build(IEnumerable assemblyPaths /// Scans a single assembly for types with [DynamicSchema("operationId")] and returns /// a dictionary of simple type name → operationId. /// + /// A dictionary mapping type names to operation IDs from the assembly. public static Dictionary ScanAssemblyForDynamicSchema(string assemblyPath) { var result = new Dictionary(StringComparer.Ordinal); diff --git a/Server/Handlers/CodeActionHandler/DynamicSchemaCodeActionHandler.cs b/Server/Handlers/CodeActionHandler/DynamicSchemaCodeActionHandler.cs index 59b9958..bedf5c5 100644 --- a/Server/Handlers/CodeActionHandler/DynamicSchemaCodeActionHandler.cs +++ b/Server/Handlers/CodeActionHandler/DynamicSchemaCodeActionHandler.cs @@ -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. /// + /// The detected dynamic schema type info, or if the cursor is not on a dynamic type. internal DynamicSchemaTypeInfo? DetectDynamicSchemaType( string documentText, OmniSharp.Extensions.LanguageServer.Protocol.Models.Range range, @@ -305,6 +306,7 @@ private static Dictionary BuildCacheFromSdkIndex(SdkIndex? sdkIn /// Generates a clean class name from the dynamic type name. /// E.g., "DynamicPostMessageRequest" → "PostMessageInput". /// + /// The generated class name. internal static string GenerateClassName(string dynamicTypeName) { string name = dynamicTypeName; diff --git a/Server/Handlers/CodeActionHandler/GenerateDynamicSchemaCommandHandler.cs b/Server/Handlers/CodeActionHandler/GenerateDynamicSchemaCommandHandler.cs index d7f8bdb..44d2d6f 100644 --- a/Server/Handlers/CodeActionHandler/GenerateDynamicSchemaCommandHandler.cs +++ b/Server/Handlers/CodeActionHandler/GenerateDynamicSchemaCommandHandler.cs @@ -191,6 +191,7 @@ protected override ExecuteCommandRegistrationOptions CreateRegistrationOptions( /// new GeneratedClassName() in the source document. Does not modify /// AdditionalProperties access — those still work via inheritance. /// + /// The updated document text with dynamic type instantiations replaced. internal static string ApplySourceCodeUpdate( string documentText, string dynamicTypeName, diff --git a/Server/Handlers/CodeActionHandler/SchemaToClassGenerator.cs b/Server/Handlers/CodeActionHandler/SchemaToClassGenerator.cs index 8a66f74..49398d0 100644 --- a/Server/Handlers/CodeActionHandler/SchemaToClassGenerator.cs +++ b/Server/Handlers/CodeActionHandler/SchemaToClassGenerator.cs @@ -18,6 +18,7 @@ internal static class SchemaToClassGenerator /// The namespace of the base class. /// The JSON Schema describing the properties. /// The namespace for the generated class. + /// The generated C# class source code. public static string GenerateClass( string className, string baseClassName, @@ -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. /// + /// The C# type string corresponding to the JSON Schema type. internal static string ResolveCSharpType(JsonElement schema, string propertyName, List nestedClasses) { string? schemaType = null; @@ -196,6 +198,7 @@ private static string ResolveArrayType(JsonElement schema, string propertyName, /// /// Converts a camelCase or snake_case JSON property name to PascalCase. /// + /// The PascalCase string. internal static string ToPascalCase(string jsonName) { if (string.IsNullOrEmpty(jsonName)) diff --git a/Server/Handlers/CompletionHandler/CompletionHandler.cs b/Server/Handlers/CompletionHandler/CompletionHandler.cs index 1b0db08..268838b 100644 --- a/Server/Handlers/CompletionHandler/CompletionHandler.cs +++ b/Server/Handlers/CompletionHandler/CompletionHandler.cs @@ -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". /// + /// The parameter value, or if not found. internal static string? ReadSiblingAttributeParameterValue(AttributeSyntax attribute, string parameterName) { if (attribute.ArgumentList is null) @@ -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. /// + /// The extracted parameter value, or if not found. internal static string? ExtractParameterValueFromText(string contextText, string parameterName) { // Narrow to the last attribute in the context so we don't match diff --git a/Server/Handlers/HoverHandler/HoverHandlerTypes.cs b/Server/Handlers/HoverHandler/HoverHandlerTypes.cs index 52ca49d..694c39b 100644 --- a/Server/Handlers/HoverHandler/HoverHandlerTypes.cs +++ b/Server/Handlers/HoverHandler/HoverHandlerTypes.cs @@ -159,7 +159,7 @@ internal class DynamicInvokeRequest /// /// Generic response from API Hub runtime endpoints that return a list of items. - /// Shape: { "value": [ { "Name": "...", "DisplayName": "..." }, ... ] } + /// Shape: { "value": [ { "Name": "...", "DisplayName": "..." }, ... ] }. /// internal class DynamicValuesListResponse { diff --git a/Server/Handlers/HoverHandler/SdkDynamicOperationsDiscovery.cs b/Server/Handlers/HoverHandler/SdkDynamicOperationsDiscovery.cs index c04a372..8a56112 100644 --- a/Server/Handlers/HoverHandler/SdkDynamicOperationsDiscovery.cs +++ b/Server/Handlers/HoverHandler/SdkDynamicOperationsDiscovery.cs @@ -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. /// + /// The operation metadata, or if not found in the configuration. public static DynamicOperationMetadata? GetOperationFromConfig(string connectorName, string operationName) { string key = $"{connectorName.ToLowerInvariant()}:{operationName}"; diff --git a/Server/LogSanitizer.cs b/Server/LogSanitizer.cs index 9a20af4..9aa7933 100644 --- a/Server/LogSanitizer.cs +++ b/Server/LogSanitizer.cs @@ -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. /// + /// The sanitized URL with sensitive segments redacted. public static string SanitizeUrl(string url) { // Redact subscription IDs: /subscriptions/{guid-or-id}/ diff --git a/Server/SdkIndex.cs b/Server/SdkIndex.cs index 9929769..97a0648 100644 --- a/Server/SdkIndex.cs +++ b/Server/SdkIndex.cs @@ -108,6 +108,7 @@ private SdkIndex( /// Creates an with explicit connector names and trigger operations. /// Intended for unit testing only. /// + /// A new instance for testing. internal static SdkIndex CreateForTesting( IEnumerable connectorNames, IDictionary> triggerOperations, @@ -125,6 +126,7 @@ internal static SdkIndex CreateForTesting( /// /// Gets trigger operations for a specific connector name (case-insensitive). /// + /// The trigger operations for the connector, or an empty array if none exist. public ImmutableArray GetTriggerOperations(string connectorName) { return TriggerOperationsByConnector.TryGetValue(connectorName, out ImmutableArray operations) @@ -135,6 +137,7 @@ public ImmutableArray GetTriggerOperations(string connectorName) /// /// Gets all trigger operations from all connectors. /// + /// All trigger operations across all connectors. public IEnumerable GetAllTriggerOperations() { return TriggerOperationsByConnector.Values.SelectMany(operations => operations); @@ -144,6 +147,7 @@ public IEnumerable GetAllTriggerOperations() /// Maps an operation name to its corresponding TriggerPayload type name. /// Convention: {Connector}{OperationName}TriggerPayload. /// + /// The payload type name, or if the operation is not found. public string? GetPayloadTypeForOperation(string connectorName, string operationName) { if (!TriggerOperationsByConnector.TryGetValue(connectorName, out ImmutableArray operations) || operations.IsEmpty) @@ -202,6 +206,7 @@ public IEnumerable GetAllTriggerOperations() /// are read directly via MetadataLoadContext. /// /// One or more paths to SDK assembly DLLs. + /// A task that represents the asynchronous operation. The task result contains the created , or if creation failed. public static async Task TryCreateFromAssembliesAsync(params string[] assemblyPaths) { if (assemblyPaths is null || assemblyPaths.Length == 0) diff --git a/Server/Services/Api/ApiServiceConfig.cs b/Server/Services/Api/ApiServiceConfig.cs index 5212b27..0fc2d19 100644 --- a/Server/Services/Api/ApiServiceConfig.cs +++ b/Server/Services/Api/ApiServiceConfig.cs @@ -30,7 +30,7 @@ public class ApiServiceConfig public string ApiVersion { get; set; } = string.Empty; /// - /// 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. /// [JsonIgnore] public string EffectiveApiVersion => diff --git a/Server/Services/CodeLens/CodeLensConfig.cs b/Server/Services/CodeLens/CodeLensConfig.cs index 3e63229..cb8e3ab 100644 --- a/Server/Services/CodeLens/CodeLensConfig.cs +++ b/Server/Services/CodeLens/CodeLensConfig.cs @@ -10,7 +10,7 @@ namespace SdkLspServer.Services.CodeLens; public class CodeLensConfig { /// - /// 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. /// [JsonPropertyName("openConnectionViewCommand")] diff --git a/Server/Services/CompilationService.cs b/Server/Services/CompilationService.cs index bca35ef..060f65b 100644 --- a/Server/Services/CompilationService.cs +++ b/Server/Services/CompilationService.cs @@ -50,6 +50,7 @@ public CompilationService(SdkIndex? sdkIndex) /// The URI of the document being compiled. /// The caller's parsed syntax tree. The returned semantic model is for this tree. /// Optional file path used to resolve NuGet project references. + /// A tuple containing the Roslyn compilation and the semantic model for the given syntax tree. public (CSharpCompilation Compilation, SemanticModel Model) GetCompilation( Uri documentUri, SyntaxTree syntaxTree, @@ -113,6 +114,7 @@ public CompilationService(SdkIndex? sdkIndex) /// Creates a compilation containing only SDK and core references, without any user source text. /// Used for metadata-only analysis such as dynamic operations discovery. /// + /// A Roslyn compilation containing only SDK and core assembly references. public CSharpCompilation CreateSdkMetadataCompilation() { var references = new List(); @@ -199,6 +201,7 @@ internal static void TryAddTrustedReference(List references, /// Searches the TRUSTED_PLATFORM_ASSEMBLIES list, runtime directory, and core library directory. /// /// The file name of the assembly to locate (e.g., "System.Runtime.dll"). + /// The full path to the assembly, or if not found. internal static string? TryGetTrustedAssemblyPath(string assemblyFile) { if (string.IsNullOrWhiteSpace(assemblyFile)) @@ -269,6 +272,7 @@ internal static void TryAddTrustedReference(List references, /// The collection of metadata references to add to. /// A set tracking already processed assembly paths to prevent duplicates. /// The pre-resolved project directory containing the .csproj file. + /// The number of assembly references added. internal static int AddProjectNuGetReferences(List references, HashSet seenPaths, string projectDirectory) { // TODO(#9): NuGetReferenceCache never invalidates when project.assets.json changes @@ -293,6 +297,7 @@ internal static int AddProjectNuGetReferences(List references /// /// Walks up from a file path to find the directory containing a .csproj file. /// + /// The directory path containing the .csproj file, or if not found. internal static string? FindProjectDirectory(string filePath) { string? directory = Path.GetDirectoryName(filePath); diff --git a/Server/Services/Connections/ConnectionsConfig.cs b/Server/Services/Connections/ConnectionsConfig.cs index 80fd400..eb1736e 100644 --- a/Server/Services/Connections/ConnectionsConfig.cs +++ b/Server/Services/Connections/ConnectionsConfig.cs @@ -9,13 +9,13 @@ namespace SdkLspServer.Services.Connections; public class ConnectionsConfig { /// - /// Managed API connections from a connections.json file (Codeful SDK pattern). + /// Gets or sets the managed API connections from a connections.json file (Codeful SDK pattern). /// [JsonPropertyName("managedApiConnections")] public Dictionary ManagedApiConnections { get; set; } = []; /// - /// DirectClient connections from local.settings.json or app configuration (DirectClient SDK pattern). + /// Gets or sets the DirectClient connections from local.settings.json or app configuration (DirectClient SDK pattern). /// Keys are logical connection names used in code (e.g., "SharePoint", "Office365"). /// [JsonPropertyName("directClientConnections")] diff --git a/Server/Services/Connections/DirectClientConnection.cs b/Server/Services/Connections/DirectClientConnection.cs index 4b99855..d2d2950 100644 --- a/Server/Services/Connections/DirectClientConnection.cs +++ b/Server/Services/Connections/DirectClientConnection.cs @@ -10,13 +10,13 @@ namespace SdkLspServer.Services.Connections; public class DirectClientConnection { /// - /// The connector type identifier (e.g., "office365", "sharepointonline"). + /// Gets or sets the connector type identifier (e.g., "office365", "sharepointonline"). /// [JsonPropertyName("connectorType")] public string ConnectorType { get; set; } = string.Empty; /// - /// The connection runtime URL from which the ARM connection resource name is derived. + /// Gets or sets the connection runtime URL from which the ARM connection resource name is derived. /// Format: https://{instance}.azure-apihub.net/apim/{connectorType}/{connectionResourceName}. /// [JsonPropertyName("connectionRuntimeUrl")]