Add ks-zl skill
This commit is contained in:
200
scripts/build-requirement-index.ps1
Normal file
200
scripts/build-requirement-index.ps1
Normal file
@@ -0,0 +1,200 @@
|
||||
param(
|
||||
[string]$Root = (Get-Location).Path,
|
||||
[string]$OutputPath,
|
||||
[switch]$Quiet
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
if (-not (Test-Path -LiteralPath $Root)) {
|
||||
throw "Root path does not exist: $Root"
|
||||
}
|
||||
|
||||
$rootPath = (Resolve-Path -LiteralPath $Root).Path.TrimEnd([char[]]"\/")
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($OutputPath)) {
|
||||
$OutputPath = Join-Path (Join-Path $rootPath "_indexes") "requirements-index.json"
|
||||
}
|
||||
|
||||
function Get-RelativePath {
|
||||
param([string]$Path)
|
||||
|
||||
$fullPath = (Resolve-Path -LiteralPath $Path).Path
|
||||
if ($fullPath.StartsWith($rootPath, [System.StringComparison]::OrdinalIgnoreCase)) {
|
||||
return ($fullPath.Substring($rootPath.Length).TrimStart([char[]]"\/") -replace "\\", "/")
|
||||
}
|
||||
|
||||
return ($fullPath -replace "\\", "/")
|
||||
}
|
||||
|
||||
function Get-FrontMatter {
|
||||
param([string]$Content)
|
||||
|
||||
$match = [regex]::Match($Content, "(?s)\A---\r?\n(?<body>.*?)\r?\n---")
|
||||
if ($match.Success) {
|
||||
return $match.Groups["body"].Value
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
function Get-MetadataValue {
|
||||
param(
|
||||
[string]$FrontMatter,
|
||||
[string]$Key
|
||||
)
|
||||
|
||||
$match = [regex]::Match($FrontMatter, "(?m)^$([regex]::Escape($Key))\s*:\s*(?<value>.*)\s*$")
|
||||
if ($match.Success) {
|
||||
return $match.Groups["value"].Value.Trim().Trim('"').Trim("'")
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
function Get-MetadataList {
|
||||
param(
|
||||
[string]$FrontMatter,
|
||||
[string]$Key
|
||||
)
|
||||
|
||||
$lines = $FrontMatter -split "`r?`n"
|
||||
$values = New-Object System.Collections.Generic.List[string]
|
||||
|
||||
for ($i = 0; $i -lt $lines.Count; $i++) {
|
||||
if ($lines[$i] -match "^$([regex]::Escape($Key))\s*:\s*(?<inline>.*)\s*$") {
|
||||
$inline = $Matches["inline"].Trim()
|
||||
if ($inline.StartsWith("[") -and $inline.EndsWith("]")) {
|
||||
$inline.Trim("[]").Split(",") |
|
||||
ForEach-Object { $_.Trim().Trim('"').Trim("'") } |
|
||||
Where-Object { -not [string]::IsNullOrWhiteSpace($_) } |
|
||||
ForEach-Object { [void]$values.Add($_) }
|
||||
}
|
||||
|
||||
for ($j = $i + 1; $j -lt $lines.Count; $j++) {
|
||||
if ($lines[$j] -match "^\s*-\s*(?<value>.+?)\s*$") {
|
||||
[void]$values.Add($Matches["value"].Trim().Trim('"').Trim("'"))
|
||||
continue
|
||||
}
|
||||
|
||||
if ($lines[$j] -match "^\S[^:]*\s*:") {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return @($values)
|
||||
}
|
||||
|
||||
function Get-MarkdownSectionBody {
|
||||
param(
|
||||
[string]$Content,
|
||||
[string]$Section
|
||||
)
|
||||
|
||||
$match = [regex]::Match($Content, "(?ms)^##\s+$([regex]::Escape($Section))[ `t]*\r?\n(?<body>.*?)(?=^##\s+|\z)")
|
||||
if ($match.Success) {
|
||||
return $match.Groups["body"].Value
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
function ConvertTo-PlainText {
|
||||
param([string]$Value)
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($Value)) {
|
||||
return ""
|
||||
}
|
||||
|
||||
return (($Value -replace "`r?`n", " ") -replace "\s+", " ").Trim()
|
||||
}
|
||||
|
||||
function Get-PackageInfo {
|
||||
param([string]$RelativePath)
|
||||
|
||||
$parts = $RelativePath -split "/"
|
||||
$domain = ""
|
||||
$packageType = ""
|
||||
$slug = ""
|
||||
|
||||
if ($parts.Count -ge 4) {
|
||||
$domain = $parts[0]
|
||||
$packageType = $parts[1]
|
||||
$slug = $parts[2]
|
||||
}
|
||||
|
||||
return [pscustomobject]@{
|
||||
domain = $domain
|
||||
packageType = $packageType
|
||||
slug = $slug
|
||||
}
|
||||
}
|
||||
|
||||
$excludedTopDirs = @(".git", "templates", "scripts")
|
||||
$requirementFiles = Get-ChildItem -Path $rootPath -Recurse -File -Filter "requirement.md" -Force |
|
||||
Where-Object {
|
||||
$relativePath = Get-RelativePath $_.FullName
|
||||
$topDir = ($relativePath -split "/")[0]
|
||||
$excludedTopDirs -notcontains $topDir
|
||||
}
|
||||
|
||||
$items = New-Object System.Collections.Generic.List[object]
|
||||
|
||||
foreach ($file in $requirementFiles) {
|
||||
$relativePath = Get-RelativePath $file.FullName
|
||||
$content = Get-Content -Raw -Encoding UTF8 -LiteralPath $file.FullName
|
||||
|
||||
if ($content -notmatch "(?m)^status:\s*requirement-draft\s*$") {
|
||||
continue
|
||||
}
|
||||
|
||||
$frontMatter = Get-FrontMatter -Content $content
|
||||
$packageInfo = Get-PackageInfo -RelativePath $relativePath
|
||||
$tags = @(Get-MetadataList -FrontMatter $frontMatter -Key "tags")
|
||||
|
||||
[void]$items.Add([pscustomobject][ordered]@{
|
||||
schemaVersion = 1
|
||||
type = "requirement-package"
|
||||
title = Get-MetadataValue -FrontMatter $frontMatter -Key "title"
|
||||
category = Get-MetadataValue -FrontMatter $frontMatter -Key "category"
|
||||
tags = $tags
|
||||
status = Get-MetadataValue -FrontMatter $frontMatter -Key "status"
|
||||
updated = Get-MetadataValue -FrontMatter $frontMatter -Key "updated"
|
||||
source = Get-MetadataValue -FrontMatter $frontMatter -Key "source"
|
||||
domain = $packageInfo.domain
|
||||
packageType = $packageInfo.packageType
|
||||
slug = $packageInfo.slug
|
||||
relativePath = $relativePath
|
||||
fullPath = $file.FullName
|
||||
feature = ConvertTo-PlainText (Get-MarkdownSectionBody -Content $content -Section "功能")
|
||||
flow = ConvertTo-PlainText (Get-MarkdownSectionBody -Content $content -Section "流程")
|
||||
dataTables = ConvertTo-PlainText (Get-MarkdownSectionBody -Content $content -Section "数据表")
|
||||
dictionaries = ConvertTo-PlainText (Get-MarkdownSectionBody -Content $content -Section "字典")
|
||||
businessRules = ConvertTo-PlainText (Get-MarkdownSectionBody -Content $content -Section "业务规则")
|
||||
acceptance = ConvertTo-PlainText (Get-MarkdownSectionBody -Content $content -Section "验收")
|
||||
portability = ConvertTo-PlainText (Get-MarkdownSectionBody -Content $content -Section "移植说明")
|
||||
sourceEvidence = ConvertTo-PlainText (Get-MarkdownSectionBody -Content $content -Section "来源依据")
|
||||
pending = ConvertTo-PlainText (Get-MarkdownSectionBody -Content $content -Section "待确认")
|
||||
related = ConvertTo-PlainText (Get-MarkdownSectionBody -Content $content -Section "Related")
|
||||
})
|
||||
}
|
||||
|
||||
$outputDirectory = Split-Path -Parent $OutputPath
|
||||
if (-not [string]::IsNullOrWhiteSpace($outputDirectory) -and -not (Test-Path -LiteralPath $outputDirectory)) {
|
||||
New-Item -ItemType Directory -Path $outputDirectory -Force | Out-Null
|
||||
}
|
||||
|
||||
$itemArray = @($items.ToArray())
|
||||
$json = ConvertTo-Json -InputObject $itemArray -Depth 8
|
||||
Set-Content -LiteralPath $OutputPath -Value $json -Encoding UTF8
|
||||
|
||||
if (-not $Quiet) {
|
||||
Write-Host "Requirement index built. Indexed $($items.Count) package(s): $OutputPath"
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user