af1152b001
Refactored all C# test files to use explicit namespace declarations and moved all using directives inside the namespace block for consistency. Updated assembly info and cache files to reflect the new build. Adjusted MvcTestingAppManifest.json to use fully qualified assembly names. No functional changes; all updates are related to code style, organization, and project metadata.
389 lines
12 KiB
PowerShell
389 lines
12 KiB
PowerShell
#!/usr/bin/env pwsh
|
|
<#
|
|
.SYNOPSIS
|
|
Converts C# files from block-scoped to file-scoped namespaces and fixes System namespace conflicts.
|
|
|
|
.DESCRIPTION
|
|
This script converts all C# files in MediaBrowser.Model from block-scoped namespaces
|
|
to file-scoped namespaces, and replaces System using directives with global::System
|
|
to resolve conflicts with MediaBrowser.Model.System namespace.
|
|
|
|
.PARAMETER Path
|
|
The root path to search for C# files. Defaults to "MediaBrowser.Model"
|
|
|
|
.PARAMETER DryRun
|
|
If specified, shows what would be changed without actually modifying files
|
|
|
|
.PARAMETER Verbose
|
|
Shows detailed processing information
|
|
|
|
.PARAMETER BackupFiles
|
|
Creates .bak files before conversion
|
|
|
|
.EXAMPLE
|
|
.\ConvertToFileScopedNamespaces.ps1 -DryRun
|
|
|
|
.EXAMPLE
|
|
.\ConvertToFileScopedNamespaces.ps1 -BackupFiles
|
|
|
|
.EXAMPLE
|
|
.\ConvertToFileScopedNamespaces.ps1 -Path "MediaBrowser.Model\Dlna" -Verbose
|
|
#>
|
|
|
|
param(
|
|
[string]$Path = "MediaBrowser.Model",
|
|
[switch]$DryRun,
|
|
[switch]$BackupFiles
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
$VerbosePreference = if ($PSBoundParameters.ContainsKey('Verbose')) { 'Continue' } else { 'SilentlyContinue' }
|
|
|
|
function Get-IndentString {
|
|
param([string]$Line)
|
|
|
|
if ($Line -match '^(\s+)') {
|
|
return $Matches[1]
|
|
}
|
|
return ""
|
|
}
|
|
|
|
function Get-IndentLevel {
|
|
param([string]$IndentString)
|
|
|
|
# Count spaces (4 spaces = 1 level) or tabs (1 tab = 1 level)
|
|
$spaces = ($IndentString.ToCharArray() | Where-Object { $_ -eq ' ' }).Count
|
|
$tabs = ($IndentString.ToCharArray() | Where-Object { $_ -eq "`t" }).Count
|
|
|
|
return [Math]::Max($tabs, [Math]::Floor($spaces / 4))
|
|
}
|
|
|
|
function Remove-OneIndentLevel {
|
|
param([string]$Line, [ref]$IndentChar, [ref]$IndentSize)
|
|
|
|
if ([string]::IsNullOrWhiteSpace($Line)) {
|
|
return $Line
|
|
}
|
|
|
|
$indent = Get-IndentString -Line $Line
|
|
|
|
if ($indent.Length -eq 0) {
|
|
return $Line
|
|
}
|
|
|
|
# Detect indent character and size on first indented line
|
|
if ($IndentChar.Value -eq $null) {
|
|
if ($indent[0] -eq "`t") {
|
|
$IndentChar.Value = "`t"
|
|
$IndentSize.Value = 1
|
|
} else {
|
|
$IndentChar.Value = ' '
|
|
# Detect indent size (usually 4 spaces)
|
|
$IndentSize.Value = 4
|
|
if ($indent.Length -ge 2) {
|
|
# Try to detect actual indent size
|
|
for ($i = 1; $i -le 8; $i++) {
|
|
if ($indent.Length % $i -eq 0) {
|
|
$IndentSize.Value = $i
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Write-Verbose "Detected indent: '$($IndentChar.Value)' x $($IndentSize.Value)"
|
|
}
|
|
|
|
# Remove one level of indentation
|
|
if ($IndentChar.Value -eq "`t") {
|
|
if ($Line -match '^\t(.*)') {
|
|
return $Matches[1]
|
|
}
|
|
} else {
|
|
$pattern = "^" + (' ' * $IndentSize.Value) + '(.*)'
|
|
if ($Line -match $pattern) {
|
|
return $Matches[1]
|
|
}
|
|
}
|
|
|
|
return $Line
|
|
}
|
|
|
|
function Test-FileScopedNamespace {
|
|
param([string]$Content)
|
|
|
|
# Check if already using file-scoped namespace (semicolon after namespace declaration)
|
|
return $Content -match 'namespace\s+[\w\.]+\s*;'
|
|
}
|
|
|
|
function Test-BlockScopedNamespace {
|
|
param([string]$Content)
|
|
|
|
# Check for block-scoped namespace
|
|
return $Content -match 'namespace\s+[\w\.]+\s*\r?\n?\s*\{'
|
|
}
|
|
|
|
function Add-GlobalPrefix {
|
|
param([string]$Content)
|
|
|
|
# System namespaces to prefix (ordered from most specific to least)
|
|
$systemNamespaces = @(
|
|
'System\.Xml\.Serialization',
|
|
'System\.ComponentModel\.DataAnnotations',
|
|
'System\.ComponentModel',
|
|
'System\.Collections\.Generic',
|
|
'System\.Collections\.Concurrent',
|
|
'System\.Collections',
|
|
'System\.Diagnostics\.CodeAnalysis',
|
|
'System\.Diagnostics',
|
|
'System\.Globalization',
|
|
'System\.Linq\.Expressions',
|
|
'System\.Linq',
|
|
'System\.Text\.Json\.Serialization',
|
|
'System\.Text\.Json',
|
|
'System\.Text\.RegularExpressions',
|
|
'System\.Text',
|
|
'System\.Threading\.Tasks',
|
|
'System\.Threading',
|
|
'System\.Runtime\.Serialization',
|
|
'System\.Runtime\.CompilerServices',
|
|
'System\.Runtime',
|
|
'System\.Net\.Http',
|
|
'System\.Net\.Sockets',
|
|
'System\.Net\.WebSockets',
|
|
'System\.Net\.Mime',
|
|
'System\.Net',
|
|
'System\.IO\.Compression',
|
|
'System\.IO',
|
|
'System\.Security',
|
|
'System' # Must be last to avoid partial matches
|
|
)
|
|
|
|
foreach ($ns in $systemNamespaces) {
|
|
# Don't add global:: if it's already there
|
|
# Match: "using System.X" but not "using global::System.X"
|
|
$pattern = '(\s+using\s+)(?!global::)(' + $ns + ')(\s|;)'
|
|
$replacement = '${1}global::${2}${3}'
|
|
$Content = $Content -replace $pattern, $replacement
|
|
}
|
|
|
|
return $Content
|
|
}
|
|
|
|
function Convert-ToFileScopedNamespace {
|
|
param(
|
|
[string]$FilePath,
|
|
[switch]$DryRun,
|
|
[switch]$CreateBackup
|
|
)
|
|
|
|
$content = Get-Content -Path $FilePath -Raw
|
|
$originalContent = $content
|
|
$modified = $false
|
|
|
|
# Check current state
|
|
$hasFileScopedNS = Test-FileScopedNamespace -Content $content
|
|
$hasBlockScopedNS = Test-BlockScopedNamespace -Content $content
|
|
|
|
if ($hasFileScopedNS) {
|
|
Write-Verbose " Already using file-scoped namespace"
|
|
|
|
# But still add global:: prefixes if needed
|
|
$contentWithGlobal = Add-GlobalPrefix -Content $content
|
|
if ($contentWithGlobal -ne $content) {
|
|
$content = $contentWithGlobal
|
|
$modified = $true
|
|
Write-Host " [UPDATED] Added global:: prefixes" -ForegroundColor Yellow
|
|
} else {
|
|
Write-Host " [SKIP] Already correct" -ForegroundColor Gray
|
|
return $false
|
|
}
|
|
}
|
|
elseif (-not $hasBlockScopedNS) {
|
|
Write-Host " [SKIP] No namespace found" -ForegroundColor Gray
|
|
return $false
|
|
}
|
|
else {
|
|
Write-Verbose " Converting block-scoped to file-scoped namespace"
|
|
|
|
# Extract namespace name and line
|
|
if ($content -match 'namespace\s+([\w\.]+)\s*\r?\n?\s*\{') {
|
|
$namespaceName = $Matches[1]
|
|
Write-Verbose " Namespace: $namespaceName"
|
|
} else {
|
|
Write-Warning " Could not parse namespace"
|
|
return $false
|
|
}
|
|
|
|
# Step 1: Convert namespace declaration to file-scoped
|
|
$content = $content -replace '(namespace\s+[\w\.]+)\s*\r?\n?\s*\{', '$1;'
|
|
$modified = $true
|
|
|
|
# Step 2: Add global:: prefixes to System using directives
|
|
$content = Add-GlobalPrefix -Content $content
|
|
|
|
# Step 3: Parse into lines for indentation removal
|
|
$lines = $content -split '\r?\n'
|
|
$hasWindowsLineEndings = $originalContent -match '\r\n'
|
|
|
|
# Find namespace declaration line
|
|
$namespaceLineIndex = -1
|
|
for ($i = 0; $i -lt $lines.Length; $i++) {
|
|
if ($lines[$i] -match '^namespace\s+[\w\.]+\s*;') {
|
|
$namespaceLineIndex = $i
|
|
break
|
|
}
|
|
}
|
|
|
|
if ($namespaceLineIndex -lt 0) {
|
|
Write-Warning " Could not find namespace declaration after conversion"
|
|
return $false
|
|
}
|
|
|
|
# Step 4: Remove one level of indentation from all lines after namespace
|
|
$indentChar = $null
|
|
$indentSize = 4
|
|
$indentCharRef = [ref]$indentChar
|
|
$indentSizeRef = [ref]$indentSize
|
|
|
|
for ($i = $namespaceLineIndex + 1; $i -lt $lines.Length; $i++) {
|
|
$lines[$i] = Remove-OneIndentLevel -Line $lines[$i] -IndentChar $indentCharRef -IndentSize $indentSizeRef
|
|
}
|
|
|
|
# Step 5: Remove the closing brace of the namespace
|
|
# Find the last non-empty, non-whitespace line that's just a closing brace
|
|
$closingBraceIndex = -1
|
|
for ($i = $lines.Length - 1; $i -gt $namespaceLineIndex; $i--) {
|
|
$trimmed = $lines[$i].Trim()
|
|
if ($trimmed -eq '}') {
|
|
$closingBraceIndex = $i
|
|
break
|
|
}
|
|
elseif ($trimmed -ne '' -and $trimmed -ne '}') {
|
|
# Found non-brace content, stop looking
|
|
break
|
|
}
|
|
}
|
|
|
|
if ($closingBraceIndex -ge 0) {
|
|
Write-Verbose " Removing closing brace at line $closingBraceIndex"
|
|
$lines = $lines[0..($closingBraceIndex-1)] + $lines[($closingBraceIndex+1)..($lines.Length-1)]
|
|
}
|
|
|
|
# Step 6: Rejoin lines
|
|
$lineEnding = if ($hasWindowsLineEndings) { "`r`n" } else { "`n" }
|
|
$content = ($lines | Where-Object { $_ -ne $null }) -join $lineEnding
|
|
|
|
# Step 7: Clean up trailing whitespace and ensure single newline at end
|
|
$content = $content.TrimEnd()
|
|
$content += $lineEnding
|
|
|
|
Write-Host " [CONVERTED] Block-scoped → File-scoped" -ForegroundColor Green
|
|
}
|
|
|
|
# Apply changes
|
|
if ($modified -and $content -ne $originalContent) {
|
|
if ($DryRun) {
|
|
Write-Host " [DRY-RUN] Would save changes" -ForegroundColor Cyan
|
|
return $true
|
|
}
|
|
|
|
if ($CreateBackup) {
|
|
$backupPath = "$FilePath.bak"
|
|
Copy-Item -Path $FilePath -Destination $backupPath -Force
|
|
Write-Verbose " Created backup: $backupPath"
|
|
}
|
|
|
|
# Write with correct encoding (UTF-8 without BOM for .cs files)
|
|
[System.IO.File]::WriteAllText($FilePath, $content, [System.Text.UTF8Encoding]::new($false))
|
|
return $true
|
|
}
|
|
|
|
return $false
|
|
}
|
|
|
|
# Main script
|
|
Write-Host ("=" * 80) -ForegroundColor Cyan
|
|
Write-Host "C# File-Scoped Namespace Converter" -ForegroundColor Cyan
|
|
Write-Host "Fixes MediaBrowser.Model.System namespace conflicts" -ForegroundColor Cyan
|
|
Write-Host ("=" * 80) -ForegroundColor Cyan
|
|
Write-Host
|
|
|
|
if ($DryRun) {
|
|
Write-Host "DRY RUN MODE - No files will be modified" -ForegroundColor Yellow
|
|
Write-Host
|
|
}
|
|
|
|
if ($BackupFiles) {
|
|
Write-Host "Backup mode enabled - .bak files will be created" -ForegroundColor Yellow
|
|
Write-Host
|
|
}
|
|
|
|
if (-not (Test-Path $Path)) {
|
|
Write-Error "❌ Path not found: $Path"
|
|
exit 1
|
|
}
|
|
|
|
# Find all C# files
|
|
$files = Get-ChildItem -Path $Path -Filter "*.cs" -Recurse | Where-Object {
|
|
$_.FullName -notmatch "\\obj\\" -and
|
|
$_.FullName -notmatch "\\bin\\" -and
|
|
$_.FullName -notmatch "\\Properties\\AssemblyInfo\.cs$"
|
|
}
|
|
|
|
Write-Host "Found $($files.Count) C# files in $Path" -ForegroundColor Cyan
|
|
Write-Host
|
|
|
|
$convertedCount = 0
|
|
$skippedCount = 0
|
|
$errorCount = 0
|
|
$updatedCount = 0
|
|
|
|
foreach ($file in $files) {
|
|
$relativePath = $file.FullName.Replace((Get-Location).Path, "").TrimStart([char]92, [char]47)
|
|
Write-Host "[Processing] $relativePath" -ForegroundColor White
|
|
|
|
try {
|
|
$result = Convert-ToFileScopedNamespace -FilePath $file.FullName -DryRun:$DryRun -CreateBackup:$BackupFiles
|
|
|
|
if ($result) {
|
|
if ($result -eq "updated") {
|
|
$updatedCount++
|
|
} else {
|
|
$convertedCount++
|
|
}
|
|
} else {
|
|
$skippedCount++
|
|
}
|
|
}
|
|
catch {
|
|
Write-Host " [ERROR] $_" -ForegroundColor Red
|
|
Write-Verbose $_.ScriptStackTrace
|
|
$errorCount++
|
|
}
|
|
}
|
|
|
|
Write-Host
|
|
Write-Host ("=" * 80) -ForegroundColor Cyan
|
|
Write-Host "Summary:" -ForegroundColor Cyan
|
|
Write-Host ("=" * 80) -ForegroundColor Cyan
|
|
Write-Host " Total files: $($files.Count)" -ForegroundColor White
|
|
Write-Host " Converted: $convertedCount" -ForegroundColor Green
|
|
Write-Host " Updated (global::): $updatedCount" -ForegroundColor Yellow
|
|
Write-Host " Skipped: $skippedCount" -ForegroundColor Gray
|
|
Write-Host " Errors: $errorCount" -ForegroundColor Red
|
|
|
|
if ($DryRun) {
|
|
Write-Host
|
|
Write-Host "This was a DRY RUN. Run without -DryRun to apply changes." -ForegroundColor Yellow
|
|
} elseif ($convertedCount -gt 0 -or $updatedCount -gt 0) {
|
|
Write-Host
|
|
Write-Host "Conversion complete! Next steps:" -ForegroundColor Green
|
|
Write-Host " 1. Review changes with: git diff" -ForegroundColor White
|
|
Write-Host " 2. Build project: dotnet build MediaBrowser.Model\MediaBrowser.Model.csproj" -ForegroundColor White
|
|
Write-Host " 3. If successful: git add . && git commit -m `"Convert to file-scoped namespaces`"" -ForegroundColor White
|
|
}
|
|
|
|
Write-Host ("=" * 80) -ForegroundColor Cyan
|
|
|
|
exit $errorCount
|