GFramework/refactor-scripts/refactor-namespaces.ps1
GeWuYou fb14d7122c docs(style): 更新文档中的命名空间导入格式
- 将所有小写的命名空间导入更正为首字母大写格式
- 统一 GFramework 框架的命名空间引用规范
- 修复 core、ecs、godot 等模块的命名空间导入错误
- 标准化文档示例代码中的 using 语句格式
- 确保所有文档中的命名空间引用保持一致性
- 更新 global using 语句以匹配正确的命名空间格式
2026-03-10 07:18:49 +08:00

457 lines
18 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env pwsh
<#
.SYNOPSIS
GFramework 命名空间重构脚本 - 将所有文件夹和命名空间从小写改为 PascalCase
.DESCRIPTION
此脚本执行以下操作:
1. 重命名文件夹(使用 git mv 保留历史)
2. 更新所有 C# 文件中的命名空间声明和 using 语句
3. 更新文档中的命名空间引用
4. 验证更改的完整性
.PARAMETER Phase
指定要执行的阶段:
- 1: 文件夹重命名
- 2: 命名空间更新
- 3: 文档更新
- 4: 验证
- All: 执行所有阶段(默认)
.PARAMETER DryRun
干运行模式,只显示将要执行的操作,不实际执行
.PARAMETER SkipTests
跳过测试验证
.EXAMPLE
./refactor-namespaces.ps1 -Phase 1
./refactor-namespaces.ps1 -DryRun
./refactor-namespaces.ps1 -Phase All -SkipTests
#>
param(
[Parameter()]
[ValidateSet("1", "2", "3", "4", "All")]
[string]$Phase = "All",
[Parameter()]
[switch]$DryRun,
[Parameter()]
[switch]$SkipTests
)
$ErrorActionPreference = "Stop"
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$rootDir = Split-Path -Parent $scriptDir
$mappingFile = Join-Path $scriptDir "folder-mappings.json"
# 颜色输出函数
function Write-ColorOutput {
param(
[string]$Message,
[string]$Color = "White"
)
Write-Host $Message -ForegroundColor $Color
}
function Write-Success { param([string]$Message) Write-ColorOutput "$Message" "Green" }
function Write-Info { param([string]$Message) Write-ColorOutput " $Message" "Cyan" }
function Write-Warning { param([string]$Message) Write-ColorOutput "$Message" "Yellow" }
function Write-Error { param([string]$Message) Write-ColorOutput "$Message" "Red" }
# 阶段 1: 文件夹重命名
function Invoke-FolderRename {
Write-Info "=== 阶段 1: 文件夹重命名 ==="
$config = Get-Content $mappingFile | ConvertFrom-Json
$totalFolders = 0
foreach ($project in $config.projects) {
Write-Info "处理项目: $($project.name)"
$projectPath = Join-Path $rootDir $project.path
if (-not (Test-Path $projectPath)) {
Write-Warning "项目路径不存在: $projectPath"
continue
}
# 按深度排序(深度优先,避免路径冲突)
$sortedFolders = $project.folders | Sort-Object { ($_.from -split '/').Count } -Descending
foreach ($folder in $sortedFolders) {
$fromPath = Join-Path $projectPath $folder.from
$toPath = Join-Path $projectPath $folder.to
if (-not (Test-Path $fromPath)) {
Write-Warning "源文件夹不存在: $fromPath"
continue
}
if ($fromPath -eq $toPath) {
Write-Info "跳过(路径相同): $($folder.from)"
continue
}
# Windows 文件系统不区分大小写,需要两步重命名
$tempPath = "$fromPath`_temp"
if ($DryRun) {
Write-Info "[DRY RUN] git mv $fromPath $tempPath"
Write-Info "[DRY RUN] git mv $tempPath $toPath"
} else {
try {
Write-Info "重命名: $($folder.from) -> $($folder.to)"
# 第一步:重命名为临时名称
git mv $fromPath $tempPath
if ($LASTEXITCODE -ne 0) {
throw "git mv 失败: $fromPath -> $tempPath"
}
# 第二步:重命名为目标名称
git mv $tempPath $toPath
if ($LASTEXITCODE -ne 0) {
throw "git mv 失败: $tempPath -> $toPath"
}
$totalFolders++
Write-Success "完成: $($folder.from) -> $($folder.to)"
} catch {
Write-Error "重命名失败: $_"
throw
}
}
}
if (-not $DryRun) {
Write-Info "提交项目 $($project.name) 的文件夹重命名"
git add -A
git commit -m "refactor($($project.name)): 重命名文件夹为 PascalCase"
}
}
Write-Success "阶段 1 完成: 共重命名 $totalFolders 个文件夹"
}
# 阶段 2: 命名空间更新
function Invoke-NamespaceUpdate {
Write-Info "=== 阶段 2: 命名空间更新 ==="
$csFiles = Get-ChildItem -Path $rootDir -Filter "*.cs" -Recurse |
Where-Object { $_.FullName -notmatch "\\bin\\|\\obj\\|\\Generated\\" }
Write-Info "找到 $($csFiles.Count) 个 C# 文件"
$updatedFiles = 0
$totalReplacements = 0
# 定义命名空间替换规则(按优先级排序,长的先匹配)
$namespaceRules = @(
# CQRS 子命名空间
@{ Pattern = '\.cqrs\.notification\b'; Replacement = '.CQRS.Notification' }
@{ Pattern = '\.cqrs\.command\b'; Replacement = '.CQRS.Command' }
@{ Pattern = '\.cqrs\.request\b'; Replacement = '.CQRS.Request' }
@{ Pattern = '\.cqrs\.query\b'; Replacement = '.CQRS.Query' }
@{ Pattern = '\.cqrs\.behaviors\b'; Replacement = '.CQRS.Behaviors' }
@{ Pattern = '\.cqrs\b'; Replacement = '.CQRS' }
# 其他嵌套命名空间
@{ Pattern = '\.coroutine\.instructions\b'; Replacement = '.Coroutine.Instructions' }
@{ Pattern = '\.coroutine\.extensions\b'; Replacement = '.Coroutine.Extensions' }
@{ Pattern = '\.coroutine\b'; Replacement = '.Coroutine' }
@{ Pattern = '\.events\.filters\b'; Replacement = '.Events.Filters' }
@{ Pattern = '\.events\b'; Replacement = '.Events' }
@{ Pattern = '\.logging\.appenders\b'; Replacement = '.Logging.Appenders' }
@{ Pattern = '\.logging\.filters\b'; Replacement = '.Logging.Filters' }
@{ Pattern = '\.logging\.formatters\b'; Replacement = '.Logging.Formatters' }
@{ Pattern = '\.logging\b'; Replacement = '.Logging' }
@{ Pattern = '\.functional\.async\b'; Replacement = '.Functional.Async' }
@{ Pattern = '\.functional\.control\b'; Replacement = '.Functional.Control' }
@{ Pattern = '\.functional\.functions\b'; Replacement = '.Functional.Functions' }
@{ Pattern = '\.functional\.pipe\b'; Replacement = '.Functional.Pipe' }
@{ Pattern = '\.functional\.result\b'; Replacement = '.Functional.Result' }
@{ Pattern = '\.functional\b'; Replacement = '.Functional' }
@{ Pattern = '\.services\.modules\b'; Replacement = '.Services.Modules' }
@{ Pattern = '\.services\b'; Replacement = '.Services' }
# 单层命名空间
@{ Pattern = '\.architecture\b'; Replacement = '.Architecture' }
@{ Pattern = '\.bases\b'; Replacement = '.Bases' }
@{ Pattern = '\.command\b'; Replacement = '.Command' }
@{ Pattern = '\.configuration\b'; Replacement = '.Configuration' }
@{ Pattern = '\.constants\b'; Replacement = '.Constants' }
@{ Pattern = '\.data\b'; Replacement = '.Data' }
@{ Pattern = '\.enums\b'; Replacement = '.Enums' }
@{ Pattern = '\.environment\b'; Replacement = '.Environment' }
@{ Pattern = '\.extensions\b'; Replacement = '.Extensions' }
@{ Pattern = '\.internals\b'; Replacement = '.Internals' }
@{ Pattern = '\.ioc\b'; Replacement = '.IoC' }
@{ Pattern = '\.lifecycle\b'; Replacement = '.Lifecycle' }
@{ Pattern = '\.model\b'; Replacement = '.Model' }
@{ Pattern = '\.pause\b'; Replacement = '.Pause' }
@{ Pattern = '\.pool\b'; Replacement = '.Pool' }
@{ Pattern = '\.properties\b'; Replacement = '.Properties' }
@{ Pattern = '\.property\b'; Replacement = '.Property' }
@{ Pattern = '\.query\b'; Replacement = '.Query' }
@{ Pattern = '\.registries\b'; Replacement = '.Registries' }
@{ Pattern = '\.resource\b'; Replacement = '.Resource' }
@{ Pattern = '\.rule\b'; Replacement = '.Rule' }
@{ Pattern = '\.serializer\b'; Replacement = '.Serializer' }
@{ Pattern = '\.state\b'; Replacement = '.State' }
@{ Pattern = '\.storage\b'; Replacement = '.Storage' }
@{ Pattern = '\.system\b'; Replacement = '.System' }
@{ Pattern = '\.time\b'; Replacement = '.Time' }
@{ Pattern = '\.utility\b'; Replacement = '.Utility' }
@{ Pattern = '\.versioning\b'; Replacement = '.Versioning' }
)
foreach ($file in $csFiles) {
$content = Get-Content $file.FullName -Raw
$originalContent = $content
$fileReplacements = 0
foreach ($rule in $namespaceRules) {
$matches = [regex]::Matches($content, $rule.Pattern, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
if ($matches.Count -gt 0) {
$content = [regex]::Replace($content, $rule.Pattern, $rule.Replacement, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
$fileReplacements += $matches.Count
}
}
if ($content -ne $originalContent) {
if ($DryRun) {
Write-Info "[DRY RUN] 更新文件: $($file.FullName) ($fileReplacements 处替换)"
} else {
Set-Content -Path $file.FullName -Value $content -NoNewline
$updatedFiles++
$totalReplacements += $fileReplacements
Write-Info "更新: $($file.Name) ($fileReplacements 处替换)"
}
}
}
if (-not $DryRun) {
Write-Info "提交命名空间更新"
git add -A
git commit -m "refactor: 更新所有命名空间为 PascalCase"
}
Write-Success "阶段 2 完成: 更新了 $updatedFiles 个文件,共 $totalReplacements 处替换"
}
# 阶段 3: 文档更新
function Invoke-DocumentationUpdate {
Write-Info "=== 阶段 3: 文档更新 ==="
$mdFiles = Get-ChildItem -Path $rootDir -Filter "*.md" -Recurse |
Where-Object { $_.FullName -notmatch "\\node_modules\\|\\bin\\|\\obj\\" }
Write-Info "找到 $($mdFiles.Count) 个 Markdown 文件"
$updatedFiles = 0
$totalReplacements = 0
# 使用与阶段 2 相同的替换规则
$namespaceRules = @(
@{ Pattern = '\.cqrs\.notification\b'; Replacement = '.CQRS.Notification' }
@{ Pattern = '\.cqrs\.command\b'; Replacement = '.CQRS.Command' }
@{ Pattern = '\.cqrs\.request\b'; Replacement = '.CQRS.Request' }
@{ Pattern = '\.cqrs\.query\b'; Replacement = '.CQRS.Query' }
@{ Pattern = '\.cqrs\.behaviors\b'; Replacement = '.CQRS.Behaviors' }
@{ Pattern = '\.cqrs\b'; Replacement = '.CQRS' }
@{ Pattern = '\.coroutine\.instructions\b'; Replacement = '.Coroutine.Instructions' }
@{ Pattern = '\.coroutine\.extensions\b'; Replacement = '.Coroutine.Extensions' }
@{ Pattern = '\.coroutine\b'; Replacement = '.Coroutine' }
@{ Pattern = '\.events\.filters\b'; Replacement = '.Events.Filters' }
@{ Pattern = '\.events\b'; Replacement = '.Events' }
@{ Pattern = '\.logging\.appenders\b'; Replacement = '.Logging.Appenders' }
@{ Pattern = '\.logging\.filters\b'; Replacement = '.Logging.Filters' }
@{ Pattern = '\.logging\.formatters\b'; Replacement = '.Logging.Formatters' }
@{ Pattern = '\.logging\b'; Replacement = '.Logging' }
@{ Pattern = '\.functional\.async\b'; Replacement = '.Functional.Async' }
@{ Pattern = '\.functional\.control\b'; Replacement = '.Functional.Control' }
@{ Pattern = '\.functional\.functions\b'; Replacement = '.Functional.Functions' }
@{ Pattern = '\.functional\.pipe\b'; Replacement = '.Functional.Pipe' }
@{ Pattern = '\.functional\.result\b'; Replacement = '.Functional.Result' }
@{ Pattern = '\.functional\b'; Replacement = '.Functional' }
@{ Pattern = '\.services\.modules\b'; Replacement = '.Services.Modules' }
@{ Pattern = '\.services\b'; Replacement = '.Services' }
@{ Pattern = '\.architecture\b'; Replacement = '.Architecture' }
@{ Pattern = '\.bases\b'; Replacement = '.Bases' }
@{ Pattern = '\.command\b'; Replacement = '.Command' }
@{ Pattern = '\.configuration\b'; Replacement = '.Configuration' }
@{ Pattern = '\.constants\b'; Replacement = '.Constants' }
@{ Pattern = '\.data\b'; Replacement = '.Data' }
@{ Pattern = '\.enums\b'; Replacement = '.Enums' }
@{ Pattern = '\.environment\b'; Replacement = '.Environment' }
@{ Pattern = '\.extensions\b'; Replacement = '.Extensions' }
@{ Pattern = '\.internals\b'; Replacement = '.Internals' }
@{ Pattern = '\.ioc\b'; Replacement = '.IoC' }
@{ Pattern = '\.lifecycle\b'; Replacement = '.Lifecycle' }
@{ Pattern = '\.model\b'; Replacement = '.Model' }
@{ Pattern = '\.pause\b'; Replacement = '.Pause' }
@{ Pattern = '\.pool\b'; Replacement = '.Pool' }
@{ Pattern = '\.properties\b'; Replacement = '.Properties' }
@{ Pattern = '\.property\b'; Replacement = '.Property' }
@{ Pattern = '\.query\b'; Replacement = '.Query' }
@{ Pattern = '\.registries\b'; Replacement = '.Registries' }
@{ Pattern = '\.resource\b'; Replacement = '.Resource' }
@{ Pattern = '\.rule\b'; Replacement = '.Rule' }
@{ Pattern = '\.serializer\b'; Replacement = '.Serializer' }
@{ Pattern = '\.state\b'; Replacement = '.State' }
@{ Pattern = '\.storage\b'; Replacement = '.Storage' }
@{ Pattern = '\.system\b'; Replacement = '.System' }
@{ Pattern = '\.time\b'; Replacement = '.Time' }
@{ Pattern = '\.utility\b'; Replacement = '.Utility' }
@{ Pattern = '\.versioning\b'; Replacement = '.Versioning' }
)
foreach ($file in $mdFiles) {
$content = Get-Content $file.FullName -Raw
$originalContent = $content
$fileReplacements = 0
foreach ($rule in $namespaceRules) {
$matches = [regex]::Matches($content, $rule.Pattern, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
if ($matches.Count -gt 0) {
$content = [regex]::Replace($content, $rule.Pattern, $rule.Replacement, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
$fileReplacements += $matches.Count
}
}
if ($content -ne $originalContent) {
if ($DryRun) {
Write-Info "[DRY RUN] 更新文档: $($file.FullName) ($fileReplacements 处替换)"
} else {
Set-Content -Path $file.FullName -Value $content -NoNewline
$updatedFiles++
$totalReplacements += $fileReplacements
Write-Info "更新: $($file.Name) ($fileReplacements 处替换)"
}
}
}
if (-not $DryRun) {
Write-Info "提交文档更新"
git add -A
git commit -m "docs: 更新文档中的命名空间为 PascalCase"
}
Write-Success "阶段 3 完成: 更新了 $updatedFiles 个文档,共 $totalReplacements 处替换"
}
# 阶段 4: 验证
function Invoke-Verification {
Write-Info "=== 阶段 4: 验证 ==="
# 1. 编译验证
Write-Info "1. 编译验证..."
if ($DryRun) {
Write-Info "[DRY RUN] dotnet build"
} else {
Push-Location $rootDir
try {
dotnet build --no-restore
if ($LASTEXITCODE -eq 0) {
Write-Success "编译成功"
} else {
Write-Error "编译失败"
throw "编译失败"
}
} finally {
Pop-Location
}
}
# 2. 测试验证
if (-not $SkipTests) {
Write-Info "2. 测试验证..."
if ($DryRun) {
Write-Info "[DRY RUN] dotnet test"
} else {
Push-Location $rootDir
try {
dotnet test --no-build
if ($LASTEXITCODE -eq 0) {
Write-Success "所有测试通过"
} else {
Write-Error "测试失败"
throw "测试失败"
}
} finally {
Pop-Location
}
}
} else {
Write-Warning "跳过测试验证"
}
# 3. 检查残留的小写命名空间
Write-Info "3. 检查残留的小写命名空间..."
$csFiles = Get-ChildItem -Path $rootDir -Filter "*.cs" -Recurse |
Where-Object { $_.FullName -notmatch "\\bin\\|\\obj\\|\\Generated\\" }
$lowercasePatterns = @(
'\.architecture\b', '\.command\b', '\.configuration\b', '\.coroutine\b',
'\.cqrs\b', '\.events\b', '\.extensions\b', '\.functional\b',
'\.ioc\b', '\.logging\b', '\.model\b', '\.query\b',
'\.resource\b', '\.state\b', '\.system\b', '\.utility\b'
)
$foundIssues = @()
foreach ($file in $csFiles) {
$content = Get-Content $file.FullName -Raw
foreach ($pattern in $lowercasePatterns) {
if ($content -match $pattern) {
$foundIssues += "$($file.FullName): 找到小写命名空间 $pattern"
}
}
}
if ($foundIssues.Count -gt 0) {
Write-Warning "发现 $($foundIssues.Count) 个残留的小写命名空间:"
$foundIssues | ForEach-Object { Write-Warning $_ }
} else {
Write-Success "未发现残留的小写命名空间"
}
Write-Success "阶段 4 完成: 验证通过"
}
# 主执行逻辑
try {
Write-Info "GFramework 命名空间重构脚本"
Write-Info "工作目录: $rootDir"
Write-Info "配置文件: $mappingFile"
if ($DryRun) {
Write-Warning "*** 干运行模式 - 不会执行实际操作 ***"
}
if (-not (Test-Path $mappingFile)) {
Write-Error "配置文件不存在: $mappingFile"
exit 1
}
switch ($Phase) {
"1" { Invoke-FolderRename }
"2" { Invoke-NamespaceUpdate }
"3" { Invoke-DocumentationUpdate }
"4" { Invoke-Verification }
"All" {
Invoke-FolderRename
Invoke-NamespaceUpdate
Invoke-DocumentationUpdate
Invoke-Verification
}
}
Write-Success "=== 重构完成 ==="
} catch {
Write-Error "重构失败: $_"
Write-Error $_.ScriptStackTrace
exit 1
}