286 lines
9.8 KiB
PowerShell
286 lines
9.8 KiB
PowerShell
param(
|
|
[string]$RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
$sourceDir = Join-Path $RepoRoot "data/tsl_reference_catalog_source"
|
|
$outputDir = Join-Path $RepoRoot "docs/tsl/reference/catalog"
|
|
|
|
$moduleOrder = @(
|
|
[pscustomobject]@{ File = "base"; Summary = "字符串、数组、日期时间、类型转换与常用基础能力" }
|
|
[pscustomobject]@{ File = "math"; Summary = "数值计算、统计分析、矩阵处理与数学算法" }
|
|
[pscustomobject]@{ File = "system"; Summary = "数据类型、表达式调用、性能与运行时能力" }
|
|
[pscustomobject]@{ File = "resource"; Summary = "文件、数据库、网络与外部资源访问" }
|
|
[pscustomobject]@{ File = "platform"; Summary = "平台相关功能与系统接口" }
|
|
[pscustomobject]@{ File = "client"; Summary = "客户端交互、界面控制与前端协作能力" }
|
|
[pscustomobject]@{ File = "graphics"; Summary = "图表、绘图与可视化相关函数" }
|
|
[pscustomobject]@{ File = "compression"; Summary = "压缩、解压与归档能力" }
|
|
[pscustomobject]@{ File = "digest_encoding"; Summary = "哈希、摘要、编码与转换能力" }
|
|
[pscustomobject]@{ File = "third_party"; Summary = "第三方库与外部程序交互能力" }
|
|
)
|
|
|
|
function Get-HeadingSections {
|
|
param([string[]]$Lines)
|
|
|
|
$sections = @()
|
|
|
|
for ($i = 0; $i -lt $Lines.Count; $i++) {
|
|
if ($Lines[$i] -match '^(#{4,7})\s+(.+?)\s*$') {
|
|
$sections += [pscustomobject]@{
|
|
Level = $Matches[1].Length
|
|
Title = $Matches[2].Trim()
|
|
Start = $i
|
|
}
|
|
}
|
|
}
|
|
|
|
for ($i = 0; $i -lt $sections.Count; $i++) {
|
|
$nextStart = if ($i + 1 -lt $sections.Count) { $sections[$i + 1].Start } else { $Lines.Count }
|
|
$sections[$i] | Add-Member -NotePropertyName End -NotePropertyValue ($nextStart - 1)
|
|
}
|
|
|
|
return $sections
|
|
}
|
|
|
|
function Test-IsFunctionSection {
|
|
param(
|
|
[string]$Title,
|
|
[string[]]$BodyLines
|
|
)
|
|
|
|
if ($null -eq $BodyLines -or $BodyLines.Count -eq 0) {
|
|
return $false
|
|
}
|
|
|
|
$body = $BodyLines -join "`n"
|
|
$hasStructuredMarkers = (
|
|
$body -match '(^|\n)\s*用途:' -or
|
|
$body -match '(^|\n)\s*参数:' -or
|
|
$body -match '(^|\n)\s*返回:'
|
|
)
|
|
|
|
if ($hasStructuredMarkers) {
|
|
return $true
|
|
}
|
|
|
|
$looksLikeFunctionName = $Title -match '^[A-Za-z_][A-Za-z0-9_]*$'
|
|
$hasMeaningfulBody = $body -match '\S'
|
|
|
|
return (
|
|
$looksLikeFunctionName -and
|
|
$hasMeaningfulBody
|
|
)
|
|
}
|
|
|
|
function Add-FunctionToGroup {
|
|
param(
|
|
[System.Collections.Specialized.OrderedDictionary]$GroupMap,
|
|
[string]$Category,
|
|
[string]$Subcategory,
|
|
[string]$FunctionName
|
|
)
|
|
|
|
if ([string]::IsNullOrWhiteSpace($FunctionName)) {
|
|
return
|
|
}
|
|
|
|
$categoryName = if ([string]::IsNullOrWhiteSpace($Category)) { "未分类" } else { $Category }
|
|
$groupTitle = if ([string]::IsNullOrWhiteSpace($Subcategory)) {
|
|
$categoryName
|
|
}
|
|
else {
|
|
"{0} / {1}" -f $categoryName, $Subcategory
|
|
}
|
|
|
|
if (-not $GroupMap.Contains($groupTitle)) {
|
|
$GroupMap[$groupTitle] = [pscustomobject]@{
|
|
Title = $groupTitle
|
|
Category = $categoryName
|
|
Subcategory = $Subcategory
|
|
Functions = [System.Collections.Generic.List[string]]::new()
|
|
}
|
|
}
|
|
|
|
$functionList = $GroupMap[$groupTitle].Functions
|
|
if (-not $functionList.Contains($FunctionName)) {
|
|
$functionList.Add($FunctionName)
|
|
}
|
|
}
|
|
|
|
function Parse-TslFunctionModule {
|
|
param([string]$Path)
|
|
|
|
$lines = Get-Content -LiteralPath $Path
|
|
$sections = Get-HeadingSections -Lines $lines
|
|
$moduleTitle = ($sections | Where-Object { $_.Level -eq 4 } | Select-Object -First 1).Title
|
|
|
|
if ([string]::IsNullOrWhiteSpace($moduleTitle)) {
|
|
throw "Unable to detect module title in $Path"
|
|
}
|
|
|
|
$groupMap = [ordered]@{}
|
|
$currentCategory = $null
|
|
$currentSubcategory = $null
|
|
|
|
foreach ($section in $sections | Where-Object { $_.Level -ge 5 }) {
|
|
$title = $section.Title.Trim()
|
|
if ($title -in @("内容", "范例")) {
|
|
continue
|
|
}
|
|
|
|
$bodyLines = @()
|
|
if ($section.End -gt $section.Start) {
|
|
$bodyLines = $lines[($section.Start + 1)..$section.End]
|
|
}
|
|
|
|
$isFunction = Test-IsFunctionSection -Title $title -BodyLines $bodyLines
|
|
|
|
switch ($section.Level) {
|
|
5 {
|
|
if ($isFunction) {
|
|
Add-FunctionToGroup -GroupMap $groupMap -Category "直接函数" -Subcategory $null -FunctionName $title
|
|
}
|
|
else {
|
|
$currentCategory = $title
|
|
$currentSubcategory = $null
|
|
}
|
|
continue
|
|
}
|
|
6 {
|
|
if ($isFunction) {
|
|
Add-FunctionToGroup -GroupMap $groupMap -Category $currentCategory -Subcategory $null -FunctionName $title
|
|
}
|
|
else {
|
|
$currentSubcategory = $title
|
|
}
|
|
continue
|
|
}
|
|
7 {
|
|
if ($isFunction) {
|
|
Add-FunctionToGroup -GroupMap $groupMap -Category $currentCategory -Subcategory $currentSubcategory -FunctionName $title
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
$groups = foreach ($entry in $groupMap.GetEnumerator()) {
|
|
[pscustomobject]@{
|
|
Title = $entry.Value.Title
|
|
Category = $entry.Value.Category
|
|
Subcategory = $entry.Value.Subcategory
|
|
Functions = @($entry.Value.Functions)
|
|
}
|
|
}
|
|
|
|
$functionCount = ($groups | ForEach-Object { $_.Functions } | Sort-Object -Unique).Count
|
|
|
|
return [pscustomobject]@{
|
|
File = [System.IO.Path]::GetFileNameWithoutExtension($Path)
|
|
ModuleTitle = $moduleTitle
|
|
Groups = $groups
|
|
FunctionCount = $functionCount
|
|
}
|
|
}
|
|
|
|
function New-MarkdownModulePage {
|
|
param(
|
|
[pscustomobject]$Module,
|
|
[string]$Summary
|
|
)
|
|
|
|
$lines = [System.Collections.Generic.List[string]]::new()
|
|
$lines.Add("# $($Module.ModuleTitle)")
|
|
$lines.Add("")
|
|
$lines.Add("这一页只负责函数定位:先按主题找到模块,再在页内搜索函数名。")
|
|
$lines.Add("")
|
|
$lines.Add("## 使用方式")
|
|
$lines.Add("")
|
|
$lines.Add("- 返回总目录:[catalog/index.md](index.md)")
|
|
$lines.Add("- 需要基础语法时回到 [../../syntax/index.md](../../syntax/index.md)")
|
|
$lines.Add("- 需要金融任务组织方式时回到 [../../finance/index.md](../../finance/index.md)")
|
|
$lines.Add("")
|
|
$lines.Add("## 模块范围")
|
|
$lines.Add("")
|
|
$lines.Add("- 说明:$Summary")
|
|
$lines.Add("- 主题数:$($Module.Groups.Count)")
|
|
$lines.Add("- 函数数:$($Module.FunctionCount)")
|
|
$lines.Add("")
|
|
$lines.Add("## 主题目录")
|
|
$lines.Add("")
|
|
|
|
foreach ($group in $Module.Groups) {
|
|
$lines.Add("### $($group.Title)")
|
|
$lines.Add("")
|
|
foreach ($functionName in $group.Functions) {
|
|
$lines.Add("- ``$functionName``")
|
|
}
|
|
$lines.Add("")
|
|
}
|
|
|
|
return ($lines -join "`r`n").TrimEnd() + "`r`n"
|
|
}
|
|
|
|
function New-MarkdownCatalogIndex {
|
|
param([object[]]$Modules)
|
|
|
|
$lines = [System.Collections.Generic.List[string]]::new()
|
|
$lines.Add("# Function Catalog")
|
|
$lines.Add("")
|
|
$lines.Add('这里是 canonical 函数目录。它只回答“函数在哪个模块里”,不承担基础语法教学。')
|
|
$lines.Add("")
|
|
$lines.Add("## 使用顺序")
|
|
$lines.Add("")
|
|
$lines.Add("1. 不知道函数在哪个模块,先看下面的模块目录。")
|
|
$lines.Add("2. 进入模块页后,在页内搜索具体函数名。")
|
|
$lines.Add("3. 如果问题是语法怎么写,回到 [../../syntax/index.md](../../syntax/index.md)。")
|
|
$lines.Add("4. 如果问题是金融场景如何组织,回到 [../../finance/index.md](../../finance/index.md)。")
|
|
$lines.Add("")
|
|
$lines.Add("## 模块目录")
|
|
$lines.Add("")
|
|
$lines.Add("| 模块 | 分类页 | 范围 | 函数数 |")
|
|
$lines.Add("| --- | --- | --- | --- |")
|
|
|
|
foreach ($module in $Modules) {
|
|
$pageName = "{0}.md" -f $module.File
|
|
$lines.Add("| $($module.ModuleTitle) | [$pageName]($pageName) | $($module.Summary) | $($module.FunctionCount) |")
|
|
}
|
|
|
|
$lines.Add("")
|
|
$lines.Add("## 说明")
|
|
$lines.Add("")
|
|
$lines.Add("- 这套目录页由仓库内的函数语料自动整理生成。")
|
|
$lines.Add("- 当前目标是先提供稳定检索层,再逐步补全更细的 canonical 说明。")
|
|
$lines.Add("")
|
|
|
|
return ($lines -join "`r`n").TrimEnd() + "`r`n"
|
|
}
|
|
|
|
if (-not (Test-Path -LiteralPath $sourceDir)) {
|
|
throw "Source directory not found: $sourceDir"
|
|
}
|
|
|
|
New-Item -ItemType Directory -Force -Path $outputDir | Out-Null
|
|
|
|
$modules = foreach ($meta in $moduleOrder) {
|
|
$sourcePath = Join-Path $sourceDir ("{0}.md" -f $meta.File)
|
|
if (-not (Test-Path -LiteralPath $sourcePath)) {
|
|
throw "Missing module source: $sourcePath"
|
|
}
|
|
|
|
$module = Parse-TslFunctionModule -Path $sourcePath
|
|
$module | Add-Member -NotePropertyName Summary -NotePropertyValue $meta.Summary
|
|
$module
|
|
}
|
|
|
|
$catalogIndex = New-MarkdownCatalogIndex -Modules $modules
|
|
Set-Content -LiteralPath (Join-Path $outputDir "index.md") -Value $catalogIndex -Encoding UTF8
|
|
|
|
foreach ($module in $modules) {
|
|
$page = New-MarkdownModulePage -Module $module -Summary $module.Summary
|
|
Set-Content -LiteralPath (Join-Path $outputDir ("{0}.md" -f $module.File)) -Value $page -Encoding UTF8
|
|
}
|
|
|
|
Write-Output ("Generated {0} catalog pages in {1}" -f ($modules.Count + 1), $outputDir)
|