From 9d1041180de44dc67e5fa07077242fd64cc1552a Mon Sep 17 00:00:00 2001 From: Raul Avila Catala Date: Sun, 1 Feb 2026 13:32:24 -0600 Subject: [PATCH 1/4] #118 --- FindOrphans.ps1 | 117 +++++++ FindOrphansComplete.ps1 | 322 ++++++++++++++++++ FindOrphansFiltered.ps1 | 72 ++++ .../Layouts}/PdfLayoutDefaultOptions.cs | 10 +- .../Common/PdfGeneratorConstants.cs | 6 - .../Core/Implementation/Sk/Models/SpanRun.cs | 9 - .../Sk/Pages/ContentPageOrchestrator.cs | 137 -------- .../Core/Implementation/Sk/Utils/SkiaUtils.cs | 6 +- .../Implementation/Sk/Views/TextRenderer.cs | 126 ------- .../Core/Interfaces/ITextFragment.cs | 6 - MauiPdfGenerator/Core/Interfaces/ITextLine.cs | 8 - .../Core/Utils/TextRendererHelpers.cs | 39 --- .../Fluent/Builders/PageContentBuilder.cs | 73 ---- .../Interfaces/Builders/IGridConfiguration.cs | 5 - .../Fluent/Interfaces/IPdfPage.cs | 24 -- .../Interfaces/Pages/IPdfContentPage.cs | 19 -- 16 files changed, 514 insertions(+), 465 deletions(-) create mode 100644 FindOrphans.ps1 create mode 100644 FindOrphansComplete.ps1 create mode 100644 FindOrphansFiltered.ps1 rename MauiPdfGenerator/{Fluent/Models => Common/Models/Layouts}/PdfLayoutDefaultOptions.cs (82%) delete mode 100644 MauiPdfGenerator/Common/PdfGeneratorConstants.cs delete mode 100644 MauiPdfGenerator/Core/Implementation/Sk/Pages/ContentPageOrchestrator.cs delete mode 100644 MauiPdfGenerator/Core/Interfaces/ITextFragment.cs delete mode 100644 MauiPdfGenerator/Core/Interfaces/ITextLine.cs delete mode 100644 MauiPdfGenerator/Core/Utils/TextRendererHelpers.cs delete mode 100644 MauiPdfGenerator/Fluent/Builders/PageContentBuilder.cs delete mode 100644 MauiPdfGenerator/Fluent/Interfaces/Builders/IGridConfiguration.cs delete mode 100644 MauiPdfGenerator/Fluent/Interfaces/IPdfPage.cs delete mode 100644 MauiPdfGenerator/Fluent/Interfaces/Pages/IPdfContentPage.cs diff --git a/FindOrphans.ps1 b/FindOrphans.ps1 new file mode 100644 index 0000000..4dc43ec --- /dev/null +++ b/FindOrphans.ps1 @@ -0,0 +1,117 @@ +# Script para encontrar tipos huérfanos en proyectos C# +$projectPaths = @( + "D:\TodosProyectos\CSHARP\MauiPdfGenerator\MauiPdfGenerator", + "D:\TodosProyectos\CSHARP\MauiPdfGenerator\MauiPdfGenerator.SourceGenerators" +) + +# Obtener todos los archivos .cs excluyendo directorios obj/ +$allCsFiles = @() +foreach ($projectPath in $projectPaths) { + $files = Get-ChildItem -Path $projectPath -Filter "*.cs" -Recurse -File | + Where-Object { $_.FullName -notmatch "\\obj\\" } + $allCsFiles += $files +} + +Write-Host "Analizando $($allCsFiles.Count) archivos .cs..." -ForegroundColor Cyan + +# Diccionario para almacenar tipos encontrados: Key = Tipo, Value = Info (Archivo, Línea) +$allTypes = @{} + +# Expresión regular para encontrar definiciones de tipos +$typeRegex = [regex]::new('^\s*(?:public|internal|private|protected)?\s*(?:sealed|abstract|static|partial)?\s*(class|interface|enum|struct|record)\s+(\w+)', [System.Text.RegularExpressions.RegexOptions]::Multiline) + +# Paso 1: Extraer todas las definiciones de tipos +Write-Host "`nExtrayendo definiciones de tipos..." -ForegroundColor Yellow + +foreach ($file in $allCsFiles) { + $content = Get-Content -Path $file.FullName -Raw + $matches = $typeRegex.Matches($content) + + foreach ($match in $matches) { + $typeName = $match.Groups[2].Value + $typeKind = $match.Groups[1].Value + $lineNumber = ($content.Substring(0, $match.Index).Split("`n").Length) + + $allTypes[$typeName] = @{ + Name = $typeName + Kind = $typeKind + File = $file.Name + FilePath = $file.FullName + Line = $lineNumber + Referenced = $false + ReferencedBy = @() + } + } +} + +Write-Host "Se encontraron $($allTypes.Count) tipos definidos." -ForegroundColor Green + +# Paso 2: Buscar referencias en todos los archivos +Write-Host "`nBuscando referencias..." -ForegroundColor Yellow + +foreach ($file in $allCsFiles) { + $content = Get-Content -Path $file.FullName -Raw + $fileNameWithoutExtension = [System.IO.Path]::GetFileNameWithoutExtension($file.Name) + + foreach ($typeName in $allTypes.Keys) { + # No contar como referencia si es el mismo archivo + if ($allTypes[$typeName].FilePath -eq $file.FullName) { + continue + } + + # Buscar el tipo como palabra completa en el contenido + if ($content -match "\b$typeName\b") { + $allTypes[$typeName].Referenced = $true + $allTypes[$typeName].ReferencedBy += $file.Name + } + } +} + +# Paso 3: Organizar tipos huérfanos por archivo +Write-Host "`n`n========================================" -ForegroundColor Cyan +Write-Host "TIPOS HUÉRFANOS (No referenciados)" -ForegroundColor Cyan +Write-Host "========================================" -ForegroundColor Cyan + +$orphanTypesByFile = @{} +$totalOrphans = 0 + +foreach ($typeInfo in $allTypes.Values) { + if (-not $typeInfo.Referenced) { + if (-not $orphanTypesByFile.ContainsKey($typeInfo.FilePath)) { + $orphanTypesByFile[$typeInfo.FilePath] = @() + } + $orphanTypesByFile[$typeInfo.FilePath] += $typeInfo + $totalOrphans++ + } +} + +# Mostrar resultados organizados por archivo +if ($orphanTypesByFile.Count -eq 0) { + Write-Host "`nNo se encontraron tipos huérfanos." -ForegroundColor Green +} else { + foreach ($filePath in $orphanTypesByFile.Keys | Sort-Object) { + $orphans = $orphanTypesByFile[$filePath] + Write-Host "`n----------------------------------------" -ForegroundColor Gray + Write-Host "Archivo: $($orphanTypesByFile[$filePath][0].File)" -ForegroundColor White + Write-Host "Ruta: $filePath" -ForegroundColor DarkGray + Write-Host "----------------------------------------" -ForegroundColor Gray + + foreach ($orphan in $orphans) { + Write-Host " - $($orphan.Kind): $($orphan.Name) (línea $($orphan.Line))" -ForegroundColor Yellow + } + } +} + +# Paso 4: Resumen final +Write-Host "`n`n========================================" -ForegroundColor Cyan +Write-Host "RESUMEN" -ForegroundColor Cyan +Write-Host "========================================" -ForegroundColor Cyan +Write-Host "Total de tipos analizados: $($allTypes.Count)" -ForegroundColor White +Write-Host "Total de tipos huérfanos: $totalOrphans" -ForegroundColor $(if ($totalOrphans -gt 0) { "Yellow" } else { "Green" }) + +if ($allTypes.Count -gt 0) { + $percentage = [math]::Round(($totalOrphans / $allTypes.Count) * 100, 2) + Write-Host "Porcentaje de huérfanos: $percentage%" -ForegroundColor $(if ($percentage -gt 10) { "Red" } elseif ($percentage -gt 5) { "Yellow" } else { "Green" }) +} + +Write-Host "`n========================================" -ForegroundColor Cyan diff --git a/FindOrphansComplete.ps1 b/FindOrphansComplete.ps1 new file mode 100644 index 0000000..ddda73a --- /dev/null +++ b/FindOrphansComplete.ps1 @@ -0,0 +1,322 @@ +$ErrorActionPreference = "Stop" + +$projectRoot = Split-Path -Parent $MyInvocation.MyCommand.Path +$csFiles = Get-ChildItem -Path $projectRoot -Filter "*.cs" -Recurse -File + +$results = @{ + OrphanFiles = @() + OrphanTypes = @() + OrphanMethods = @() + OrphanProperties = @() +} + +Write-Host "Analizando proyecto en: $projectRoot" -ForegroundColor Cyan +Write-Host "Encontrados $($csFiles.Count) archivos .cs" -ForegroundColor Cyan +Write-Host "" + +function Get-TypeDefinitions { + param([string]$content) + + $patterns = @( + '(?m)^\s*(public|internal|protected|private)?\s*(partial\s+)?(class|interface|struct|enum|record)\s+(\w+)' + ) + + $types = @() + foreach ($pattern in $patterns) { + $matches = [regex]::Matches($content, $pattern) + foreach ($match in $matches) { + $access = if ($match.Groups[1].Value) { $match.Groups[1].Value } else { "internal" } + $keyword = $match.Groups[3].Value + $name = $match.Groups[4].Value + + if ($access -in @("public", "internal") -and $keyword -eq "interface") { + continue + } + + $types += [PSCustomObject]@{ + Name = $name + Access = $access + Keyword = $keyword + FullName = "$keyword $name" + } + } + } + return $types +} + +function Get-MethodDefinitions { + param([string]$content) + + $patterns = @( + '(?m)^\s*(public|protected)\s+(?:override\s+)?(?:virtual\s+)?(?:async\s+)?(?:static\s+)?(?:new\s+)?[\w<>[\],\s]+\s+(\w+)\s*\(', + '(?m)^\s*(public|protected)\s+(?:override\s+)?(?:virtual\s+)?(?:async\s+)?(?:static\s+)?(?:new\s+)?\w+\s+(\w+)\s*\(' + ) + + $methods = @() + foreach ($pattern in $patterns) { + $matches = [regex]::Matches($content, $pattern) + foreach ($match in $matches) { + $access = $match.Groups[1].Value + $name = $match.Groups[2].Value + + if ($name -match '^(get|set|add|remove)$') { continue } + + $methods += [PSCustomObject]@{ + Name = $name + Access = $access + } + } + } + return $methods +} + +function Get-PropertyDefinitions { + param([string]$content) + + $patterns = @( + '(?m)^\s*(public|protected)\s+[\w<>[\],\s]+\s+(\w+)\s*\{', + '(?m)^\s*(public|protected)\s+(?:override\s+)?(?:virtual\s+)?[\w<>[\],\s]+\s+(\w+)\s*\{' + ) + + $properties = @() + foreach ($pattern in $patterns) { + $matches = [regex]::Matches($content, $pattern) + foreach ($match in $matches) { + $access = $match.Groups[1].Value + $name = $match.Groups[2].Value + + $properties += [PSCustomObject]@{ + Name = $name + Access = $access + } + } + } + return $properties +} + +function Is-ReferencedInOtherFiles { + param( + [string]$name, + [string]$currentFile, + [string[]]$allFiles + ) + + foreach ($file in $allFiles) { + if ($file -eq $currentFile) { continue } + + $matches = Select-String -Path $file -Pattern "\b$name\b" -ErrorAction SilentlyContinue + if ($matches) { + return $true + } + } + return $false +} + +function Get-FileImports { + param([string]$filePath) + + $content = Get-Content $filePath -Raw + $imports = @() + + $matches = [regex]::Matches($content, '(?m)^\s*using\s+([^;]+);') + foreach ($match in $matches) { + $import = $match.Groups[1].Value.Trim() + if ($import -notmatch '^(System|Microsoft|Maui|Android|Apple|iOS)') { + $imports += $import + } + } + + return $imports +} + +$fileNames = $csFiles | Select-Object -ExpandProperty FullName +$fileBasenames = @{} + +foreach ($file in $csFiles) { + $basename = [System.IO.Path]::GetFileNameWithoutExtension($file.Name) + $fileBasenames[$file.FullName] = $basename +} + +Write-Host "1. Buscando archivos completos huérfanos..." -ForegroundColor Yellow + +foreach ($file in $csFiles) { + $basename = $fileBasenames[$file.FullName] + $isReferenced = $false + + foreach ($otherFile in $csFiles) { + if ($otherFile.FullName -eq $file.FullName) { continue } + + $imports = Get-FileImports $otherFile.FullName + foreach ($import in $imports) { + $importName = $import -replace '.*\.' + if ($importName -eq $basename -or $import -eq $basename) { + $isReferenced = $true + break + } + } + + if ($isReferenced) { break } + } + + if (-not $isReferenced) { + $results.OrphanFiles += $file.FullName.Replace($projectRoot, "").Trim("\") + } +} + +Write-Host " Encontrados $($results.OrphanFiles.Count) archivos huérfanos" -ForegroundColor Gray +Write-Host "" + +Write-Host "2. Buscando tipos huérfanos..." -ForegroundColor Yellow + +foreach ($file in $csFiles) { + $content = Get-Content $file.FullName -Raw + $types = Get-TypeDefinitions $content + + foreach ($type in $types) { + if ($type.Access -eq "public" -or $type.Keyword -eq "interface") { + continue + } + + if ($content -match "\[Generator\]") { + continue + } + + $isReferenced = Is-ReferencedInOtherFiles $type.Name $file.FullName $fileNames + + if (-not $isReferenced) { + $relativePath = $file.FullName.Replace($projectRoot, "").Trim("\") + $results.OrphanTypes += [PSCustomObject]@{ + File = $relativePath + Type = $type.FullName + } + } + } +} + +Write-Host " Encontrados $($results.OrphanTypes.Count) tipos huérfanos" -ForegroundColor Gray +Write-Host "" + +Write-Host "3. Buscando métodos huérfanos..." -ForegroundColor Yellow + +foreach ($file in $csFiles) { + $content = Get-Content $file.FullName -Raw + $methods = Get-MethodDefinitions $content + + foreach ($method in $methods) { + if ($content -match "\[Test\]|\[Theory\]|\[Fact\]") { + continue + } + + $isReferenced = Is-ReferencedInOtherFiles $method.Name $file.FullName $fileNames + + if (-not $isReferenced) { + $relativePath = $file.FullName.Replace($projectRoot, "").Trim("\") + $results.OrphanMethods += [PSCustomObject]@{ + File = $relativePath + Method = $method.Name + Access = $method.Access + } + } + } +} + +Write-Host " Encontrados $($results.OrphanMethods.Count) métodos huérfanos" -ForegroundColor Gray +Write-Host "" + +Write-Host "4. Buscando propiedades huérfanas..." -ForegroundColor Yellow + +foreach ($file in $csFiles) { + $content = Get-Content $file.FullName -Raw + $properties = Get-PropertyDefinitions $content + + foreach ($property in $properties) { + $isReferenced = Is-ReferencedInOtherFiles $property.Name $file.FullName $fileNames + + if (-not $isReferenced) { + $relativePath = $file.FullName.Replace($projectRoot, "").Trim("\") + $results.OrphanProperties += [PSCustomObject]@{ + File = $relativePath + Property = $property.Name + Access = $property.Access + } + } + } +} + +Write-Host " Encontradas $($results.OrphanProperties.Count) propiedades huérfanas" -ForegroundColor Gray +Write-Host "" + +Write-Host "=" * 80 -ForegroundColor Cyan +Write-Host "RESULTADOS DETALLADOS" -ForegroundColor Cyan +Write-Host "=" * 80 -ForegroundColor Cyan +Write-Host "" + +if ($results.OrphanFiles.Count -gt 0) { + Write-Host "ARCHIVOS COMPLETOS HUÉRFANOS" -ForegroundColor Magenta + Write-Host "-" * 80 -ForegroundColor Magenta + foreach ($file in $results.OrphanFiles | Sort-Object) { + Write-Host " $file" -ForegroundColor White + } + Write-Host "" +} + +if ($results.OrphanTypes.Count -gt 0) { + Write-Host "TIPOS HUÉRFANOS" -ForegroundColor Magenta + Write-Host "-" * 80 -ForegroundColor Magenta + + $grouped = $results.OrphanTypes | Group-Object File + foreach ($group in $grouped | Sort-Object Name) { + Write-Host " $($group.Name):" -ForegroundColor Cyan + foreach ($type in $group.Group | Sort-Object Type) { + Write-Host " - $($type.Type)" -ForegroundColor White + } + } + Write-Host "" +} + +if ($results.OrphanMethods.Count -gt 0) { + Write-Host "MÉTODOS HUÉRFANOS" -ForegroundColor Magenta + Write-Host "-" * 80 -ForegroundColor Magenta + + $grouped = $results.OrphanMethods | Group-Object File + foreach ($group in $grouped | Sort-Object Name) { + Write-Host " $($group.Name):" -ForegroundColor Cyan + foreach ($method in $group.Group | Sort-Object Method) { + Write-Host " - $($method.Access) $($method.Method)()" -ForegroundColor White + } + } + Write-Host "" +} + +if ($results.OrphanProperties.Count -gt 0) { + Write-Host "PROPIEDADES HUÉRFANAS" -ForegroundColor Magenta + Write-Host "-" * 80 -ForegroundColor Magenta + + $grouped = $results.OrphanProperties | Group-Object File + foreach ($group in $grouped | Sort-Object Name) { + Write-Host " $($group.Name):" -ForegroundColor Cyan + foreach ($property in $group.Group | Sort-Object Property) { + Write-Host " - $($property.Access) $($property.Property)" -ForegroundColor White + } + } + Write-Host "" +} + +Write-Host "=" * 80 -ForegroundColor Cyan +Write-Host "RESUMEN DE ESTADÍSTICAS" -ForegroundColor Cyan +Write-Host "=" * 80 -ForegroundColor Cyan +Write-Host "" + +Write-Host "Total de archivos .cs analizados: $($csFiles.Count)" -ForegroundColor White +Write-Host "" +Write-Host "Archivos completos huérfanos: $($results.OrphanFiles.Count)" -ForegroundColor $(if ($results.OrphanFiles.Count -gt 0) { "Red" } else { "Green" }) +Write-Host "Tipos huérfanos: $($results.OrphanTypes.Count)" -ForegroundColor $(if ($results.OrphanTypes.Count -gt 0) { "Red" } else { "Green" }) +Write-Host "Métodos huérfanos: $($results.OrphanMethods.Count)" -ForegroundColor $(if ($results.OrphanMethods.Count -gt 0) { "Red" } else { "Green" }) +Write-Host "Propiedades huérfanas: $($results.OrphanProperties.Count)" -ForegroundColor $(if ($results.OrphanProperties.Count -gt 0) { "Red" } else { "Green" }) +Write-Host "" + +$totalOrphans = $results.OrphanFiles.Count + $results.OrphanTypes.Count + $results.OrphanMethods.Count + $results.OrphanProperties.Count +Write-Host "TOTAL DE ELEMENTOS HUÉRFANOS: $totalOrphans" -ForegroundColor $(if ($totalOrphans -gt 0) { "Yellow" } else { "Green" }) + +Write-Host "" +Write-Host "Análisis completado." -ForegroundColor Green diff --git a/FindOrphansFiltered.ps1 b/FindOrphansFiltered.ps1 new file mode 100644 index 0000000..8c133ca --- /dev/null +++ b/FindOrphansFiltered.ps1 @@ -0,0 +1,72 @@ +$rootPath = "D:\TodosProyectos\CSHARP\MauiPdfGenerator" +$projectsToAnalyze = @("MauiPdfGenerator", "MauiPdfGenerator.SourceGenerators") + +$allCsFiles = @() + +foreach ($project in $projectsToAnalyze) { + $projectPath = Join-Path $rootPath $project + $files = Get-ChildItem -Path $projectPath -Filter "*.cs" -Recurse | + Where-Object { $_.FullName -notmatch '\\(obj|bin)\\' } + $allCsFiles += $files +} + +Write-Host "Analizando $($allCsFiles.Count) archivos..." + +$typeRegex = [regex]::new('^\s*(?:public|internal|private|protected)?\s*(?:abstract|sealed|static|partial)?\s*(class|interface|enum|struct|record)\s+(\w+)', [System.Text.RegularExpressions.RegexOptions]::Multiline) + +$allTypes = @{} + +foreach ($file in $allCsFiles) { + $content = Get-Content $file.FullName -Raw + $matches = $typeRegex.Matches($content) + $types = @($matches | ForEach-Object { $_.Groups[2].Value }) + + if ($types.Count -gt 0) { + $allTypes[$file.FullName] = @{ + File = $file.Name + Types = $types + } + } +} + +Write-Host "`n=== TIPOS HUÉRFANOS ===" -ForegroundColor Cyan + +$orphanTypes = @{} +$totalOrphans = 0 + +foreach ($filePath in $allTypes.Keys) { + $data = $allTypes[$filePath] + $orphans = @() + + foreach ($type in $data.Types) { + $found = $false + foreach ($searchFile in $allCsFiles.FullName) { + if ($searchFile -eq $filePath) { continue } + + $result = Select-String -Path $searchFile -Pattern "\b$type\b" -Quiet + if ($result) { $found = $true; break } + } + + if (-not $found) { + $orphans += $type + $totalOrphans++ + } + } + + if ($orphans.Count -gt 0) { + $orphanTypes[$filePath] = $orphans + Write-Host "`n$($data.File)" -ForegroundColor Yellow + Write-Host " Ruta: $filePath" -ForegroundColor DarkGray + $orphans | ForEach-Object { Write-Host " - $_" } + } +} + +Write-Host "`n=== RESUMEN ===" -ForegroundColor Green +Write-Host "Archivos analizados: $($allCsFiles.Count)" +$totalTypes = ($allTypes.Values | ForEach-Object { $_.Types.Count } | Measure-Object -Sum).Sum +Write-Host "Total tipos: $totalTypes" +Write-Host "Tipos huérfanos: $totalOrphans" +if ($totalTypes -gt 0) { + $pct = [math]::Round(($totalOrphans / $totalTypes) * 100, 2) + Write-Host "Porcentaje: $pct%" +} diff --git a/MauiPdfGenerator/Fluent/Models/PdfLayoutDefaultOptions.cs b/MauiPdfGenerator/Common/Models/Layouts/PdfLayoutDefaultOptions.cs similarity index 82% rename from MauiPdfGenerator/Fluent/Models/PdfLayoutDefaultOptions.cs rename to MauiPdfGenerator/Common/Models/Layouts/PdfLayoutDefaultOptions.cs index 54b9280..a9fc751 100644 --- a/MauiPdfGenerator/Fluent/Models/PdfLayoutDefaultOptions.cs +++ b/MauiPdfGenerator/Common/Models/Layouts/PdfLayoutDefaultOptions.cs @@ -1,7 +1,4 @@ -using MauiPdfGenerator.Common.Models; -using MauiPdfGenerator.Common.Models.Layouts; - -namespace MauiPdfGenerator.Fluent.Models; +namespace MauiPdfGenerator.Common.Models.Layouts; public class PdfLayoutDefaultOptions { @@ -18,11 +15,6 @@ public record struct DefaultOptions( VerticalOptions: LayoutAlignment.Start ); - private static readonly DefaultOptions GridCellDefaults = new( - HorizontalOptions: LayoutAlignment.Start, - VerticalOptions: LayoutAlignment.Start - ); - private static readonly DefaultOptions VerticalStackLayoutDefaults = new( HorizontalOptions: LayoutAlignment.Fill, VerticalOptions: LayoutAlignment.Start diff --git a/MauiPdfGenerator/Common/PdfGeneratorConstants.cs b/MauiPdfGenerator/Common/PdfGeneratorConstants.cs deleted file mode 100644 index d8c0a98..0000000 --- a/MauiPdfGenerator/Common/PdfGeneratorConstants.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace MauiPdfGenerator.Common; - -internal static class PdfGeneratorConstants -{ - public const string PdfFontRegistryBuilderKey = "MauiPdfGenerator_FontRegistryBuilder"; -} diff --git a/MauiPdfGenerator/Core/Implementation/Sk/Models/SpanRun.cs b/MauiPdfGenerator/Core/Implementation/Sk/Models/SpanRun.cs index 58c3972..a804d23 100644 --- a/MauiPdfGenerator/Core/Implementation/Sk/Models/SpanRun.cs +++ b/MauiPdfGenerator/Core/Implementation/Sk/Models/SpanRun.cs @@ -10,12 +10,3 @@ internal record SpanRun( TextDecorations? Decorations, TextTransform? Transform ); - -internal record LineRunInfo( - string Line, - int LineStartIndex, - List IntersectingRuns -) -{ - public bool HasMultipleRuns => IntersectingRuns.Count > 1; -} diff --git a/MauiPdfGenerator/Core/Implementation/Sk/Pages/ContentPageOrchestrator.cs b/MauiPdfGenerator/Core/Implementation/Sk/Pages/ContentPageOrchestrator.cs deleted file mode 100644 index 8c0aa8d..0000000 --- a/MauiPdfGenerator/Core/Implementation/Sk/Pages/ContentPageOrchestrator.cs +++ /dev/null @@ -1,137 +0,0 @@ -using MauiPdfGenerator.Core.Models; -using MauiPdfGenerator.Common.Models; -using Microsoft.Extensions.Logging; -using SkiaSharp; -using MauiPdfGenerator.Diagnostics; -using MauiPdfGenerator.Diagnostics.Enums; -using MauiPdfGenerator.Diagnostics.Models; - -namespace MauiPdfGenerator.Core.Implementation.Sk.Pages; - -internal class ContentPageOrchestrator -{ - public async Task<(List ArrangedElements, Queue RemainingElements)> ProcessPageAsync( - Queue elements, - PdfRect contentRect, - PdfGenerationContext context) - { - var arrangedElementsOnPage = new List(); - var spilloverElements = new List(); - var currentY = contentRect.Top; - var remainingHeight = contentRect.Height; - - context.Logger.LogTrace("Starting layout for new page. Available height: {RemainingHeight}", remainingHeight); - - while (elements.Count > 0) - { - var element = elements.Peek(); - var renderer = context.RendererFactory.GetRenderer(element); - var elementContext = context with { Element = element }; - - context.Logger.LogTrace("Measuring element {ElementType}", element.GetType().Name); - // --- CORRECCIÓN: Pasamos un SKSize en lugar de un SKRect --- - var availableSizeForMeasure = new SKSize(contentRect.Width, float.PositiveInfinity); - var measureInfo = await renderer.MeasureAsync(elementContext, availableSizeForMeasure); - context.Logger.LogTrace("Element measured. Desired height: {DesiredHeight}", measureInfo.Height); - - if (measureInfo.Height <= remainingHeight) - { - // El elemento cabe completo en el espacio restante. - elements.Dequeue(); - var arrangeInfo = await ArrangeElementAsync(element, renderer, elementContext, contentRect, currentY, measureInfo.Height); - arrangedElementsOnPage.Add(arrangeInfo); - currentY += arrangeInfo.Height; - remainingHeight -= arrangeInfo.Height; - context.Logger.LogTrace("Element arranged. Consumed height: {ConsumedHeight}, Remaining height: {RemainingHeight}", arrangeInfo.Height, remainingHeight); - } - else - { - // El elemento no cabe completo. - elements.Dequeue(); // Lo consumimos de la cola actual. - - // Le pedimos que se disponga en el espacio que SÍ queda. - var arrangeInfo = await ArrangeElementAsync(element, renderer, elementContext, contentRect, currentY, remainingHeight); - - if (arrangeInfo.Height > 0) - { - // Una parte del elemento cupo (caso de elemento divisible). - arrangedElementsOnPage.Add(arrangeInfo); - } - - if (arrangeInfo.RemainingElement is not null) - { - // El resto va a la siguiente página. - spilloverElements.Add(arrangeInfo.RemainingElement); - } - else if (arrangeInfo.Height <= 0) - { - // No cupo nada del elemento (era atómico o no cabía ni un fragmento). - if (measureInfo.Height > contentRect.Height) - { - // El elemento es más grande que una página completa. Se omite. - context.DiagnosticSink.Submit(new DiagnosticMessage( - DiagnosticSeverity.Warning, - DiagnosticCodes.PageContentOversized, - $"The element of type '{element.GetType().Name}' has a required height of {measureInfo.Height}, which is larger than the available page height of {contentRect.Height}. The element will be skipped.", - new DiagnosticRect(contentRect.X, currentY, contentRect.Width, measureInfo.Height) - )); - } - else - { - // Lo devolvemos a la cola para la siguiente página. - spilloverElements.Add(element); - } - } - - // La página está llena, ya sea porque un elemento se dividió o porque uno atómico no cupo. - break; - } - } - - // Preparamos la cola para la siguiente página, añadiendo primero los elementos sobrantes. - var nextQueue = new Queue(); - foreach (var item in spilloverElements) - { - nextQueue.Enqueue(item); - } - foreach (var item in elements) - { - nextQueue.Enqueue(item); - } - - context.Logger.LogTrace("Page composition complete. {ElementCount} elements placed.", arrangedElementsOnPage.Count); - return (arrangedElementsOnPage, nextQueue); - } - - private async Task ArrangeElementAsync( - PdfElementData element, - IElementRenderer renderer, - PdfGenerationContext elementContext, - PdfRect contentRect, - float currentY, - float availableHeight) - { - // --- CORRECCIÓN: Pasamos un SKSize en lugar de un SKRect --- - var measureInfo = await renderer.MeasureAsync(elementContext, new SKSize(contentRect.Width, float.PositiveInfinity)); - - var elementWidth = element.GetHorizontalOptions is LayoutAlignment.Fill - ? contentRect.Width - : Math.Min(measureInfo.Width, contentRect.Width); - - var offsetX = element.GetHorizontalOptions switch - { - LayoutAlignment.Center => (contentRect.Width - elementWidth) / 2f, - LayoutAlignment.End => contentRect.Width - elementWidth, - _ => 0f - }; - - var finalRect = new PdfRect( - contentRect.Left + offsetX, - currentY, - elementWidth, - availableHeight); - - var arrangeInfo = await renderer.ArrangeAsync(finalRect, elementContext); - return arrangeInfo; - } -} diff --git a/MauiPdfGenerator/Core/Implementation/Sk/Utils/SkiaUtils.cs b/MauiPdfGenerator/Core/Implementation/Sk/Utils/SkiaUtils.cs index 3daa578..c51a763 100644 --- a/MauiPdfGenerator/Core/Implementation/Sk/Utils/SkiaUtils.cs +++ b/MauiPdfGenerator/Core/Implementation/Sk/Utils/SkiaUtils.cs @@ -114,10 +114,7 @@ internal static class SkiaUtils typefaceFromExplicitFile?.Dispose(); return finalTypeface; } - internal static string? GetMauiFontFilePath(string fontAlias) - { - return null; - } + public static SKColor ConvertToSkColor(Color? mauiColor) { if (mauiColor is null) return SKColors.Black; @@ -127,6 +124,7 @@ public static SKColor ConvertToSkColor(Color? mauiColor) float a = Math.Clamp(mauiColor.Alpha, 0f, 1f); return new SKColor((byte)(r * 255), (byte)(g * 255), (byte)(b * 255), (byte)(a * 255)); } + public static SKSize GetSkPageSize(PageSizeType size, PageOrientationType orientation) { float width, height; diff --git a/MauiPdfGenerator/Core/Implementation/Sk/Views/TextRenderer.cs b/MauiPdfGenerator/Core/Implementation/Sk/Views/TextRenderer.cs index 95cb433..087120f 100644 --- a/MauiPdfGenerator/Core/Implementation/Sk/Views/TextRenderer.cs +++ b/MauiPdfGenerator/Core/Implementation/Sk/Views/TextRenderer.cs @@ -658,36 +658,6 @@ private void DrawTextDecorations(SKCanvas canvas, SKFont font, SKPaint paint, Te return resultingLines; } - private List WrapTextToLines(string text, SKFont font, float maxWidth, LineBreakMode lineBreakMode, MultiFontTextRenderer? multiFontRenderer = null) - { - var lines = new List(); - if (string.IsNullOrEmpty(text)) return lines; - - string normalizedText = PdfStringUtils.NormalizeNewlines(text); - string[] textSegments = normalizedText.Split(PdfStringUtils.NormalizeNewline); - - foreach (string segment in textSegments) - { - if (maxWidth <= 0 || lineBreakMode is LineBreakMode.NoWrap) - { - lines.Add(segment); - continue; - } - - if (lineBreakMode is LineBreakMode.HeadTruncation or LineBreakMode.MiddleTruncation or LineBreakMode.TailTruncation) - { - float segmentWidth = multiFontRenderer?.MeasureTextWidth(segment) ?? font.MeasureText(segment); - if (segmentWidth <= maxWidth) lines.Add(segment); - else lines.Add(ApplyLineBreakModeTruncation(segment, font, maxWidth, lineBreakMode, multiFontRenderer)); - } - else - { - lines.AddRange(ApplyLineBreakModeWrapping(segment, font, maxWidth, lineBreakMode, multiFontRenderer)); - } - } - return lines; - } - private string ApplyLineBreakModeTruncation(string textSegment, SKFont font, float maxWidth, LineBreakMode lineBreakMode, MultiFontTextRenderer? multiFontRenderer = null) { float ellipsisWidth = multiFontRenderer?.MeasureTextWidth(Ellipsis) ?? font.MeasureText(Ellipsis); @@ -775,91 +745,6 @@ private long CountCharactersInWidth(string text, float maxWidth, MultiFontTextRe return text.Length; } - private List ApplyLineBreakModeWrapping(string singleLine, SKFont font, float maxWidth, LineBreakMode lineBreakMode, MultiFontTextRenderer? multiFontRenderer = null) - { - var resultingLines = new List(); - if (string.IsNullOrEmpty(singleLine)) { resultingLines.Add(string.Empty); return resultingLines; } - - float singleLineWidth = multiFontRenderer?.MeasureTextWidth(singleLine) ?? font.MeasureText(singleLine); - if (singleLineWidth <= maxWidth) { resultingLines.Add(singleLine); return resultingLines; } - - int currentPosition = 0; - int textLength = singleLine.Length; - while (currentPosition < textLength) - { - long countMeasured; - if (multiFontRenderer != null) - { - countMeasured = CountCharactersInWidth(singleLine.Substring(currentPosition), maxWidth, multiFontRenderer); - } - else - { - countMeasured = font.BreakText(singleLine.AsSpan(currentPosition), maxWidth); - } - int count = (int)countMeasured; - - if (count == 0 && currentPosition < textLength) - { - float charWidth = multiFontRenderer?.MeasureTextWidth(singleLine[currentPosition].ToString()) ?? font.MeasureText(singleLine[currentPosition].ToString()); - if (charWidth > maxWidth) - { - resultingLines.Add(singleLine.Substring(currentPosition, 1)); - currentPosition += 1; - continue; - } - count = 1; - } - - int breakPositionAttempt = currentPosition + count; - - if (breakPositionAttempt >= textLength) - { - resultingLines.Add(singleLine[currentPosition..]); - break; - } - - int actualBreakPosition = breakPositionAttempt; - - if (lineBreakMode is LineBreakMode.WordWrap) - { - string segmentToConsider = singleLine.Substring(currentPosition, count); - int lastValidBreakInSegment = -1; - for (int k = segmentToConsider.Length - 1; k >= 0; --k) - { - if (char.IsWhiteSpace(segmentToConsider[k]) || segmentToConsider[k] == '-') - { - lastValidBreakInSegment = k; - break; - } - } - - if (lastValidBreakInSegment > 0 && currentPosition + lastValidBreakInSegment + 1 > currentPosition) - { - actualBreakPosition = currentPosition + lastValidBreakInSegment + 1; - } - else - { - actualBreakPosition = currentPosition + count; - } - } - - if (actualBreakPosition <= currentPosition && currentPosition < textLength) - { - actualBreakPosition = currentPosition + 1; - } - - string lineToAdd = singleLine[currentPosition..actualBreakPosition].TrimEnd(); - resultingLines.Add(lineToAdd); - currentPosition = actualBreakPosition; - - while (currentPosition < textLength && char.IsWhiteSpace(singleLine[currentPosition])) - { - currentPosition++; - } - } - return resultingLines; - } - #region Span Support private async Task> ResolveSpanRunsAsync( PdfParagraphData paragraph, @@ -960,16 +845,5 @@ private async Task> ResolveSpanRunsAsync( return runs; } - - private string ApplyTextTransform(string text, TextTransform? transform) - { - return transform switch - { - TextTransform.Uppercase => text.ToUpperInvariant(), - TextTransform.Lowercase => text.ToLowerInvariant(), - _ => text - }; - } - #endregion } diff --git a/MauiPdfGenerator/Core/Interfaces/ITextFragment.cs b/MauiPdfGenerator/Core/Interfaces/ITextFragment.cs deleted file mode 100644 index 02b18b8..0000000 --- a/MauiPdfGenerator/Core/Interfaces/ITextFragment.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace MauiPdfGenerator.Core.Interfaces; - -public interface ITextFragment -{ - string Text { get; } -} \ No newline at end of file diff --git a/MauiPdfGenerator/Core/Interfaces/ITextLine.cs b/MauiPdfGenerator/Core/Interfaces/ITextLine.cs deleted file mode 100644 index 61ea697..0000000 --- a/MauiPdfGenerator/Core/Interfaces/ITextLine.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System.Collections.Generic; - -namespace MauiPdfGenerator.Core.Interfaces; - -public interface ITextLine -{ - IReadOnlyList Fragments { get; } -} \ No newline at end of file diff --git a/MauiPdfGenerator/Core/Utils/TextRendererHelpers.cs b/MauiPdfGenerator/Core/Utils/TextRendererHelpers.cs deleted file mode 100644 index aaacb01..0000000 --- a/MauiPdfGenerator/Core/Utils/TextRendererHelpers.cs +++ /dev/null @@ -1,39 +0,0 @@ -using MauiPdfGenerator.Core.Interfaces; - -namespace MauiPdfGenerator.Core.Utils; - -internal interface ITextMeasurer -{ - float MeasureWidth(string text); -} - -internal interface IFontMeasurer : ITextMeasurer -{ - float Ascent { get; } - float Descent { get; } - float LineAdvance { get; } -} - -internal static class TextRendererHelpers -{ - public static async Task MeasureLinesAsync(IEnumerable lines, IFontMeasurer measurer) - { - if (!lines.Any()) return 0; - if (lines.Count() == 1) - { - return measurer.LineAdvance; - } - else - { - float visualTopOffset = -measurer.Ascent; - float visualBottomOffset = measurer.Descent; - return visualTopOffset + ((lines.Count() - 1) * measurer.LineAdvance) + visualBottomOffset; - } - } -} - -internal record DecorationOptions -{ - public bool Underline { get; init; } - public bool Strikethrough { get; init; } -} diff --git a/MauiPdfGenerator/Fluent/Builders/PageContentBuilder.cs b/MauiPdfGenerator/Fluent/Builders/PageContentBuilder.cs deleted file mode 100644 index fd870f3..0000000 --- a/MauiPdfGenerator/Fluent/Builders/PageContentBuilder.cs +++ /dev/null @@ -1,73 +0,0 @@ -using MauiPdfGenerator.Common.Models.Styling; -using MauiPdfGenerator.Fluent.Builders.Views; -using MauiPdfGenerator.Fluent.Builders.Layouts; -using MauiPdfGenerator.Fluent.Interfaces.Builders; -using MauiPdfGenerator.Fluent.Interfaces.Layouts; -using MauiPdfGenerator.Fluent.Interfaces.Pages; -using MauiPdfGenerator.Fluent.Interfaces.Views; - -namespace MauiPdfGenerator.Fluent.Builders; - -internal class PageContentBuilder : IPageContentBuilder -{ - private readonly List _children = []; - private readonly PdfFontRegistryBuilder _fontRegistry; - private readonly PdfResourceDictionary? _resourceDictionary; - - internal PageContentBuilder(PdfFontRegistryBuilder fontRegistry, PdfResourceDictionary? resourceDictionary = null) - { - _fontRegistry = fontRegistry ?? throw new ArgumentNullException(nameof(fontRegistry)); - _resourceDictionary = resourceDictionary; - } - - internal IReadOnlyList GetBuildableChildren() => _children.AsReadOnly(); - - public IPdfPageChildParagraph Paragraph(string text) - { - var builder = new PdfParagraphBuilder(text, _fontRegistry, _resourceDictionary); - _children.Add(builder); - return builder; - } - - public IPdfPageChildParagraph Paragraph(Action configure) - { - var builder = new PdfParagraphBuilder(configure, _fontRegistry, _resourceDictionary); - _children.Add(builder); - return builder; - } - - public IPdfPageChildHorizontalLine HorizontalLine() - { - var builder = new PdfHorizontalLineBuilder(); - _children.Add(builder); - return builder; - } - - public IPdfPageChildImage Image(Stream stream) - { - var builder = new PdfImageBuilder(stream); - _children.Add(builder); - return builder; - } - - public void VerticalStackLayout(Action layoutSetup) - { - var stackBuilder = new PdfVerticalStackLayoutBuilder(_fontRegistry, _resourceDictionary); - layoutSetup(stackBuilder); - _children.Add(stackBuilder); - } - - public void HorizontalStackLayout(Action layoutSetup) - { - var stackBuilder = new PdfHorizontalStackLayoutBuilder(_fontRegistry, _resourceDictionary); - layoutSetup(stackBuilder); - _children.Add(stackBuilder); - } - - public void Grid(Action layoutSetup) - { - var gridBuilder = new PdfGridBuilder(_fontRegistry, _resourceDictionary); - layoutSetup(gridBuilder); - _children.Add(gridBuilder); - } -} diff --git a/MauiPdfGenerator/Fluent/Interfaces/Builders/IGridConfiguration.cs b/MauiPdfGenerator/Fluent/Interfaces/Builders/IGridConfiguration.cs deleted file mode 100644 index c40286a..0000000 --- a/MauiPdfGenerator/Fluent/Interfaces/Builders/IGridConfiguration.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace MauiPdfGenerator.Fluent.Interfaces.Builders; - -public interface IGridConfiguration -{ -} diff --git a/MauiPdfGenerator/Fluent/Interfaces/IPdfPage.cs b/MauiPdfGenerator/Fluent/Interfaces/IPdfPage.cs deleted file mode 100644 index e78f682..0000000 --- a/MauiPdfGenerator/Fluent/Interfaces/IPdfPage.cs +++ /dev/null @@ -1,24 +0,0 @@ -using MauiPdfGenerator.Fluent.Enums; - -namespace MauiPdfGenerator.Fluent.Interfaces; - -public interface IPdfPage where TSelf : IPdfPage -{ - TSelf PageSize(PageSizeType pageSizeType); - - TSelf PageOrientation(PageOrientationType pageOrientationType); - - TSelf Padding(float uniformPadding); - - TSelf Padding(float verticalPadding, float horizontalPadding); - - TSelf Padding(float leftPadding, float topPadding, float rightPadding, float bottomPadding); - - TSelf Padding(DefaultPagePaddingType defaultPaddingType); - - TSelf BackgroundColor(Color backgroundColor); - - TSelf Culture(string cultureName); - - IPdfDocument Build(); -} diff --git a/MauiPdfGenerator/Fluent/Interfaces/Pages/IPdfContentPage.cs b/MauiPdfGenerator/Fluent/Interfaces/Pages/IPdfContentPage.cs deleted file mode 100644 index abad248..0000000 --- a/MauiPdfGenerator/Fluent/Interfaces/Pages/IPdfContentPage.cs +++ /dev/null @@ -1,19 +0,0 @@ -using MauiPdfGenerator.Fluent.Interfaces.Builders; - -namespace MauiPdfGenerator.Fluent.Interfaces.Pages; - -public interface IPdfContentPage where TContent : class -{ - IPdfContentPage PageSize(Enums.PageSizeType pageSizeType); - IPdfContentPage PageOrientation(Enums.PageOrientationType pageOrientationType); - IPdfContentPage Padding(float uniformPadding); - IPdfContentPage Padding(float verticalPadding, float horizontalPadding); - IPdfContentPage Padding(float leftPadding, float topPadding, float rightPadding, float bottomPadding); - IPdfContentPage Padding(Enums.DefaultPagePaddingType defaultPaddingType); - IPdfContentPage BackgroundColor(Color backgroundColor); - IPdfContentPage DefaultFont(Action fontDefaults); - IPdfContentPage DefaultTextColor(Color color); - IPdfContentPage DefaultTextDecorations(TextDecorations decorations); - IPdfContentPage DefaultTextTransform(TextTransform transform); - IPageReadyToBuild Content(Action contentSetup); -} From 6d4f4cad0986e30febc32b07edf258871da96f14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Avila=20Catal=C3=A1?= Date: Sun, 1 Feb 2026 13:41:34 -0600 Subject: [PATCH 2/4] Delete FindOrphans.ps1 --- FindOrphans.ps1 | 117 ------------------------------------------------ 1 file changed, 117 deletions(-) delete mode 100644 FindOrphans.ps1 diff --git a/FindOrphans.ps1 b/FindOrphans.ps1 deleted file mode 100644 index 4dc43ec..0000000 --- a/FindOrphans.ps1 +++ /dev/null @@ -1,117 +0,0 @@ -# Script para encontrar tipos huérfanos en proyectos C# -$projectPaths = @( - "D:\TodosProyectos\CSHARP\MauiPdfGenerator\MauiPdfGenerator", - "D:\TodosProyectos\CSHARP\MauiPdfGenerator\MauiPdfGenerator.SourceGenerators" -) - -# Obtener todos los archivos .cs excluyendo directorios obj/ -$allCsFiles = @() -foreach ($projectPath in $projectPaths) { - $files = Get-ChildItem -Path $projectPath -Filter "*.cs" -Recurse -File | - Where-Object { $_.FullName -notmatch "\\obj\\" } - $allCsFiles += $files -} - -Write-Host "Analizando $($allCsFiles.Count) archivos .cs..." -ForegroundColor Cyan - -# Diccionario para almacenar tipos encontrados: Key = Tipo, Value = Info (Archivo, Línea) -$allTypes = @{} - -# Expresión regular para encontrar definiciones de tipos -$typeRegex = [regex]::new('^\s*(?:public|internal|private|protected)?\s*(?:sealed|abstract|static|partial)?\s*(class|interface|enum|struct|record)\s+(\w+)', [System.Text.RegularExpressions.RegexOptions]::Multiline) - -# Paso 1: Extraer todas las definiciones de tipos -Write-Host "`nExtrayendo definiciones de tipos..." -ForegroundColor Yellow - -foreach ($file in $allCsFiles) { - $content = Get-Content -Path $file.FullName -Raw - $matches = $typeRegex.Matches($content) - - foreach ($match in $matches) { - $typeName = $match.Groups[2].Value - $typeKind = $match.Groups[1].Value - $lineNumber = ($content.Substring(0, $match.Index).Split("`n").Length) - - $allTypes[$typeName] = @{ - Name = $typeName - Kind = $typeKind - File = $file.Name - FilePath = $file.FullName - Line = $lineNumber - Referenced = $false - ReferencedBy = @() - } - } -} - -Write-Host "Se encontraron $($allTypes.Count) tipos definidos." -ForegroundColor Green - -# Paso 2: Buscar referencias en todos los archivos -Write-Host "`nBuscando referencias..." -ForegroundColor Yellow - -foreach ($file in $allCsFiles) { - $content = Get-Content -Path $file.FullName -Raw - $fileNameWithoutExtension = [System.IO.Path]::GetFileNameWithoutExtension($file.Name) - - foreach ($typeName in $allTypes.Keys) { - # No contar como referencia si es el mismo archivo - if ($allTypes[$typeName].FilePath -eq $file.FullName) { - continue - } - - # Buscar el tipo como palabra completa en el contenido - if ($content -match "\b$typeName\b") { - $allTypes[$typeName].Referenced = $true - $allTypes[$typeName].ReferencedBy += $file.Name - } - } -} - -# Paso 3: Organizar tipos huérfanos por archivo -Write-Host "`n`n========================================" -ForegroundColor Cyan -Write-Host "TIPOS HUÉRFANOS (No referenciados)" -ForegroundColor Cyan -Write-Host "========================================" -ForegroundColor Cyan - -$orphanTypesByFile = @{} -$totalOrphans = 0 - -foreach ($typeInfo in $allTypes.Values) { - if (-not $typeInfo.Referenced) { - if (-not $orphanTypesByFile.ContainsKey($typeInfo.FilePath)) { - $orphanTypesByFile[$typeInfo.FilePath] = @() - } - $orphanTypesByFile[$typeInfo.FilePath] += $typeInfo - $totalOrphans++ - } -} - -# Mostrar resultados organizados por archivo -if ($orphanTypesByFile.Count -eq 0) { - Write-Host "`nNo se encontraron tipos huérfanos." -ForegroundColor Green -} else { - foreach ($filePath in $orphanTypesByFile.Keys | Sort-Object) { - $orphans = $orphanTypesByFile[$filePath] - Write-Host "`n----------------------------------------" -ForegroundColor Gray - Write-Host "Archivo: $($orphanTypesByFile[$filePath][0].File)" -ForegroundColor White - Write-Host "Ruta: $filePath" -ForegroundColor DarkGray - Write-Host "----------------------------------------" -ForegroundColor Gray - - foreach ($orphan in $orphans) { - Write-Host " - $($orphan.Kind): $($orphan.Name) (línea $($orphan.Line))" -ForegroundColor Yellow - } - } -} - -# Paso 4: Resumen final -Write-Host "`n`n========================================" -ForegroundColor Cyan -Write-Host "RESUMEN" -ForegroundColor Cyan -Write-Host "========================================" -ForegroundColor Cyan -Write-Host "Total de tipos analizados: $($allTypes.Count)" -ForegroundColor White -Write-Host "Total de tipos huérfanos: $totalOrphans" -ForegroundColor $(if ($totalOrphans -gt 0) { "Yellow" } else { "Green" }) - -if ($allTypes.Count -gt 0) { - $percentage = [math]::Round(($totalOrphans / $allTypes.Count) * 100, 2) - Write-Host "Porcentaje de huérfanos: $percentage%" -ForegroundColor $(if ($percentage -gt 10) { "Red" } elseif ($percentage -gt 5) { "Yellow" } else { "Green" }) -} - -Write-Host "`n========================================" -ForegroundColor Cyan From e7625366952c3e9d9fbd8bb124bd31a8c89e870e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Avila=20Catal=C3=A1?= Date: Sun, 1 Feb 2026 13:42:13 -0600 Subject: [PATCH 3/4] Delete FindOrphansFiltered.ps1 --- FindOrphansFiltered.ps1 | 72 ----------------------------------------- 1 file changed, 72 deletions(-) delete mode 100644 FindOrphansFiltered.ps1 diff --git a/FindOrphansFiltered.ps1 b/FindOrphansFiltered.ps1 deleted file mode 100644 index 8c133ca..0000000 --- a/FindOrphansFiltered.ps1 +++ /dev/null @@ -1,72 +0,0 @@ -$rootPath = "D:\TodosProyectos\CSHARP\MauiPdfGenerator" -$projectsToAnalyze = @("MauiPdfGenerator", "MauiPdfGenerator.SourceGenerators") - -$allCsFiles = @() - -foreach ($project in $projectsToAnalyze) { - $projectPath = Join-Path $rootPath $project - $files = Get-ChildItem -Path $projectPath -Filter "*.cs" -Recurse | - Where-Object { $_.FullName -notmatch '\\(obj|bin)\\' } - $allCsFiles += $files -} - -Write-Host "Analizando $($allCsFiles.Count) archivos..." - -$typeRegex = [regex]::new('^\s*(?:public|internal|private|protected)?\s*(?:abstract|sealed|static|partial)?\s*(class|interface|enum|struct|record)\s+(\w+)', [System.Text.RegularExpressions.RegexOptions]::Multiline) - -$allTypes = @{} - -foreach ($file in $allCsFiles) { - $content = Get-Content $file.FullName -Raw - $matches = $typeRegex.Matches($content) - $types = @($matches | ForEach-Object { $_.Groups[2].Value }) - - if ($types.Count -gt 0) { - $allTypes[$file.FullName] = @{ - File = $file.Name - Types = $types - } - } -} - -Write-Host "`n=== TIPOS HUÉRFANOS ===" -ForegroundColor Cyan - -$orphanTypes = @{} -$totalOrphans = 0 - -foreach ($filePath in $allTypes.Keys) { - $data = $allTypes[$filePath] - $orphans = @() - - foreach ($type in $data.Types) { - $found = $false - foreach ($searchFile in $allCsFiles.FullName) { - if ($searchFile -eq $filePath) { continue } - - $result = Select-String -Path $searchFile -Pattern "\b$type\b" -Quiet - if ($result) { $found = $true; break } - } - - if (-not $found) { - $orphans += $type - $totalOrphans++ - } - } - - if ($orphans.Count -gt 0) { - $orphanTypes[$filePath] = $orphans - Write-Host "`n$($data.File)" -ForegroundColor Yellow - Write-Host " Ruta: $filePath" -ForegroundColor DarkGray - $orphans | ForEach-Object { Write-Host " - $_" } - } -} - -Write-Host "`n=== RESUMEN ===" -ForegroundColor Green -Write-Host "Archivos analizados: $($allCsFiles.Count)" -$totalTypes = ($allTypes.Values | ForEach-Object { $_.Types.Count } | Measure-Object -Sum).Sum -Write-Host "Total tipos: $totalTypes" -Write-Host "Tipos huérfanos: $totalOrphans" -if ($totalTypes -gt 0) { - $pct = [math]::Round(($totalOrphans / $totalTypes) * 100, 2) - Write-Host "Porcentaje: $pct%" -} From dbbddafb47fc02ed81b61a8db4e84b034b673cae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Avila=20Catal=C3=A1?= Date: Sun, 1 Feb 2026 13:42:44 -0600 Subject: [PATCH 4/4] Delete FindOrphansComplete.ps1 --- FindOrphansComplete.ps1 | 322 ---------------------------------------- 1 file changed, 322 deletions(-) delete mode 100644 FindOrphansComplete.ps1 diff --git a/FindOrphansComplete.ps1 b/FindOrphansComplete.ps1 deleted file mode 100644 index ddda73a..0000000 --- a/FindOrphansComplete.ps1 +++ /dev/null @@ -1,322 +0,0 @@ -$ErrorActionPreference = "Stop" - -$projectRoot = Split-Path -Parent $MyInvocation.MyCommand.Path -$csFiles = Get-ChildItem -Path $projectRoot -Filter "*.cs" -Recurse -File - -$results = @{ - OrphanFiles = @() - OrphanTypes = @() - OrphanMethods = @() - OrphanProperties = @() -} - -Write-Host "Analizando proyecto en: $projectRoot" -ForegroundColor Cyan -Write-Host "Encontrados $($csFiles.Count) archivos .cs" -ForegroundColor Cyan -Write-Host "" - -function Get-TypeDefinitions { - param([string]$content) - - $patterns = @( - '(?m)^\s*(public|internal|protected|private)?\s*(partial\s+)?(class|interface|struct|enum|record)\s+(\w+)' - ) - - $types = @() - foreach ($pattern in $patterns) { - $matches = [regex]::Matches($content, $pattern) - foreach ($match in $matches) { - $access = if ($match.Groups[1].Value) { $match.Groups[1].Value } else { "internal" } - $keyword = $match.Groups[3].Value - $name = $match.Groups[4].Value - - if ($access -in @("public", "internal") -and $keyword -eq "interface") { - continue - } - - $types += [PSCustomObject]@{ - Name = $name - Access = $access - Keyword = $keyword - FullName = "$keyword $name" - } - } - } - return $types -} - -function Get-MethodDefinitions { - param([string]$content) - - $patterns = @( - '(?m)^\s*(public|protected)\s+(?:override\s+)?(?:virtual\s+)?(?:async\s+)?(?:static\s+)?(?:new\s+)?[\w<>[\],\s]+\s+(\w+)\s*\(', - '(?m)^\s*(public|protected)\s+(?:override\s+)?(?:virtual\s+)?(?:async\s+)?(?:static\s+)?(?:new\s+)?\w+\s+(\w+)\s*\(' - ) - - $methods = @() - foreach ($pattern in $patterns) { - $matches = [regex]::Matches($content, $pattern) - foreach ($match in $matches) { - $access = $match.Groups[1].Value - $name = $match.Groups[2].Value - - if ($name -match '^(get|set|add|remove)$') { continue } - - $methods += [PSCustomObject]@{ - Name = $name - Access = $access - } - } - } - return $methods -} - -function Get-PropertyDefinitions { - param([string]$content) - - $patterns = @( - '(?m)^\s*(public|protected)\s+[\w<>[\],\s]+\s+(\w+)\s*\{', - '(?m)^\s*(public|protected)\s+(?:override\s+)?(?:virtual\s+)?[\w<>[\],\s]+\s+(\w+)\s*\{' - ) - - $properties = @() - foreach ($pattern in $patterns) { - $matches = [regex]::Matches($content, $pattern) - foreach ($match in $matches) { - $access = $match.Groups[1].Value - $name = $match.Groups[2].Value - - $properties += [PSCustomObject]@{ - Name = $name - Access = $access - } - } - } - return $properties -} - -function Is-ReferencedInOtherFiles { - param( - [string]$name, - [string]$currentFile, - [string[]]$allFiles - ) - - foreach ($file in $allFiles) { - if ($file -eq $currentFile) { continue } - - $matches = Select-String -Path $file -Pattern "\b$name\b" -ErrorAction SilentlyContinue - if ($matches) { - return $true - } - } - return $false -} - -function Get-FileImports { - param([string]$filePath) - - $content = Get-Content $filePath -Raw - $imports = @() - - $matches = [regex]::Matches($content, '(?m)^\s*using\s+([^;]+);') - foreach ($match in $matches) { - $import = $match.Groups[1].Value.Trim() - if ($import -notmatch '^(System|Microsoft|Maui|Android|Apple|iOS)') { - $imports += $import - } - } - - return $imports -} - -$fileNames = $csFiles | Select-Object -ExpandProperty FullName -$fileBasenames = @{} - -foreach ($file in $csFiles) { - $basename = [System.IO.Path]::GetFileNameWithoutExtension($file.Name) - $fileBasenames[$file.FullName] = $basename -} - -Write-Host "1. Buscando archivos completos huérfanos..." -ForegroundColor Yellow - -foreach ($file in $csFiles) { - $basename = $fileBasenames[$file.FullName] - $isReferenced = $false - - foreach ($otherFile in $csFiles) { - if ($otherFile.FullName -eq $file.FullName) { continue } - - $imports = Get-FileImports $otherFile.FullName - foreach ($import in $imports) { - $importName = $import -replace '.*\.' - if ($importName -eq $basename -or $import -eq $basename) { - $isReferenced = $true - break - } - } - - if ($isReferenced) { break } - } - - if (-not $isReferenced) { - $results.OrphanFiles += $file.FullName.Replace($projectRoot, "").Trim("\") - } -} - -Write-Host " Encontrados $($results.OrphanFiles.Count) archivos huérfanos" -ForegroundColor Gray -Write-Host "" - -Write-Host "2. Buscando tipos huérfanos..." -ForegroundColor Yellow - -foreach ($file in $csFiles) { - $content = Get-Content $file.FullName -Raw - $types = Get-TypeDefinitions $content - - foreach ($type in $types) { - if ($type.Access -eq "public" -or $type.Keyword -eq "interface") { - continue - } - - if ($content -match "\[Generator\]") { - continue - } - - $isReferenced = Is-ReferencedInOtherFiles $type.Name $file.FullName $fileNames - - if (-not $isReferenced) { - $relativePath = $file.FullName.Replace($projectRoot, "").Trim("\") - $results.OrphanTypes += [PSCustomObject]@{ - File = $relativePath - Type = $type.FullName - } - } - } -} - -Write-Host " Encontrados $($results.OrphanTypes.Count) tipos huérfanos" -ForegroundColor Gray -Write-Host "" - -Write-Host "3. Buscando métodos huérfanos..." -ForegroundColor Yellow - -foreach ($file in $csFiles) { - $content = Get-Content $file.FullName -Raw - $methods = Get-MethodDefinitions $content - - foreach ($method in $methods) { - if ($content -match "\[Test\]|\[Theory\]|\[Fact\]") { - continue - } - - $isReferenced = Is-ReferencedInOtherFiles $method.Name $file.FullName $fileNames - - if (-not $isReferenced) { - $relativePath = $file.FullName.Replace($projectRoot, "").Trim("\") - $results.OrphanMethods += [PSCustomObject]@{ - File = $relativePath - Method = $method.Name - Access = $method.Access - } - } - } -} - -Write-Host " Encontrados $($results.OrphanMethods.Count) métodos huérfanos" -ForegroundColor Gray -Write-Host "" - -Write-Host "4. Buscando propiedades huérfanas..." -ForegroundColor Yellow - -foreach ($file in $csFiles) { - $content = Get-Content $file.FullName -Raw - $properties = Get-PropertyDefinitions $content - - foreach ($property in $properties) { - $isReferenced = Is-ReferencedInOtherFiles $property.Name $file.FullName $fileNames - - if (-not $isReferenced) { - $relativePath = $file.FullName.Replace($projectRoot, "").Trim("\") - $results.OrphanProperties += [PSCustomObject]@{ - File = $relativePath - Property = $property.Name - Access = $property.Access - } - } - } -} - -Write-Host " Encontradas $($results.OrphanProperties.Count) propiedades huérfanas" -ForegroundColor Gray -Write-Host "" - -Write-Host "=" * 80 -ForegroundColor Cyan -Write-Host "RESULTADOS DETALLADOS" -ForegroundColor Cyan -Write-Host "=" * 80 -ForegroundColor Cyan -Write-Host "" - -if ($results.OrphanFiles.Count -gt 0) { - Write-Host "ARCHIVOS COMPLETOS HUÉRFANOS" -ForegroundColor Magenta - Write-Host "-" * 80 -ForegroundColor Magenta - foreach ($file in $results.OrphanFiles | Sort-Object) { - Write-Host " $file" -ForegroundColor White - } - Write-Host "" -} - -if ($results.OrphanTypes.Count -gt 0) { - Write-Host "TIPOS HUÉRFANOS" -ForegroundColor Magenta - Write-Host "-" * 80 -ForegroundColor Magenta - - $grouped = $results.OrphanTypes | Group-Object File - foreach ($group in $grouped | Sort-Object Name) { - Write-Host " $($group.Name):" -ForegroundColor Cyan - foreach ($type in $group.Group | Sort-Object Type) { - Write-Host " - $($type.Type)" -ForegroundColor White - } - } - Write-Host "" -} - -if ($results.OrphanMethods.Count -gt 0) { - Write-Host "MÉTODOS HUÉRFANOS" -ForegroundColor Magenta - Write-Host "-" * 80 -ForegroundColor Magenta - - $grouped = $results.OrphanMethods | Group-Object File - foreach ($group in $grouped | Sort-Object Name) { - Write-Host " $($group.Name):" -ForegroundColor Cyan - foreach ($method in $group.Group | Sort-Object Method) { - Write-Host " - $($method.Access) $($method.Method)()" -ForegroundColor White - } - } - Write-Host "" -} - -if ($results.OrphanProperties.Count -gt 0) { - Write-Host "PROPIEDADES HUÉRFANAS" -ForegroundColor Magenta - Write-Host "-" * 80 -ForegroundColor Magenta - - $grouped = $results.OrphanProperties | Group-Object File - foreach ($group in $grouped | Sort-Object Name) { - Write-Host " $($group.Name):" -ForegroundColor Cyan - foreach ($property in $group.Group | Sort-Object Property) { - Write-Host " - $($property.Access) $($property.Property)" -ForegroundColor White - } - } - Write-Host "" -} - -Write-Host "=" * 80 -ForegroundColor Cyan -Write-Host "RESUMEN DE ESTADÍSTICAS" -ForegroundColor Cyan -Write-Host "=" * 80 -ForegroundColor Cyan -Write-Host "" - -Write-Host "Total de archivos .cs analizados: $($csFiles.Count)" -ForegroundColor White -Write-Host "" -Write-Host "Archivos completos huérfanos: $($results.OrphanFiles.Count)" -ForegroundColor $(if ($results.OrphanFiles.Count -gt 0) { "Red" } else { "Green" }) -Write-Host "Tipos huérfanos: $($results.OrphanTypes.Count)" -ForegroundColor $(if ($results.OrphanTypes.Count -gt 0) { "Red" } else { "Green" }) -Write-Host "Métodos huérfanos: $($results.OrphanMethods.Count)" -ForegroundColor $(if ($results.OrphanMethods.Count -gt 0) { "Red" } else { "Green" }) -Write-Host "Propiedades huérfanas: $($results.OrphanProperties.Count)" -ForegroundColor $(if ($results.OrphanProperties.Count -gt 0) { "Red" } else { "Green" }) -Write-Host "" - -$totalOrphans = $results.OrphanFiles.Count + $results.OrphanTypes.Count + $results.OrphanMethods.Count + $results.OrphanProperties.Count -Write-Host "TOTAL DE ELEMENTOS HUÉRFANOS: $totalOrphans" -ForegroundColor $(if ($totalOrphans -gt 0) { "Yellow" } else { "Green" }) - -Write-Host "" -Write-Host "Análisis completado." -ForegroundColor Green