[docs][refactor]: 将旧 01~06 中文教程合并整理为 modules/frameworks 文件夹结构
- 删除 01~05 旧中文教程目录 - 将 03 核心功能教程拆分为各 framework 模块的子文档 - 06 工具脚本移入 modules/frameworks/编辑器工具/UI工具/ - 非框架内容合并进 rules/20-开发规则.md 与 rules/40-工作流清单.md - 更新所有交叉链接与文档关联表 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
181
hooks/archive-check.ps1
Normal file
181
hooks/archive-check.ps1
Normal file
@@ -0,0 +1,181 @@
|
||||
# hooks/archive-check.ps1
|
||||
# Check changed .md files and suggest related docs to update.
|
||||
# This script only outputs suggestions; it does NOT modify any files.
|
||||
#
|
||||
# Mechanism:
|
||||
# For every changed .md file, parse its "## 文档关联" section and extract
|
||||
# Markdown links. Those links are the documents that may need syncing.
|
||||
|
||||
$ErrorActionPreference = "SilentlyContinue"
|
||||
|
||||
$scriptPath = $MyInvocation.MyCommand.Path
|
||||
if (-not [System.IO.Path]::IsPathRooted($scriptPath)) {
|
||||
$scriptPath = Join-Path (Get-Location) $scriptPath
|
||||
}
|
||||
$scriptPath = [System.IO.Path]::GetFullPath($scriptPath)
|
||||
$scriptDir = Split-Path -Parent $scriptPath
|
||||
$projectRoot = [System.IO.Path]::GetFullPath((Join-Path $scriptDir ".."))
|
||||
|
||||
Set-Location $projectRoot
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function Resolve-RelativePath {
|
||||
param(
|
||||
[string]$BaseFile,
|
||||
[string]$LinkPath
|
||||
)
|
||||
|
||||
# Skip anchors, query strings, and external URLs
|
||||
if ($LinkPath -match '^[a-zA-Z][a-zA-Z0-9+.-]*://') { return $null }
|
||||
if ([string]::IsNullOrWhiteSpace($LinkPath)) { return $null }
|
||||
|
||||
# Drop fragment
|
||||
$pathOnly = ($LinkPath -split '#')[0]
|
||||
if ([string]::IsNullOrWhiteSpace($pathOnly)) { return $null }
|
||||
|
||||
$baseDir = Split-Path -Parent $BaseFile
|
||||
$combined = Join-Path $baseDir $pathOnly
|
||||
try {
|
||||
$resolved = [System.IO.Path]::GetFullPath($combined)
|
||||
} catch {
|
||||
return $null
|
||||
}
|
||||
|
||||
# Convert to relative path from project root, normalizing separators
|
||||
$fullProjectRoot = [System.IO.Path]::GetFullPath($projectRoot)
|
||||
if ($resolved.StartsWith($fullProjectRoot, [System.StringComparison]::OrdinalIgnoreCase)) {
|
||||
$relative = $resolved.Substring($fullProjectRoot.Length).TrimStart('\', '/')
|
||||
return $relative -replace '\\', '/'
|
||||
}
|
||||
return $pathOnly -replace '\\', '/'
|
||||
}
|
||||
|
||||
function Get-DocumentAssociations {
|
||||
param(
|
||||
[string]$MdFile
|
||||
)
|
||||
|
||||
$fullPath = Join-Path $projectRoot $MdFile
|
||||
if (-not (Test-Path $fullPath)) { return @() }
|
||||
|
||||
$lines = [System.IO.File]::ReadAllLines($fullPath, [System.Text.Encoding]::UTF8)
|
||||
$associations = @()
|
||||
$inSection = $false
|
||||
$inCodeBlock = $false
|
||||
|
||||
foreach ($line in $lines) {
|
||||
# Toggle fenced code block state (``` or ~~~)
|
||||
if ($line -match '^\s*```' -or $line -match '^\s*~~~') {
|
||||
$inCodeBlock = -not $inCodeBlock
|
||||
continue
|
||||
}
|
||||
if ($inCodeBlock) { continue }
|
||||
|
||||
# Match exactly '## 文档关联' (not '## 文档关联机制' etc.).
|
||||
if ($line -match "^##\s+文档关联\s*$") {
|
||||
$inSection = $true
|
||||
continue
|
||||
}
|
||||
if ($inSection -and $line -match '^##\s+') {
|
||||
break
|
||||
}
|
||||
if ($inSection) {
|
||||
# Extract markdown links: [text](path)
|
||||
$regex = '\[(?<text>[^\]]*)\]\((?<path>[^\)]+)\)'
|
||||
$matches = [regex]::Matches($line, $regex)
|
||||
foreach ($match in $matches) {
|
||||
$linkPath = $match.Groups['path'].Value.Trim()
|
||||
$resolved = Resolve-RelativePath -BaseFile $MdFile -LinkPath $linkPath
|
||||
if ($resolved) {
|
||||
$associations += $resolved
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $associations | Select-Object -Unique
|
||||
}
|
||||
|
||||
function Test-WildcardMatch {
|
||||
param(
|
||||
[string]$Pattern,
|
||||
[string]$Path
|
||||
)
|
||||
$regex = "^" + ($Pattern -replace "\.", "\." -replace "\*", ".*" -replace "\?", ".") + "$"
|
||||
return $Path -match $regex
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Collect changed .md files (tracked modifications + untracked new files)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
$changedFiles = @(cmd /c "git diff --name-only 2>nul") | Where-Object { $_ }
|
||||
if ($changedFiles.Count -eq 0) {
|
||||
$changedFiles = @(cmd /c "git diff --name-only --cached 2>nul") | Where-Object { $_ }
|
||||
}
|
||||
|
||||
# Also include untracked .md files so new documents are checked too
|
||||
$untrackedFiles = @(cmd /c "git ls-files --others --exclude-standard 2>nul") | Where-Object { $_ }
|
||||
$allChangedFiles = @($changedFiles) + @($untrackedFiles) | Where-Object { $_ } | Select-Object -Unique
|
||||
|
||||
if (-not $allChangedFiles) {
|
||||
Write-Output "[archive-check] No documentation changes detected (git diff is empty and no untracked .md files)."
|
||||
exit 0
|
||||
}
|
||||
|
||||
$changedMdFiles = $allChangedFiles | Where-Object { $_ -like "*.md" } | Select-Object -Unique
|
||||
|
||||
if ($changedMdFiles.Count -eq 0) {
|
||||
Write-Output "[archive-check] No .md documentation changes detected."
|
||||
exit 0
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Build suggestions from each changed file's "## 文档关联" section
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
$suggestions = @{}
|
||||
|
||||
foreach ($changed in $changedMdFiles) {
|
||||
$relatedDocs = Get-DocumentAssociations -MdFile $changed
|
||||
foreach ($related in $relatedDocs) {
|
||||
# Normalize related path
|
||||
$relatedNormalized = $related -replace '\\', '/'
|
||||
if (-not $suggestions.ContainsKey($relatedNormalized)) {
|
||||
$suggestions[$relatedNormalized] = @()
|
||||
}
|
||||
if ($suggestions[$relatedNormalized] -notcontains $changed) {
|
||||
$suggestions[$relatedNormalized] += $changed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Output results
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Write-Output "[archive-check] Changed documentation files:"
|
||||
foreach ($changed in $changedMdFiles | Sort-Object) {
|
||||
Write-Output " - $changed"
|
||||
}
|
||||
|
||||
if ($suggestions.Count -eq 0) {
|
||||
Write-Output ""
|
||||
Write-Output "[archive-check] No associations found in changed files' `"## 文档关联`" sections."
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
Write-Output "[archive-check] Related docs that may need updating:"
|
||||
foreach ($related in $suggestions.Keys | Sort-Object) {
|
||||
$sources = $suggestions[$related] | Sort-Object
|
||||
$sourceList = $sources -join ", "
|
||||
Write-Output " - $related (mentioned by: $sourceList)"
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
Write-Output "[archive-check] Please confirm whether to sync-update the above docs."
|
||||
exit 0
|
||||
Reference in New Issue
Block a user