diff --git a/scripts/find-missing-csharp-docs.bat b/scripts/find-missing-csharp-docs.bat new file mode 100644 index 0000000..93949b8 --- /dev/null +++ b/scripts/find-missing-csharp-docs.bat @@ -0,0 +1,6 @@ +@echo off +setlocal + +set SCRIPT_DIR=%~dp0 +powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%SCRIPT_DIR%find-missing-csharp-docs.ps1" %* +exit /b %ERRORLEVEL% diff --git a/scripts/find-missing-csharp-docs.ps1 b/scripts/find-missing-csharp-docs.ps1 new file mode 100644 index 0000000..1148ef2 --- /dev/null +++ b/scripts/find-missing-csharp-docs.ps1 @@ -0,0 +1,360 @@ +param( + [string]$Path = ".", + [string]$OutputPath = "scripts/missing-csharp-docs.txt", + [switch]$IncludeMigrations, + [switch]$IncludeGenerated, + [switch]$Json +) + +$ErrorActionPreference = "Stop" + +$repoRoot = Resolve-Path (Join-Path $PSScriptRoot "..") +$scanRoot = Resolve-Path (Join-Path $repoRoot $Path) + +$excludedDirectories = @( + "\bin\", + "\obj\", + "\.git\", + "\.vs\", + "\node_modules\", + "\dist\", + "\logs\" +) + +if (-not $IncludeMigrations) { + $excludedDirectories += "\Migrations\" +} + +$memberRegexes = @( + @{ + Kind = "Type" + Pattern = '^\s*(?:\[(?:[^\]]+)\]\s*)*(?:(?:public|private|protected|internal|static|abstract|sealed|partial|readonly|unsafe|file)\s+)*(?:class|interface|struct|enum|record(?:\s+(?:class|struct))?)\s+[A-Za-z_][A-Za-z0-9_]*' + }, + @{ + Kind = "Delegate" + Pattern = '^\s*(?:\[(?:[^\]]+)\]\s*)*(?:(?:public|private|protected|internal|static|virtual|abstract|sealed|override|new|unsafe|partial)\s+)*delegate\s+' + }, + @{ + Kind = "Event" + Pattern = '^\s*(?:\[(?:[^\]]+)\]\s*)*(?:(?:public|private|protected|internal|static|virtual|abstract|sealed|override|new|unsafe)\s+)*event\s+' + }, + @{ + Kind = "Property" + Pattern = '^\s*(?:\[(?:[^\]]+)\]\s*)*(?:(?:public|private|protected|internal|static|virtual|abstract|sealed|override|new|readonly|required|unsafe)\s+)+[A-Za-z_][A-Za-z0-9_<>,\[\]\?\.\s]*\s+[A-Za-z_][A-Za-z0-9_]*\s*\{\s*(?:get|set|init)\b' + }, + @{ + Kind = "InterfaceProperty" + Pattern = '^\s*(?:\[(?:[^\]]+)\]\s*)*[A-Za-z_][A-Za-z0-9_<>,\[\]\?\.\s]*\s+[A-Za-z_][A-Za-z0-9_]*\s*\{\s*(?:get|set|init)\b' + }, + @{ + Kind = "Constructor" + Pattern = '^\s*(?:\[(?:[^\]]+)\]\s*)*(?:(?:public|private|protected|internal|static|unsafe)\s+)+[A-Za-z_][A-Za-z0-9_]*\s*\(' + }, + @{ + Kind = "Method" + Pattern = '^\s*(?:\[(?:[^\]]+)\]\s*)*(?:(?:public|private|protected|internal|static|virtual|abstract|sealed|override|async|extern|new|unsafe|partial)\s+)+[A-Za-z_][A-Za-z0-9_<>,\[\]\?\.\s]*\s+(?:operator\s*[^\s\(]+|[A-Za-z_][A-Za-z0-9_]*)\s*(?:<[^>]+>)?\s*\(' + }, + @{ + Kind = "InterfaceMethod" + Pattern = '^\s*(?:\[(?:[^\]]+)\]\s*)*[A-Za-z_][A-Za-z0-9_<>,\[\]\?\.\s]*\s+[A-Za-z_][A-Za-z0-9_]*(?:<[^>]+>)?\s*\([^;{}]*\)\s*;' + }, + @{ + Kind = "Field" + Pattern = '^\s*(?:\[(?:[^\]]+)\]\s*)*(?:(?:public|private|protected|internal|static|readonly|const|volatile|new|unsafe)\s+)+[A-Za-z_][A-Za-z0-9_<>,\[\]\?\.\s]*\s+[A-Za-z_][A-Za-z0-9_]*(?:\s*=\s*[^;]+)?\s*;' + } +) + +function Test-IsExcludedFile { + param([System.IO.FileInfo]$File) + + $fullName = $File.FullName + foreach ($directory in $excludedDirectories) { + if ($fullName.Contains($directory)) { + return $true + } + } + + if (-not $IncludeGenerated) { + if ($File.Name -like "*.g.cs" -or + $File.Name -like "*.g.i.cs" -or + $File.Name -like "*.Designer.cs" -or + $File.Name -like "*.AssemblyInfo.cs") { + return $true + } + } + + return $false +} + +function Get-RelativePath { + param( + [string]$BasePath, + [string]$TargetPath + ) + + $baseFullPath = [System.IO.Path]::GetFullPath($BasePath) + if (-not $baseFullPath.EndsWith([System.IO.Path]::DirectorySeparatorChar)) { + $baseFullPath += [System.IO.Path]::DirectorySeparatorChar + } + + $targetFullPath = [System.IO.Path]::GetFullPath($TargetPath) + $baseUri = New-Object System.Uri($baseFullPath) + $targetUri = New-Object System.Uri($targetFullPath) + $relativeUri = $baseUri.MakeRelativeUri($targetUri) + return [System.Uri]::UnescapeDataString($relativeUri.ToString()).Replace("/", [System.IO.Path]::DirectorySeparatorChar) +} + +function Remove-LineNoise { + param([string]$Line) + + $lineWithoutStrings = [regex]::Replace($Line, '@?"(?:[^"\\]|\\.|"")*"', '""') + return [regex]::Replace($lineWithoutStrings, '//.*$', '') +} + +function Get-PreviousCodeLineIndex { + param( + [string[]]$Lines, + [int]$StartIndex + ) + + for ($i = $StartIndex; $i -ge 0; $i--) { + $trimmed = $Lines[$i].Trim() + if ([string]::IsNullOrWhiteSpace($trimmed)) { + continue + } + + if ($trimmed.StartsWith("[") -and $trimmed.EndsWith("]")) { + continue + } + + return $i + } + + return -1 +} + +function Test-HasXmlDoc { + param( + [string[]]$Lines, + [int]$DeclarationIndex + ) + + $previousIndex = Get-PreviousCodeLineIndex -Lines $Lines -StartIndex ($DeclarationIndex - 1) + return $previousIndex -ge 0 -and $Lines[$previousIndex].TrimStart().StartsWith("///") +} + +function Get-DeclarationText { + param( + [string[]]$Lines, + [int]$StartIndex + ) + + $parts = New-Object System.Collections.Generic.List[string] + $maxIndex = [Math]::Min($Lines.Length - 1, $StartIndex + 8) + + for ($i = $StartIndex; $i -le $maxIndex; $i++) { + $clean = Remove-LineNoise $Lines[$i] + if ([string]::IsNullOrWhiteSpace($clean)) { + continue + } + + $parts.Add($clean.Trim()) + $joined = ($parts -join " ") + if ($joined -match '[\{;\}=]\s*$' -or $joined.Contains("=>")) { + break + } + } + + return ($parts -join " ") +} + +function Test-IsInsideInterface { + param( + [string[]]$Lines, + [int]$Index + ) + + $scopeStack = New-Object System.Collections.Generic.List[string] + $pendingInterface = $false + + for ($i = 0; $i -lt $Index; $i++) { + $line = Remove-LineNoise $Lines[$i] + if ($line -match '\binterface\s+[A-Za-z_][A-Za-z0-9_]*') { + $pendingInterface = $true + } + + foreach ($char in $line.ToCharArray()) { + if ($char -eq "{") { + if ($pendingInterface) { + $scopeStack.Add("interface") + $pendingInterface = $false + } else { + $scopeStack.Add("block") + } + } elseif ($char -eq "}") { + if ($scopeStack.Count -gt 0) { + $scopeStack.RemoveAt($scopeStack.Count - 1) + } + } + } + } + + return $scopeStack.Contains("interface") +} + +function Get-MemberName { + param( + [string]$Kind, + [string]$Declaration + ) + + switch ($Kind) { + "Type" { + if ($Declaration -match '\b(?:class|interface|struct|enum|record(?:\s+(?:class|struct))?)\s+(?[A-Za-z_][A-Za-z0-9_]*)') { + return $Matches["name"] + } + } + "Delegate" { + if ($Declaration -match '\b(?[A-Za-z_][A-Za-z0-9_]*)\s*\(') { + return $Matches["name"] + } + } + "Event" { + if ($Declaration -match '\bevent\s+[A-Za-z_][A-Za-z0-9_<>,\[\]\?\.\s]*\s+(?[A-Za-z_][A-Za-z0-9_]*)') { + return $Matches["name"] + } + } + "Constructor" { + if ($Declaration -match '\b(?[A-Za-z_][A-Za-z0-9_]*)\s*\(') { + return $Matches["name"] + } + } + "Method" { + $openParenIndex = $Declaration.IndexOf("(") + $prefix = if ($openParenIndex -ge 0) { $Declaration.Substring(0, $openParenIndex) } else { $Declaration } + if ($prefix -match '(?operator\s*[^\s]+|[A-Za-z_][A-Za-z0-9_]*)\s*(?:<[^>]+>)?$') { + return $Matches["name"] + } + } + "InterfaceMethod" { + $openParenIndex = $Declaration.IndexOf("(") + $prefix = if ($openParenIndex -ge 0) { $Declaration.Substring(0, $openParenIndex) } else { $Declaration } + if ($prefix -match '(?[A-Za-z_][A-Za-z0-9_]*)\s*(?:<[^>]+>)?$') { + return $Matches["name"] + } + } + default { + if ($Declaration -match '\b(?[A-Za-z_][A-Za-z0-9_]*)\s*(?:[=;\{])') { + return $Matches["name"] + } + } + } + + return "" +} + +function Test-IsEnumMember { + param( + [string[]]$Lines, + [int]$Index + ) + + $line = Remove-LineNoise $Lines[$Index] + if ($line -notmatch '^\s*[A-Za-z_][A-Za-z0-9_]*(?:\s*=\s*[^,]+)?\s*,?\s*$') { + return $false + } + + for ($i = $Index - 1; $i -ge 0; $i--) { + $previous = Remove-LineNoise $Lines[$i] + if ($previous -match '\benum\s+[A-Za-z_][A-Za-z0-9_]*') { + return $true + } + + if ($previous.Contains("{") -or $previous.Contains("}")) { + return $false + } + } + + return $false +} + +$files = Get-ChildItem -Path $scanRoot -Recurse -File -Filter "*.cs" | + Where-Object { -not (Test-IsExcludedFile $_) } | + Sort-Object FullName + +$results = New-Object System.Collections.Generic.List[object] + +foreach ($file in $files) { + $lines = Get-Content $file.FullName -Encoding UTF8 + $relativePath = Get-RelativePath -BasePath $repoRoot -TargetPath $file.FullName + + for ($i = 0; $i -lt $lines.Length; $i++) { + $line = $lines[$i] + $trimmed = $line.Trim() + + if ([string]::IsNullOrWhiteSpace($trimmed) -or + $trimmed.StartsWith("///") -or + $trimmed.StartsWith("//") -or + $trimmed.StartsWith("#") -or + $trimmed.StartsWith("[") -or + $trimmed -in @("{", "}", "};")) { + continue + } + + $declaration = Get-DeclarationText -Lines $lines -StartIndex $i + $matchedKind = $null + + foreach ($entry in $memberRegexes) { + if ($declaration -cmatch $entry.Pattern) { + if (($entry.Kind -eq "InterfaceMethod" -or $entry.Kind -eq "InterfaceProperty") -and + -not (Test-IsInsideInterface -Lines $lines -Index $i)) { + continue + } + + $matchedKind = $entry.Kind + break + } + } + + if ($null -eq $matchedKind -and (Test-IsEnumMember -Lines $lines -Index $i)) { + $matchedKind = "EnumMember" + } + + if ($null -eq $matchedKind) { + continue + } + + if (Test-HasXmlDoc -Lines $lines -DeclarationIndex $i) { + continue + } + + $results.Add([pscustomobject]@{ + File = $relativePath + Line = $i + 1 + Kind = $matchedKind + Name = Get-MemberName -Kind $matchedKind -Declaration $declaration + Declaration = $declaration + }) + } +} + +if ($Json) { + $output = $results | ConvertTo-Json -Depth 4 +} else { + $output = $results | Format-Table File, Line, Kind, Name, Declaration -AutoSize | Out-String -Width 240 +} + +if (-not [string]::IsNullOrWhiteSpace($OutputPath)) { + $resolvedOutputPath = Join-Path $repoRoot $OutputPath + $outputDirectory = Split-Path $resolvedOutputPath -Parent + if (-not [string]::IsNullOrWhiteSpace($outputDirectory)) { + New-Item -ItemType Directory -Path $outputDirectory -Force | Out-Null + } + + Set-Content -Path $resolvedOutputPath -Value $output -Encoding UTF8 + Write-Host "Missing XML documentation report written to $resolvedOutputPath" + Write-Host "Total missing items: $($results.Count)" +} else { + $output + Write-Host "Total missing items: $($results.Count)" +} diff --git a/scripts/missing-csharp-docs.txt b/scripts/missing-csharp-docs.txt new file mode 100644 index 0000000..81d15f6 --- /dev/null +++ b/scripts/missing-csharp-docs.txt @@ -0,0 +1,215 @@ + +File Line Kind Name Declaration +---- ---- ---- ---- ----------- +Avalonia-API\Authentication\ApiAuthEndpointService.cs 11 Type ApiAuthEndpointService public sealed class ApiAuthEndpointService( AppDataContext db, JwtTokenService jwtTokenService, RefreshTokenServ... +Avalonia-API\Authentication\ApiAuthEndpointService.cs 21 Method LoginAsync public async Task LoginAsync(ServiceEndpointContext ctx) { +Avalonia-API\Authentication\ApiAuthEndpointService.cs 59 Method RefreshAsync public async Task RefreshAsync(ServiceEndpointContext ctx) { +Avalonia-API\Authentication\ApiAuthEndpointService.cs 91 Method LogoutAsync public async Task LogoutAsync(ServiceEndpointContext ctx) { +Avalonia-API\Authentication\ApiAuthEndpointService.cs 98 Method Deserialize private static T? Deserialize(string? body) { +Avalonia-API\Authentication\ApiAuthEndpointService.cs 105 Method GetRemoteIpAddress private static string? GetRemoteIpAddress(ServiceEndpointContext ctx) { +Avalonia-API\Authentication\ApiAuthEndpointService.cs 112 Method NormalizeRoles private static string[] NormalizeRoles(string[]? roles) { +Avalonia-API\Authentication\JwtOptions.cs 3 Type JwtOptions public sealed class JwtOptions { +Avalonia-API\Authentication\JwtOptions.cs 5 Property Issuer public string Issuer { get; set; } = ""; +Avalonia-API\Authentication\JwtOptions.cs 7 Property Audience public string Audience { get; set; } = ""; +Avalonia-API\Authentication\JwtOptions.cs 9 Property SigningKey public string SigningKey { get; set; } = ""; +Avalonia-API\Authentication\JwtOptions.cs 11 Property AccessTokenMinutes public int AccessTokenMinutes { get; set; } = 60; +Avalonia-API\Authentication\JwtOptions.cs 13 Property RefreshTokenDays public int RefreshTokenDays { get; set; } = 30; +Avalonia-API\Authentication\JwtTokenService.cs 10 Type JwtTokenService public sealed class JwtTokenService(IOptions options) { +Avalonia-API\Authentication\JwtTokenService.cs 12 Field _options private readonly JwtOptions _options = options.Value; +Avalonia-API\Authentication\RefreshTokenService.cs 10 Type RefreshTokenService public sealed class RefreshTokenService(AppDataContext db, IOptions options) { +Avalonia-API\Authentication\RefreshTokenService.cs 12 Field _options private readonly JwtOptions _options = options.Value; +Avalonia-API\Authentication\RefreshTokenService.cs 35 Method FindActiveAsync public async Task FindActiveAsync(string? token, CancellationToken cancellationToken = d... +Avalonia-API\Authentication\RefreshTokenService.cs 47 Method RevokeAsync public async Task RevokeAsync(string? token, CancellationToken cancellationToken = default) { +Avalonia-API\Authentication\RefreshTokenService.cs 78 Method HashToken private static string HashToken(string token) { +Avalonia-API\Configuration\ServicesConfiguration.cs 13 Type ServicesConfiguration public static class ServicesConfiguration { +Avalonia-API\Extensions\UnifiedEndpointExtensions.cs 98 Method MapEndpoint private static RouteHandlerBuilder MapEndpoint( IEndpointRouteBuilder group, ServiceEndpoint endpoint, IServiceP... +Avalonia-API\Extensions\UnifiedEndpointExtensions.cs 115 Method CreateAspNetCoreHandler private static Delegate CreateAspNetCoreHandler( Func> unifiedHandler, ISe... +Avalonia-API\Extensions\UnifiedEndpointExtensions.cs 138 Method BuildContextFromHttpContext private static async Task BuildContextFromHttpContext(HttpContext httpContext) { +Avalonia-API\Extensions\UnifiedEndpointExtensions.cs 169 Method ConvertFilterAsync private static async ValueTask ConvertFilterAsync( UnifiedFilter unifiedFilter, AspNetCoreFilterContext... +Avalonia-Common\Core\ApiResponse.cs 119 Property Success public bool Success { get; set; } = true; +Avalonia-Common\Core\ApiResponse.cs 122 Property Code public int Code { get; set; } = 200; +Avalonia-Common\Core\ApiResponse.cs 125 Property Items public List Items { get; set; } = new(); +Avalonia-Common\Core\ApiResponse.cs 128 Property Total public int Total { get; set; } +Avalonia-Common\Core\ApiResponse.cs 131 Property Page public int Page { get; set; } = 1; +Avalonia-Common\Core\ApiResponse.cs 134 Property PageSize public int PageSize { get; set; } = 20; +Avalonia-Common\Core\ApiResponse.cs 137 Field TotalPages public int TotalPages => PageSize > 0 ? (int)Math.Ceiling((double)Total / PageSize) : 0; +Avalonia-Common\Core\ApiResponse.cs 139 Method From public static PagedResponse From(List items, int total, int page, int pageSize) { +Avalonia-Common\Infrastructure\LoggingConfiguration.cs 90 Field _logger private static ILogger? _logger; +Avalonia-Common\Infrastructure\LoggingConfiguration.cs 101 Field Logger public static ILogger Logger => _logger ?? Log.Logger; +Avalonia-Common\Infrastructure\LoggingConfiguration.cs 103 Method Debug public static void Debug(string messageTemplate, params object?[] propertyValues) => Logger.Debug(messageTemplat... +Avalonia-Common\Infrastructure\LoggingConfiguration.cs 106 Method Information public static void Information(string messageTemplate, params object?[] propertyValues) => Logger.Information(me... +Avalonia-Common\Infrastructure\LoggingConfiguration.cs 109 Method Warning public static void Warning(string messageTemplate, params object?[] propertyValues) => Logger.Warning(messageTem... +Avalonia-Common\Infrastructure\LoggingConfiguration.cs 112 Method Error public static void Error(string messageTemplate, params object?[] propertyValues) => Logger.Error(messageTemplat... +Avalonia-Common\Infrastructure\LoggingConfiguration.cs 115 Method Error public static void Error(Exception exception, string messageTemplate, params object?[] propertyValues) => Logger... +Avalonia-Common\Infrastructure\LoggingConfiguration.cs 118 Method Fatal public static void Fatal(string messageTemplate, params object?[] propertyValues) => Logger.Fatal(messageTemplat... +Avalonia-Common\Infrastructure\LoggingConfiguration.cs 121 Method Fatal public static void Fatal(Exception exception, string messageTemplate, params object?[] propertyValues) => Logger... +Avalonia-EFCore\Database\AppDataContext.cs 22 Method OnModelCreating protected override void OnModelCreating(ModelBuilder modelBuilder) { +Avalonia-EFCore\Database\AppDataContextFactory.cs 5 Type AppDataContextFactory public class AppDataContextFactory : IDesignTimeDbContextFactory { +Avalonia-EFCore\Database\AppDataContextFactory.cs 7 Method CreateDbContext public AppDataContext CreateDbContext(string[] args) { +Avalonia-EFCore\Database\AppDbContext.cs 15 Field _dbConfig private readonly DatabaseConfiguration _dbConfig = dbConfig; +Avalonia-EFCore\Database\AppDbContext.cs 17 Method OnConfiguring protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { +Avalonia-EFCore\Database\AppDbContext.cs 68 Method SaveChangesAsync public override Task SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken =... +Avalonia-EFCore\Database\AppDbContext.cs 74 Method SetTimestamps private void SetTimestamps() { +Avalonia-EFCore\Database\DatabaseManager.cs 20 Field _context private readonly TContext _context; +Avalonia-EFCore\Database\DatabaseManager.cs 21 Field _config private readonly DatabaseConfiguration _config; +Avalonia-EFCore\Database\DatabaseManager.cs 22 Field _serviceProvider private readonly IServiceProvider? _serviceProvider; +Avalonia-EFCore\Database\DatabaseManager.cs 24 Constructor DatabaseManager public DatabaseManager(TContext context, DatabaseConfiguration config, IServiceProvider? serviceProvider = null) { +Avalonia-EFCore\Database\DatabaseManager.cs 131 Method GetApplicationVersion private static string GetApplicationVersion() { +Avalonia-EFCore\Database\DatabaseManager.cs 184 Property Provider public string Provider { get; set; } = string.Empty; +Avalonia-EFCore\Database\DatabaseManager.cs 185 Property AppliedMigrations public List AppliedMigrations { get; set; } = new(); +Avalonia-EFCore\Database\DatabaseManager.cs 186 Property PendingMigrations public List PendingMigrations { get; set; } = new(); +Avalonia-EFCore\Database\DatabaseManager.cs 187 Property IsLatest public bool IsLatest { get; set; } +Avalonia-EFCore\Database\DatabaseManager.cs 188 Property CanConnect public bool CanConnect { get; set; } +Avalonia-EFCore\Database\DatabaseProviderRegistry.cs 18 Field _providers private static readonly Dictionary _providers = new(); +Avalonia-EFCore\Models\ApiRefreshTokenEntity.cs 17 Property Id public long Id { get; set; } +Avalonia-EFCore\Models\ApiRefreshTokenEntity.cs 20 Property UserId public int UserId { get; set; } +Avalonia-EFCore\Models\ApiRefreshTokenEntity.cs 24 Property TokenHash public string TokenHash { get; set; } = string.Empty; +Avalonia-EFCore\Models\ApiRefreshTokenEntity.cs 27 Property CreatedAt public DateTime CreatedAt { get; set; } = DateTime.UtcNow; +Avalonia-EFCore\Models\ApiRefreshTokenEntity.cs 30 Property ExpiresAt public DateTime ExpiresAt { get; set; } +Avalonia-EFCore\Models\ApiRefreshTokenEntity.cs 33 Property RevokedAt public DateTime? RevokedAt { get; set; } +Avalonia-EFCore\Models\ApiRefreshTokenEntity.cs 37 Property ReplacedByTokenHash public string? ReplacedByTokenHash { get; set; } +Avalonia-EFCore\Models\ApiRefreshTokenEntity.cs 41 Property Device public string? Device { get; set; } +Avalonia-EFCore\Models\ApiRefreshTokenEntity.cs 45 Property IpAddress public string? IpAddress { get; set; } +Avalonia-EFCore\Models\ApiRefreshTokenEntity.cs 47 Field IsActive public bool IsActive => RevokedAt is null && ExpiresAt > DateTime.UtcNow; +Avalonia-EFCore\Models\UserEntity.cs 18 Property Id public int Id { get; set; } +Avalonia-EFCore\Models\UserEntity.cs 23 Property Name public string? Name { get; set; } +Avalonia-EFCore\Models\UserEntity.cs 28 Property Email public string? Email { get; set; } +Avalonia-EFCore\Models\UserEntity.cs 33 Property PhoneNumber public string? PhoneNumber { get; set; } +Avalonia-EFCore\Models\UserEntity.cs 37 Property CreatedAt public DateTime CreatedAt { get; set; } = DateTime.UtcNow; +Avalonia-EFCore\Models\UserEntity.cs 41 Property UpdatedAt public DateTime UpdatedAt { get; set; } = DateTime.UtcNow; +Avalonia-EFCore\Models\WeatherForecast.cs 3 Type WeatherForecast public class WeatherForecast { +Avalonia-EFCore\Models\WeatherForecast.cs 5 Property Date public DateOnly Date { get; set; } +Avalonia-EFCore\Models\WeatherForecast.cs 7 Property TemperatureC public int TemperatureC { get; set; } +Avalonia-EFCore\Models\WeatherForecast.cs 9 Field TemperatureF public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); +Avalonia-EFCore\Models\WeatherForecast.cs 11 Property Summary public string? Summary { get; set; } +Avalonia-EFCore\Models\WeatherForecastEntity.cs 18 Property Id public int Id { get; set; } +Avalonia-EFCore\Models\WeatherForecastEntity.cs 22 Property Date public DateOnly Date { get; set; } +Avalonia-EFCore\Models\WeatherForecastEntity.cs 26 Property TemperatureC public int TemperatureC { get; set; } +Avalonia-EFCore\Models\WeatherForecastEntity.cs 31 Property Summary public string? Summary { get; set; } +Avalonia-EFCore\Models\WeatherForecastEntity.cs 35 Property CreatedAt public DateTime CreatedAt { get; set; } = DateTime.UtcNow; +Avalonia-EFCore\Models\WeatherForecastEntity.cs 39 Property UpdatedAt public DateTime UpdatedAt { get; set; } = DateTime.UtcNow; +Avalonia-PC\App.axaml.cs 10 Type App public partial class App : Application { +Avalonia-PC\App.axaml.cs 12 Method Initialize public override void Initialize() { +Avalonia-PC\App.axaml.cs 17 Method OnFrameworkInitializationCompleted public override void OnFrameworkInitializationCompleted() { +Avalonia-PC\Authentication\DefaultPcThirdPartyAuthorizationClient.cs 13 Method ValidateAuthorizationCodeAsync public Task ValidateAuthorizationCodeAsync( string authorizationCode, CancellationTok... +Avalonia-PC\Authentication\DefaultPcThirdPartyAuthorizationClient.cs 26 Method RefreshAuthorizationAsync public Task RefreshAuthorizationAsync( string authorizationReference, CancellationTok... +Avalonia-PC\Authentication\PcAuthEndpointService.cs 11 Type PcAuthEndpointService public sealed class PcAuthEndpointService(PcGlobalTokenService tokenService) : IPcAuthEndpointService { +Avalonia-PC\Authentication\PcAuthEndpointService.cs 18 Method AuthorizeAsync public async Task AuthorizeAsync(ServiceEndpointContext ctx) { +Avalonia-PC\Authentication\PcAuthEndpointService.cs 31 Method RefreshAsync public async Task RefreshAsync(ServiceEndpointContext ctx) { +Avalonia-PC\Authentication\PcAuthEndpointService.cs 45 Method LogoutAsync public Task LogoutAsync(ServiceEndpointContext ctx) { +Avalonia-PC\Authentication\PcAuthEndpointService.cs 53 Method Deserialize private static T? Deserialize(string? body) { +Avalonia-PC\Authentication\PcAuthEndpointService.cs 60 Method ExtractBearerToken private static string? ExtractBearerToken(string? authorization) { +Avalonia-PC\Authentication\PcAuthEndpointService.cs 67 Field prefix const string prefix = ""; +Avalonia-PC\Authentication\PcAuthService.cs 9 Type PcAuthService public sealed class PcAuthService(PcGlobalTokenService tokenService) : IAuthService { +Avalonia-PC\Authentication\PcAuthService.cs 11 Method AuthenticateAsync public async Task AuthenticateAsync(ServiceEndpointContext context) { +Avalonia-PC\Authentication\PcAuthService.cs 32 Method AuthorizeAsync public Task AuthorizeAsync(ClaimsPrincipal user, string policy) { +Avalonia-PC\Authentication\PcAuthService.cs 37 Method ExtractBearerToken private static string? ExtractBearerToken(string? authorization) { +Avalonia-PC\Authentication\PcAuthService.cs 44 Field prefix const string prefix = ""; +Avalonia-PC\Authentication\PcGlobalTokenService.cs 10 Type PcGlobalTokenService public sealed class PcGlobalTokenService(IPcThirdPartyAuthorizationClient thirdPartyClient) { +Avalonia-PC\Authentication\PcGlobalTokenService.cs 12 Field SuperRoles private static readonly string[] SuperRoles = ["", ""]; +Avalonia-PC\Authentication\PcGlobalTokenService.cs 13 Field _syncRoot private readonly object _syncRoot = new(); +Avalonia-PC\Authentication\PcGlobalTokenService.cs 14 Field _current private PcTokenState? _current; +Avalonia-PC\Authentication\PcGlobalTokenService.cs 16 Field NormalLifetime private static readonly TimeSpan NormalLifetime = TimeSpan.FromHours(8); +Avalonia-PC\Authentication\PcGlobalTokenService.cs 17 Field TemporaryFailureLifetime private static readonly TimeSpan TemporaryFailureLifetime = TimeSpan.FromMinutes(20); +Avalonia-PC\Authentication\PcGlobalTokenService.cs 18 Field MaxTemporaryFailureWindow private static readonly TimeSpan MaxTemporaryFailureWindow = TimeSpan.FromHours(24); +Avalonia-PC\Authentication\PcGlobalTokenService.cs 20 Method AuthorizeAsync public async Task AuthorizeAsync(string? authorizationCode, CancellationToken cancellationToke... +Avalonia-PC\Authentication\PcGlobalTokenService.cs 36 Method RefreshAsync public async Task RefreshAsync(string? token, CancellationToken cancellationToken = default) { +Avalonia-PC\Authentication\PcGlobalTokenService.cs 59 Method ValidateAsync public async Task ValidateAsync(string? token, CancellationToken cancellationToken = default) { +Avalonia-PC\Authentication\PcGlobalTokenService.cs 79 Method Logout public void Logout(string? token) { +Avalonia-PC\Authentication\PcGlobalTokenService.cs 90 Method IssueToken private PcTokenResponse IssueToken(string authorizationReference, TimeSpan lifetime, bool resetTemporaryFailureW... +Avalonia-PC\Authentication\PcGlobalTokenService.cs 108 Method RefreshAfterTemporaryFailure private PcTokenResponse? RefreshAfterTemporaryFailure(PcTokenState current) { +Avalonia-PC\Authentication\PcGlobalTokenService.cs 119 Method ClearAndReturnNull private PcTokenResponse? ClearAndReturnNull() { +Avalonia-PC\Authentication\PcGlobalTokenService.cs 129 Method IsCurrentToken private bool IsCurrentToken(string? token) { +Avalonia-PC\Authentication\PcGlobalTokenService.cs 136 Method HashToken private static string HashToken(string token) { +Avalonia-PC\Authentication\PcGlobalTokenService.cs 142 Type PcTokenState private sealed record PcTokenState( string TokenHash, string AuthorizationReference, DateTime ExpiresAt, DateTim... +Avalonia-PC\Program.cs 17 Type Program internal sealed class Program { +Avalonia-PC\Program.cs 19 Property Services public static IServiceProvider Services { get; private set; } = null!; +Avalonia-PC\Program.cs 22 Method Main public static void Main(string[] args) { +Avalonia-PC\Program.cs 43 Method ConfigureServices private static void ConfigureServices() { +Avalonia-PC\Program.cs 75 Method BuildAvaloniaApp public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() +Avalonia-PC\ViewLocator.cs 15 Type ViewLocator public class ViewLocator : IDataTemplate { +Avalonia-PC\ViewLocator.cs 17 Method Build public Control? Build(object? param) { +Avalonia-PC\ViewLocator.cs 33 Method Match public bool Match(object? data) { +Avalonia-PC\ViewModels\MainWindowViewModel.cs 3 Type MainWindowViewModel public partial class MainWindowViewModel : ViewModelBase { +Avalonia-PC\ViewModels\MainWindowViewModel.cs 5 Property Greeting public string Greeting { get; } = ""; +Avalonia-PC\ViewModels\ViewModelBase.cs 5 Type ViewModelBase public abstract class ViewModelBase : ObservableObject { +Avalonia-PC\Views\MainWindow.axaml.cs 15 Type MainWindow public partial class MainWindow : Window { +Avalonia-PC\Views\MainWindow.axaml.cs 17 Field AppScheme private const string AppScheme = ""; +Avalonia-PC\Views\MainWindow.axaml.cs 18 Field OnlineStartupUrl private const string? OnlineStartupUrl = ""; +Avalonia-PC\Views\MainWindow.axaml.cs 20 Field LocalStartupPath private const string? LocalStartupPath = null; +Avalonia-PC\Views\MainWindow.axaml.cs 26 Field _webView private NativeWebView? _webView; +Avalonia-PC\Views\MainWindow.axaml.cs 27 Field _eventsAttached private bool _eventsAttached; +Avalonia-PC\Views\MainWindow.axaml.cs 28 Field _webViewAdapter private object? _webViewAdapter; +Avalonia-PC\Views\MainWindow.axaml.cs 29 Field _localHttpServer private HttpListener? _localHttpServer; +Avalonia-PC\Views\MainWindow.axaml.cs 30 Field _localHttpServerCts private CancellationTokenSource? _localHttpServerCts; +Avalonia-PC\Views\MainWindow.axaml.cs 31 Field _localHttpBaseUrl private string? _localHttpBaseUrl; +Avalonia-PC\Views\MainWindow.axaml.cs 32 Field _localHttpRoot private string? _localHttpRoot; +Avalonia-PC\Views\MainWindow.axaml.cs 613 Type AppResponse private sealed class AppResponse { +Avalonia-PC\Views\MainWindow.axaml.cs 615 Property Kind public string Kind { get; set; } = string.Empty; +Avalonia-PC\Views\MainWindow.axaml.cs 617 Property Id public string? Id { get; set; } +Avalonia-PC\Views\MainWindow.axaml.cs 619 Property StatusCode public int StatusCode { get; set; } +Avalonia-PC\Views\MainWindow.axaml.cs 621 Property StatusMessage public string StatusMessage { get; set; } = string.Empty; +Avalonia-PC\Views\MainWindow.axaml.cs 623 Property Body public string Body { get; set; } = string.Empty; +Avalonia-PC\Views\MainWindow.axaml.cs 625 Property Headers public Dictionary Headers { get; set; } = new(); +Avalonia-PC\Views\MainWindow.BridgeScript.cs 3 Type MainWindow public partial class MainWindow { +Avalonia-PC\Views\MainWindow.BridgeScript.cs 109 Type BridgeXMLHttpRequest class BridgeXMLHttpRequest { +Avalonia-PC\Views\MainWindow.Routes.cs 12 Type MainWindow public partial class MainWindow { +Avalonia-PC\Views\MainWindow.Routes.cs 25 Method RegisterRoutes private void RegisterRoutes() { +Avalonia-Services\Core\GlobalExceptionFilter.cs 13 Field _includeDetails private readonly bool _includeDetails; +Avalonia-Services\Core\GlobalExceptionFilter.cs 23 Method InvokeAsync public async Task InvokeAsync(ServiceEndpointContext context, EndpointFilterDelegate next) { +Avalonia-Services\Core\GlobalExceptionFilter.cs 76 Method LogException private static void LogException(ServiceEndpointContext context, Exception ex) { +Avalonia-Services\Core\IAuthService.cs 26 Method AuthenticateAsync public Task AuthenticateAsync(ServiceEndpointContext context) { +Avalonia-Services\Core\IAuthService.cs 33 Method AuthorizeAsync public Task AuthorizeAsync(ClaimsPrincipal user, string policy) { +Avalonia-Services\Core\IEndpointFilter.cs 28 Field _filter private readonly Func _filter; +Avalonia-Services\Core\IEndpointFilter.cs 30 Constructor AnonymousEndpointFilter public AnonymousEndpointFilter(Func filter) { +Avalonia-Services\Core\IEndpointFilter.cs 35 Method InvokeAsync public Task InvokeAsync(ServiceEndpointContext context, EndpointFilterDelegate next) { +Avalonia-Services\Core\ServiceEndpointCollection.cs 9 Type EndpointHostTarget public enum EndpointHostTarget { +Avalonia-Services\Core\ServiceEndpointCollection.cs 72 Method WithOpenApi public ServiceEndpoint WithOpenApi( string tag, string summary, string? description = null, Type? requestType = ... +Avalonia-Services\Core\ServiceEndpointCollection.cs 125 Method SupportsHost public bool SupportsHost(EndpointHostTarget host) { +Avalonia-Services\Core\ServiceEndpointCollection.cs 139 Method ForHost public IEnumerable ForHost(EndpointHostTarget host) { +Avalonia-Services\Core\ServiceEndpointCollection.cs 155 Method MapGet public ServiceEndpoint MapGet( string pattern, Func> h... +Avalonia-Services\Core\ServiceEndpointCollection.cs 171 Method MapPost public ServiceEndpoint MapPost( string pattern, Func> ... +Avalonia-Services\Core\ServiceEndpointCollection.cs 187 Method MapPut public ServiceEndpoint MapPut( string pattern, Func> h... +Avalonia-Services\Core\ServiceEndpointCollection.cs 203 Method MapDelete public ServiceEndpoint MapDelete( string pattern, Func... +Avalonia-Services\Core\ServiceEndpointCollection.cs 229 Method AddEndpoint private ServiceEndpoint AddEndpoint(string pattern, string method, Func> h... +Avalonia-Services\Core\ServiceEndpointCollection.cs 241 Method CreateServiceHandler private static Func> CreateServiceHandler( Func GetUserFromDatabaseAsync(ServiceEndpointContext ctx) { +Avalonia-Services\Endpoints\AppEndpoints.cs 112 Method ProcessDataAsync private static async Task ProcessDataAsync(ServiceEndpointContext ctx) { +Avalonia-Services\Endpoints\AuthEndpoints.cs 11 Method ConfigureApi public static void ConfigureApi(ServiceEndpointBuilder builder) { +Avalonia-Services\Endpoints\AuthEndpoints.cs 32 Method ConfigurePc public static void ConfigurePc(ServiceEndpointBuilder builder) { +Avalonia-Services\Extensions\DesktopEndpointAdapter.cs 11 Field _endpoints private readonly ServiceEndpointCollection _endpoints; +Avalonia-Services\Extensions\DesktopEndpointAdapter.cs 12 Field _authService private readonly IAuthService _authService; +Avalonia-Services\Extensions\DesktopEndpointAdapter.cs 13 Field _serviceProvider private readonly IServiceProvider _serviceProvider; +Avalonia-Services\Extensions\DesktopEndpointAdapter.cs 20 Property IsMatched public bool IsMatched { get; init; } +Avalonia-Services\Extensions\DesktopEndpointAdapter.cs 21 Property StatusCode public int StatusCode { get; init; } = 200; +Avalonia-Services\Extensions\DesktopEndpointAdapter.cs 22 Property StatusMessage public string StatusMessage { get; init; } = ""; +Avalonia-Services\Extensions\DesktopEndpointAdapter.cs 23 Property Data public object? Data { get; init; } +Avalonia-Services\Extensions\DesktopEndpointAdapter.cs 24 Property ResponseHeaders public Dictionary ResponseHeaders { get; init; } = new(); +Avalonia-Services\Extensions\DesktopEndpointAdapter.cs 26 Method Success public static RouteResult Success(object? data, ServiceEndpointContext ctx) { +Avalonia-Services\Extensions\DesktopEndpointAdapter.cs 38 Method NotFound public static RouteResult NotFound() => new() +Avalonia-Services\Extensions\DesktopEndpointAdapter.cs 46 Constructor DesktopEndpointAdapter public DesktopEndpointAdapter( ServiceEndpointCollection endpoints, IAuthService authService, IServiceProvider s... +Avalonia-Services\Services\AuthService\AuthContracts.cs 3 Type ApiLoginRequest public sealed record ApiLoginRequest(string? Account, string? Password, string[]? Roles = null); +Avalonia-Services\Services\AuthService\AuthContracts.cs 5 Type ApiRefreshTokenRequest public sealed record ApiRefreshTokenRequest(string? RefreshToken); +Avalonia-Services\Services\AuthService\AuthContracts.cs 7 Type ApiLogoutRequest public sealed record ApiLogoutRequest(string? RefreshToken); +Avalonia-Services\Services\AuthService\AuthContracts.cs 9 Type AuthTokenResponse public sealed record AuthTokenResponse( string AccessToken, string RefreshToken, DateTime AccessTokenExpiresAt, ... +Avalonia-Services\Services\AuthService\AuthContracts.cs 16 Type PcAuthorizeRequest public sealed record PcAuthorizeRequest(string? AuthorizationCode); +Avalonia-Services\Services\AuthService\AuthContracts.cs 18 Type PcRefreshRequest public sealed record PcRefreshRequest(string? Token); +Avalonia-Services\Services\AuthService\AuthContracts.cs 20 Type PcLogoutRequest public sealed record PcLogoutRequest(string? Token); +Avalonia-Services\Services\AuthService\AuthContracts.cs 22 Type PcTokenResponse public sealed record PcTokenResponse(string Token, DateTime ExpiresAt, string[] Roles); +Avalonia-Services\Services\AuthService\AuthContracts.cs 24 Type ThirdPartyAuthCheckResult public enum ThirdPartyAuthCheckResult { +Avalonia-Services\Services\AuthService\AuthContracts.cs 31 Type IPcThirdPartyAuthorizationClient public interface IPcThirdPartyAuthorizationClient { +Avalonia-Services\Services\AuthService\AuthContracts.cs 33 InterfaceMethod ValidateAuthorizationCodeAsync Task ValidateAuthorizationCodeAsync(string authorizationCode, CancellationToken cance... +Avalonia-Services\Services\AuthService\AuthContracts.cs 35 InterfaceMethod RefreshAuthorizationAsync Task RefreshAuthorizationAsync(string authorizationReference, CancellationToken cance... +Avalonia-Services\Services\AuthService\AuthEndpointServices.cs 6 Type IApiAuthEndpointService public interface IApiAuthEndpointService { +Avalonia-Services\Services\AuthService\AuthEndpointServices.cs 8 InterfaceMethod LoginAsync Task LoginAsync(ServiceEndpointContext ctx); +Avalonia-Services\Services\AuthService\AuthEndpointServices.cs 10 InterfaceMethod RefreshAsync Task RefreshAsync(ServiceEndpointContext ctx); +Avalonia-Services\Services\AuthService\AuthEndpointServices.cs 12 InterfaceMethod LogoutAsync Task LogoutAsync(ServiceEndpointContext ctx); +Avalonia-Services\Services\AuthService\AuthEndpointServices.cs 15 Type IPcAuthEndpointService public interface IPcAuthEndpointService { +Avalonia-Services\Services\AuthService\AuthEndpointServices.cs 17 InterfaceMethod AuthorizeAsync Task AuthorizeAsync(ServiceEndpointContext ctx); +Avalonia-Services\Services\AuthService\AuthEndpointServices.cs 19 InterfaceMethod RefreshAsync Task RefreshAsync(ServiceEndpointContext ctx); +Avalonia-Services\Services\AuthService\AuthEndpointServices.cs 21 InterfaceMethod LogoutAsync Task LogoutAsync(ServiceEndpointContext ctx); +Avalonia-Services\Services\WeatherForecastService.cs 5 Type WeatherForecastService public class WeatherForecastService { +Avalonia-Services\Services\WeatherForecastService.cs 12 Method GetWeatherForecasts public IEnumerable GetWeatherForecasts() { + + + diff --git a/scripts/生成注释提示词.txt b/scripts/生成注释提示词.txt new file mode 100644 index 0000000..ac7a132 --- /dev/null +++ b/scripts/生成注释提示词.txt @@ -0,0 +1,60 @@ +你是一个资深 C# 工程师。现在我会给你一个 missing-csharp-docs.txt 文件,里面列出了项目中缺少 XML 文档注释的 C# 类型、方法、属性、字段、构造函数、接口成员等。 + +请根据这个 txt 文件逐项读取对应源码文件,并直接修改源码,为缺少注释的成员补全中文 XML 文档注释。 + +要求如下: + +1. 注释必须是中文。 +2. 使用标准 C# XML 文档注释格式。 +3. 类、接口、record、struct、enum 使用: + /// + /// ... + /// +4. 方法、构造函数必须尽量补全: + /// + /// ... + /// + /// ... + /// ... + /// ... +5. 如果方法没有参数,不要生成 。 +6. 如果方法返回 void、Task 或构造函数,不要生成无意义的 。 +7. 如果方法返回 Task、ValueTask、T、IEnumerable 等有实际返回值的类型,需要生成 ,说明返回内容。 +8. 如果方法体中明确 throw 了异常,或声明逻辑明显可能抛出特定异常,可以补充 ;不确定时不要乱写。 +9. 属性使用: + /// + /// 获取或设置... + /// + 如果是只读属性,写“获取...”;如果是计算属性,说明它计算或表示的含义。 +10. 字段使用: + /// + /// 保存/定义/指示... + /// +11. 枚举成员也要加中文 summary,说明每个枚举值的含义。 +12. 接口方法必须在 interface 中写完整注释,包括 summary、param、returns。 +13. 具体实现类如果实现了已有注释的接口方法,优先使用: + /// + 不要在实现类重复写一大段相同注释。 +14. 如果实现类方法不是接口实现,或者接口中没有对应注释,则在实现类中写完整注释。 +15. 不要只根据方法名机械生成注释,要结合方法体、参数、返回值、调用逻辑和业务语义来写。 +16. 不要改业务逻辑,不要改方法签名,不要改格式以外的代码。 +17. XML 注释放在 attribute 之前,例如: + /// + /// 用户 ID。 + /// + [Column("user-id")] + public int UserId { get; set; } +18. 如果成员前已经有 XML 注释,不要重复添加。 +19. 如果 txt 中的行号因为代码变化不准确,要通过成员名称和声明内容定位实际源码位置。 +20. 修改完成后,重新运行已有的注释扫描脚本确认缺失项为 0。 +21. 最后运行相关 dotnet build 验证没有语法错误。 +22. 最后给我总结:修改了哪些文件、补了多少处注释、扫描结果、构建结果。 + +执行方式: +- 直接读取 missing-csharp-docs.txt。 +- 按 txt 中列出的 File、Line、Kind、Name、Declaration 定位源码成员。 +- 逐文件修改。 +- 不要新建额外的注释生成脚本。 +- 不要生成新的工具脚本。 +- 可以使用现有脚本重新扫描验证。 +- 最终直接完成代码修改。