|
| 1 | +<# |
| 2 | +.SYNOPSIS |
| 3 | + Enforce utility-folder hygiene for shared vs engine utilities. |
| 4 | +
|
| 5 | +.DESCRIPTION |
| 6 | + CI-safe report script for the utility consolidation lane. |
| 7 | + Fails when: |
| 8 | + - src/engine/utils contains JavaScript files |
| 9 | + - references to src/engine/utils remain |
| 10 | + - duplicate utility basenames exist under src/shared/utils |
| 11 | + - shared utility files appear unreferenced outside themselves |
| 12 | +
|
| 13 | +.PARAMETER Details |
| 14 | + Prints detailed findings. |
| 15 | +
|
| 16 | +.PARAMETER Ci |
| 17 | + Exits 1 when violations are found. |
| 18 | +#> |
| 19 | + |
| 20 | +param( |
| 21 | + [switch]$Details, |
| 22 | + [switch]$Ci |
| 23 | +) |
| 24 | + |
| 25 | +$ErrorActionPreference = "Stop" |
| 26 | + |
| 27 | +$RepoRoot = Resolve-Path (Join-Path $PSScriptRoot "..\..") |
| 28 | +$SharedUtilsRoot = Join-Path $RepoRoot "src\shared\utils" |
| 29 | +$EngineUtilsRoot = Join-Path $RepoRoot "src\engine\utils" |
| 30 | +$ReportDir = Join-Path $RepoRoot "docs\dev\reports" |
| 31 | +$CsvPath = Join-Path $ReportDir "utils_rules_audit.csv" |
| 32 | + |
| 33 | +New-Item -ItemType Directory -Path $ReportDir -Force | Out-Null |
| 34 | + |
| 35 | +$Findings = New-Object System.Collections.Generic.List[object] |
| 36 | + |
| 37 | +function Add-Finding { |
| 38 | + param( |
| 39 | + [string]$Type, |
| 40 | + [string]$Path, |
| 41 | + [string]$Detail |
| 42 | + ) |
| 43 | + |
| 44 | + $Findings.Add([PSCustomObject]@{ |
| 45 | + Type = $Type |
| 46 | + Path = $Path |
| 47 | + Detail = $Detail |
| 48 | + }) | Out-Null |
| 49 | +} |
| 50 | + |
| 51 | +function Get-RepoRelativePath { |
| 52 | + param([string]$Path) |
| 53 | + $resolved = Resolve-Path $Path -ErrorAction SilentlyContinue |
| 54 | + if ($null -eq $resolved) { return $Path } |
| 55 | + return $resolved.Path.Substring($RepoRoot.Path.Length).TrimStart('\','/') -replace '\\','/' |
| 56 | +} |
| 57 | + |
| 58 | +$SharedUtils = @() |
| 59 | +if (Test-Path $SharedUtilsRoot) { |
| 60 | + $SharedUtils = @(Get-ChildItem -Path $SharedUtilsRoot -Recurse -File -Filter *.js) |
| 61 | +} |
| 62 | + |
| 63 | +$EngineUtils = @() |
| 64 | +if (Test-Path $EngineUtilsRoot) { |
| 65 | + $EngineUtils = @(Get-ChildItem -Path $EngineUtilsRoot -Recurse -File -Filter *.js) |
| 66 | +} |
| 67 | + |
| 68 | +foreach ($file in $EngineUtils) { |
| 69 | + Add-Finding -Type "ENGINE_UTIL_FILE" -Path (Get-RepoRelativePath $file.FullName) -Detail "Utility file remains under src/engine/utils; move to src/shared/utils unless it is proven engine-runtime code." |
| 70 | +} |
| 71 | + |
| 72 | +$SourceFiles = @(Get-ChildItem -Path $RepoRoot -Recurse -File -Include *.js,*.mjs,*.html,*.json,*.md -ErrorAction SilentlyContinue | Where-Object { |
| 73 | + $_.FullName -notmatch '\\.git\\' -and |
| 74 | + $_.FullName -notmatch '\\node_modules\\' -and |
| 75 | + $_.FullName -notmatch '\\tmp\\' -and |
| 76 | + $_.FullName -notmatch '\\docs\\dev\\reports\\' |
| 77 | +}) |
| 78 | + |
| 79 | +$EngineUtilReferencePatterns = @( |
| 80 | + "src/engine/utils/", |
| 81 | + "/src/engine/utils/", |
| 82 | + "src\\engine\\utils\\", |
| 83 | + "\\src\\engine\\utils\\" |
| 84 | +) |
| 85 | + |
| 86 | +foreach ($pattern in $EngineUtilReferencePatterns) { |
| 87 | + $matches = @($SourceFiles | Select-String -SimpleMatch -Pattern $pattern -ErrorAction SilentlyContinue) |
| 88 | + foreach ($match in $matches) { |
| 89 | + Add-Finding -Type "ENGINE_UTIL_REFERENCE" -Path (Get-RepoRelativePath $match.Path) -Detail "Line $($match.LineNumber): remaining reference to $pattern" |
| 90 | + } |
| 91 | +} |
| 92 | + |
| 93 | +$ByBaseName = $SharedUtils | Group-Object BaseName | Where-Object { $_.Count -gt 1 } |
| 94 | +foreach ($group in $ByBaseName) { |
| 95 | + $paths = ($group.Group | ForEach-Object { Get-RepoRelativePath $_.FullName }) -join '; ' |
| 96 | + Add-Finding -Type "DUPLICATE_SHARED_UTIL_BASENAME" -Path $group.Name -Detail $paths |
| 97 | +} |
| 98 | + |
| 99 | +foreach ($file in $SharedUtils) { |
| 100 | + $relative = Get-RepoRelativePath $file.FullName |
| 101 | + $moduleName = $file.BaseName |
| 102 | + |
| 103 | + $refs = @($SourceFiles | Where-Object { $_.FullName -ne $file.FullName } | Select-String -SimpleMatch -Pattern $moduleName -ErrorAction SilentlyContinue) |
| 104 | + |
| 105 | + if ($refs.Count -eq 0) { |
| 106 | + Add-Finding -Type "POSSIBLY_DEAD_SHARED_UTIL" -Path $relative -Detail "No references to utility basename found outside the file itself. Review before deleting; dynamic usage may not be detected." |
| 107 | + } |
| 108 | +} |
| 109 | + |
| 110 | +$Findings | Export-Csv -Path $CsvPath -NoTypeInformation |
| 111 | + |
| 112 | +Write-Output "Utils rules audit complete." |
| 113 | +Write-Output "Shared utility files scanned: $($SharedUtils.Count)" |
| 114 | +Write-Output "Engine utility files found: $($EngineUtils.Count)" |
| 115 | +Write-Output "Findings: $($Findings.Count)" |
| 116 | +Write-Output "Report: docs/dev/reports/utils_rules_audit.csv" |
| 117 | + |
| 118 | +if ($Details -and $Findings.Count -gt 0) { |
| 119 | + Write-Output "" |
| 120 | + Write-Output "Details:" |
| 121 | + foreach ($finding in $Findings) { |
| 122 | + Write-Output "$($finding.Type) - $($finding.Path) - $($finding.Detail)" |
| 123 | + } |
| 124 | +} |
| 125 | + |
| 126 | +if ($Ci -and $Findings.Count -gt 0) { |
| 127 | + exit 1 |
| 128 | +} |
0 commit comments