$ErrorActionPreference = "Stop" $inputDirs = @PSC_CODE_COUNT_INPUT_DIRS@ $excludeDirs = @PSC_CODE_COUNT_EXCLUDE_DIRS@ $outputDir = "@PSC_CODE_COUNT_OUTPUT_DIR@" $configuredTokei = "@PSC_CODE_COUNT_TOKEI@" $configuredCloc = "@PSC_CODE_COUNT_CLOC@" function Resolve-Tool([string]$Configured, [string]$Name, [string[]]$Fallbacks) { if ($Configured -and (Test-Path -LiteralPath $Configured)) { return (Resolve-Path -LiteralPath $Configured).Path } $command = Get-Command $Name -ErrorAction SilentlyContinue | Select-Object -First 1 if ($command) { return $command.Source } foreach ($fallback in $Fallbacks) { if (Test-Path -LiteralPath $fallback) { return (Resolve-Path -LiteralPath $fallback).Path } } throw "$Name executable was not found" } $wingetLinks = Join-Path $env:LOCALAPPDATA "Microsoft\WinGet\Links" $tokei = Resolve-Tool $configuredTokei "tokei" @((Join-Path $wingetLinks "tokei.exe")) $cloc = Resolve-Tool $configuredCloc "cloc" @((Join-Path $wingetLinks "cloc.exe")) New-Item -ItemType Directory -Force -Path $outputDir | Out-Null $tokeiArguments = [Collections.Generic.List[string]]::new() $tokeiArguments.Add("--output") $tokeiArguments.Add("json") foreach ($exclude in $excludeDirs) { $tokeiArguments.Add("--exclude") $tokeiArguments.Add(($exclude.Replace("\", "/") + "/*")) } foreach ($inputDir in $inputDirs) { $tokeiArguments.Add($inputDir) } $tokeiPath = Join-Path $outputDir "tokei.json" & $tokei @tokeiArguments | Set-Content -LiteralPath $tokeiPath -Encoding UTF8 if ($LASTEXITCODE -ne 0) { throw "tokei failed with exit code $LASTEXITCODE" } $excludePattern = if ($excludeDirs.Count) { ($excludeDirs | ForEach-Object { [regex]::Escape(([IO.Path]::GetFullPath($_)).Replace("\", "/")) }) -join "|" } else { "(?!)" } $clocJsonPath = Join-Path $outputDir "cloc.json" $clocXmlPath = Join-Path $outputDir "cloc.xml" & $cloc @inputDirs "--json" "--by-file" "--fullpath" "--not-match-d=$excludePattern" "--out=$clocJsonPath" if ($LASTEXITCODE -ne 0) { throw "cloc JSON generation failed with exit code $LASTEXITCODE" } & $cloc @inputDirs "--xml" "--by-file" "--fullpath" "--not-match-d=$excludePattern" "--out=$clocXmlPath" if ($LASTEXITCODE -ne 0) { throw "cloc XML generation failed with exit code $LASTEXITCODE" } $tokeiData = Get-Content -LiteralPath $tokeiPath -Raw | ConvertFrom-Json $languages = [Collections.Generic.List[object]]::new() foreach ($property in $tokeiData.PSObject.Properties) { if ($property.Name -eq "Total") { continue } $value = $property.Value $fileCount = if ($value.reports) { @($value.reports).Count } else { 0 } $languages.Add([pscustomobject]@{ Language = $property.Name Files = $fileCount Code = [int64]$value.code Comments = [int64]$value.comments Blanks = [int64]$value.blanks Total = [int64]$value.code + [int64]$value.comments + [int64]$value.blanks }) } $languageSummary = @($languages | Sort-Object Code -Descending) $languageSummary | Export-Csv -LiteralPath (Join-Path $outputDir "languages.csv") -NoTypeInformation -Encoding UTF8 $summary = [ordered]@{ tools = [ordered]@{ tokei = (& $tokei --version | Select-Object -First 1).Trim() cloc = (& $cloc --version | Select-Object -First 1).Trim() } totals = [ordered]@{ files = [int64](($languageSummary | Measure-Object Files -Sum).Sum) code = [int64](($languageSummary | Measure-Object Code -Sum).Sum) comments = [int64](($languageSummary | Measure-Object Comments -Sum).Sum) blanks = [int64](($languageSummary | Measure-Object Blanks -Sum).Sum) } languages = $languageSummary } [IO.File]::WriteAllText((Join-Path $outputDir "summary.json"), ($summary | ConvertTo-Json -Depth 8), [Text.UTF8Encoding]::new($false)) Write-Output "Code count report: $outputDir"