Update-ReadmeIndex.ps1
<#PSScriptInfo
.VERSION 1.0.0 .AUTHOR Roman Kuzmin .COPYRIGHT (c) Roman Kuzmin .TAGS Markdown README .GUID 0ab2bbcb-6552-415f-a102-7799e8a051b8 .LICENSEURI http://www.apache.org/licenses/LICENSE-2.0 .PROJECTURI https://github.com/nightroman/PowerShelf #> <# .Synopsis Updates markdown index from article directories. Author: Roman Kuzmin .Description The command scans the articles recursively, finds README.md files and builds the index from their first line headings in the main README.md. The generated list with links is inserted into the specified markdown file. The index start and end are defined by the HTML comments Mark1 and Mark2. .Parameter Path Specifies the source markdown file to be updated. Default: README.md .Parameter Articles Specifies the directory to scan for folders with README.md files. Default: 'Articles' .Parameter Depth Specifies the recursive scan depth. Default: 0, non-recursive scan. .Parameter Descending Tells to sort root directories descending. .Parameter Mark1 The HTML comment that marks the start of generated index. Default: '<!--Generated-->' .Parameter Mark2 The HTML comment that marks the end of generated index. Default: '<!--Generated-->' .Link https://github.com/nightroman/PowerShelf #> [CmdletBinding()] param( [string]$Path = 'README.md' , [string]$Articles = 'Articles' , [int]$Depth , [switch]$Descending , [string]$Mark1 = '<!--Generated-->' , [string]$Mark2 = '<!--Generated-->' ) $ErrorActionPreference = 1 Set-StrictMode -Version 3 trap { Write-Error $_ } $escape = [regex]@' [\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^_\`\{\|\}\~] '@ # Gets markdown list lines with links for folders recursively. function Get-List($Path, $Level) { $tab = ' ' * $Level # get and sort directories $items = Get-ChildItem -LiteralPath $Path -Name -Directory if ($Level -eq 0) { $items = $items | Sort-Object -Descending:$Descending } foreach($dir in $items) { # skip the folder without README $readme = "$Path/$dir/README.md" if (!(Test-Path -LiteralPath $readme)) { continue } # the first README line must be heading, get the topic text switch -File $readme -Regex { '^#{1,6}(.*)' { $topic = $escape.Replace($matches[1].Trim(), '\$0') break } default { throw "Expected first line heading in '$readme'" } } # output the list line with the topic link '{0}- [{1}]({2})' -f $tab, $topic, "$Path/$dir" # process sub-folders if ($Level -lt $Depth) { Get-List "$Path/$dir" ($Level + 1) } } } $Path = $PSCmdlet.GetUnresolvedProviderPathFromPSPath($Path) if (!(Test-Path -LiteralPath $Path)) { throw "'$Path' does not exist." } # collect lines before and after marks $lines1 = [System.Collections.Generic.List[string]]@() $lines2 = [System.Collections.Generic.List[string]]@() $step = 1 foreach($_ in Get-Content -LiteralPath $Path) { if ($step -eq 1) { $lines1.Add($_) if ($_ -eq $Mark1) { ++$step } continue } if ($step -eq 2) { if ($_ -eq $Mark2) { $lines2.Add($_) ++$step } continue } $lines2.Add($_) } if ($step -ne 3) { throw "Cannot find mark '$Mark1' or '$Mark2' in '$Path'." } # update source file $( $lines1 Get-List $Articles 0 $lines2 ) | Set-Content -LiteralPath $Path -Encoding UTF8 |