Pomocy! Zepsułem pomoc!
PowerShell posiada bardzo przydatną funkcję: pomoc do funkcji i skryptów definiowaną za pomocą komentarza na początku, końcu (sprawdza się w przypadku skryptów i funkcji) lub tuż przed definicją (naturalnie, działa dobrze tylko w przypadku funkcji). Niestety, pomoc ta jest dość wrażliwa i niewielka literówka może sprawić, że cały nasz wysiłek włożony w jej przygotowanie pójdzie na marne i nasza pomoc w formie komentarza stanie się zwyczajnym komentarzem, nie oferującym pomocy w oczekiwany sposób.
Co jednak zrobić, gdy nasza pomoc nagle przestanie działać? Możliwości jest kilka. Po pierwsze niektóre edytory kodu (na przykład VS Code) mogą wskazać nam kiedy nasza składnia jest poprawna (odpowiednio zaznaczając nagłówki fragmentów pomocy), jeśli więc takiego oznaczenia nie widzimy, to prawdopodobnie mamy gdzieś literówkę.
Sytuacja komplikuje się oczywiście, gdy takich plików mamy więcej. W takiej sytuacji pomoże nam oczywiście PowerShell.
Przygotujemy funkcję, która z wybranego pliku „wyłuska” interesującą nas funkcję. Następnie przeanalizuje ona ciało tej funkcji w poszukiwaniu komentarza. Jeśli będzie to pierwszy lub ostatni element w ciele funkcji – będziemy sprawdzać, czy stanowi on poprawną pomoc.
Na początek: wyłuskanie funkcji z pliku. Skorzystamy w tym celu z Abstract Syntax Tree (AST). Dzięki temu narzędziu możemy w pliku wyszukać wszystkich definicji funkcji o interesującej nas nazwie. Zgodnie z logiką PowerShella nas interesować będzie ostatnia definicja (wszystkie poprzednie będą przez tę ostatnią nadpisane):
$ast = [System.Management.Automation.Language.Parser]::ParseFile($Path, [ref]$null, [ref]$null) | |
$definicja = $ast.FindAll( | |
{ | |
param ([System.Management.Automation.Language.Ast]$astElement) | |
$astElement -is [System.Management.Automation.Language.FunctionDefinitionAst] -and | |
$astElement.Name -eq $Name | |
}, | |
$false | |
) | Select-Object -Last 1 |
Następny etap to wyciągnięcie pierwszego i ostatniego elementu i sprawdzenie, czy któryś z tych elementów jest komentarzem. Analizować będziemy jedynie ciało funkcji, pomijając przy tym początkową klamrę, klamrę końcową i jakiekolwiek otaczające ją puste linie:
$lastToken = $tokens.Count - 3 | |
$first = @($tokens[1..$lastToken]).Where( | |
{ | |
$_.Kind -ne 'NewLine' | |
}, | |
'First' | |
) | |
$last = @($tokens[1..$lastToken]).Where( | |
{ | |
$_.Kind -ne 'NewLine' | |
}, | |
'Last' | |
) |
Pozostaje nam jedynie sprawdzenie, czy element jest komentarzem i czy zawiera pomoc oraz sprawdzenie, czy składnia jest prawidłowa:
$keywords = @( | |
'Synopsis' | |
'Description' | |
'Example' | |
'Inputs' | |
'Outputs' | |
'Notes' | |
'Link' | |
'Component' | |
'Role' | |
'Functionality' | |
) | |
foreach ($suspect in $first, $last) { | |
if ($suspect.Kind -eq 'Comment') { | |
@([regex]::Matches($suspect.Text, '(?m)^\s*\.(.*)$')).Where{ | |
$_.Groups[1].Value.Trim() -notin $keywords -and | |
$_.Groups[1].Value -notmatch 'Parameter \w+' | |
}.ForEach{ | |
'Nieprawidłowa składnia w pomocy: .{0}' -f $_.Groups[1].Value | |
} | |
} else { | |
Write-Verbose -Message "Odnaleziony element nie jest komentarzem: $suspect" | |
} | |
} |
Pozostaje tylko sprawdzić, czy nasza funkcja działa zgodnie z oczekiwaniem. Popsuta pomoc, którą widzieliśmy w ramach VS Code powinna również „ujawnić się” w przypadku skorzystania z naszej funkcji. Wynik:
Dzięki funkcji możemy odnaleźć problemy we wszystkich naszych funkcjach, nie otwierając każdej z osobna w VS Code.