platyPS icon indicating copy to clipboard operation
platyPS copied to clipboard

Support for data from XMLdoc for binary modules

Open svrooij opened this issue 1 year ago • 4 comments

Summary of the new feature / enhancement

As a developer of a binary powershell module I would like to document in inside the C# files, as I'm used to for creating C# libraries.

Proposed technical implementation details (optional)

I suggest supporting XML docs above the PsCmdLet as follows:

/// <summary>
/// <para type="synopsis">Synopsis here</para>
/// <para type="description">Long description here</para>
/// <para type="link" uri="https://wintuner.app/docs/related/content-prep-tool">Documentation</para> 
/// </summary>
/// <example>
/// <para type="description">Sample description here</para>
/// <code>Sample code here</code>
/// </example>

And I wrote a powershell script that parses the generated C# xml documentation file and updates the markdown files accordingly. This powershell replaces the placeholders with data from the xml docs. If the data is already updated nothing will happen. Off-course it would be better to integrate this right into the normal c# code that does the markdown generation. Something like -GenerateUsingXmlDocs <docsLocation>.

  1. Execute New-MarkdownHelp ... first, to create the docs files.
  2. Put this script in the root of your project.
  3. Execute this script to update the markdown files, and to create the external help file in the root of your project.
  4. Mark the external help file as None and Copy Always in the properties in Visual Studio.
# change accordingly
$xmlDocsPath = ".\bin\Release\net7.0\ProjectName.xml"
$docsFolder = "docs"

# Start Process to build the project
$buildOutput = & dotnet build -c Release -v quiet

# Check if the build succeeded by looking for the string "Build succeeded."
if ($buildOutput -match "Build succeeded.") {
    Write-Output "Project build succeeded"
}
else {
    Write-Output "Build failed"
    Write-Output $buildOutput
    exit
}

Write-Output "Generating docs from XML file $xmlDocsPath"

# Load the XML documentation file
[xml]$xmlDocs = Get-Content $xmlDocsPath

$assemblyName = $xmlDocs.doc.assembly.name
Write-Debug "Updating docs for Assembly: $assemblyName"

$members = $xmlDocs.doc.members.member

# Iterate over all <member> objects
foreach ($member in $members) {
    # member looks like this:
    # <member name="T:Your.Namespace.ClassNameForPsCmdLet">
    #   <summary>
    #   <para type="synopsis">synopsis here</para>
    #   <para type="description">PsCmdLet description here</para>
    #   <para type="link" uri="https://wintuner.app/docs/related/content-prep-tool">Documentation</para> 
    #   </summary>
    #   <example>
    #   <para type="description">Sample description here</para>
    #   <code>Sample Code here</code>
    #   </example>
    # </member>
    # Extract the name of the member
    $name = $member.Attributes[0].'#text'

    if ($name.startsWith("T:" + $assemblyName)) {
		    $name = $name.substring(2 + $assemblyName.length + 1)
        # name NewIntuneWinPackage
        Write-Output "Try to update markdown file for: $name"

        # Extract the synopsis
        $synopsis = $member.summary.'para' | Where-Object { $_.type -eq 'synopsis' } | Select-Object -ExpandProperty '#text'
        Write-Debug "Synopsis: $synopsis"

        # Extract the description
        $description = $member.summary.'para' | Where-Object { $_.type -eq 'description' } | Select-Object -ExpandProperty '#text'
        Write-Debug "Description: $description"

        # Extract the example
        $exampleDescription = $member.example.'para'| Where-Object { $_.type -eq 'description' } | Select-Object -ExpandProperty '#text'
        $exampleCode = $member.example.'code'

        Write-Debug "Example Description: $exampleDescription"
        Write-Debug "Example Code: $exampleCode"

        # Create the MD file name by putting a - only before the second capital letter, so NewIntuneWinPackage becomes New-IntuneWinPackage
        $index = $name.IndexOfAny([char[]]"ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray(), 1)
        $mdFile = $name.Substring(0, $index) + "-" + $name.Substring($index) + ".md"
        Write-Debug "MD Filename: $mdFile"

        # Check if the $mdFile exists in the docs folder
        $mdFilePath = Join-Path "${PSScriptRoot}\$docsFolder" $mdFile
        if (Test-Path $mdFilePath) {
            # load the existing file
            $mdFileContent = Get-Content $mdFilePath

            # Replace the synopsis placeholder '{{ Fill in the Synopsis }}' with the actual synopsis
            $mdFileContent = $mdFileContent.Replace('{{ Fill in the Synopsis }}', $synopsis)

            # Replace the description placeholder '{{ Fill in the Description }}' with the actual description
            $mdFileContent = $mdFileContent.Replace('{{ Fill in the Description }}', $description)

            # Replace the example description placeholder '{{ Add example description here }}' with the actual example description
            $mdFileContent = $mdFileContent.Replace('{{ Add example description here }}', $exampleDescription)

            # Replace the example code placeholder '{{ Add example code here }}' with the actual example code
            $mdFileContent = $mdFileContent.Replace('{{ Add example code here }}', $exampleCode)

            # Write the updated file back to disk
            $mdFileContent | Set-Content $mdFilePath
        }
        else {
            Write-Warning "File $mdFilePath does not exist"
        }
	}
}

Write-Output "Done updating markdown files with XML documentation"

New-ExternalHelp -Path "${PSScriptRoot}\$docsFolder" -OutputPath "${PSScriptRoot}" -Force

svrooij avatar Jan 11 '24 21:01 svrooij