From 7da47510f5b3fd7ac20baaed4a8b2e4bc0fea5ee Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Tue, 29 Jun 2021 16:40:13 -0700 Subject: [PATCH] Fix issues with module name and external help file metadata (#542) --- .../Model/YAML/YamlInputOutput.cs | 18 ++- src/platyPS/platyPS.psm1 | 51 +++++- test/Pester/PlatyPs.Tests.ps1 | 25 +++ .../assets/ModuleWithDash/Test-Module.md | 16 ++ .../ModuleWithDash/Test-ModuleCmdlet.md | 46 ++++++ test/Pester/assets/NestedMod/Nest.psm1 | 7 + test/Pester/assets/NestedMod/NestedMod.psd1 | 132 +++++++++++++++ test/Pester/assets/New-YamlHelp.md | 153 ++++++++++++++++++ 8 files changed, 444 insertions(+), 4 deletions(-) create mode 100644 test/Pester/assets/ModuleWithDash/Test-Module.md create mode 100644 test/Pester/assets/ModuleWithDash/Test-ModuleCmdlet.md create mode 100644 test/Pester/assets/NestedMod/Nest.psm1 create mode 100644 test/Pester/assets/NestedMod/NestedMod.psd1 create mode 100644 test/Pester/assets/New-YamlHelp.md diff --git a/src/Markdown.MAML/Model/YAML/YamlInputOutput.cs b/src/Markdown.MAML/Model/YAML/YamlInputOutput.cs index 1c678ebd..6c8625e5 100644 --- a/src/Markdown.MAML/Model/YAML/YamlInputOutput.cs +++ b/src/Markdown.MAML/Model/YAML/YamlInputOutput.cs @@ -2,7 +2,23 @@ { public class YamlInputOutput { - public string Type { get; set; } + string _type; + public string Type + { + get + { + if (_type.Contains("#")) + { + return _type.Replace("#", "\\#"); + } + + return _type; + } + set + { + _type = value; + } + } public string Description { get; set; } } } \ No newline at end of file diff --git a/src/platyPS/platyPS.psm1 b/src/platyPS/platyPS.psm1 index 763023db..26810ac4 100644 --- a/src/platyPS/platyPS.psm1 +++ b/src/platyPS/platyPS.psm1 @@ -834,7 +834,12 @@ function New-ExternalHelp process { - $MarkdownFiles += GetMarkdownFilesFromPath $Path + $files = GetMarkdownFilesFromPath $Path + + if ($files) + { + $MarkdownFiles += FilterMdFileToExcludeModulePage -Path $files + } if($MarkdownFiles) { @@ -1481,6 +1486,35 @@ function GetAboutTopicsFromPath return $AboutMarkDownFiles } +function FilterMdFileToExcludeModulePage { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [System.IO.FileInfo[]]$Path + ) + + $MarkdownFiles = @() + + if ($Path) { + $Path | ForEach-Object { + if (Test-Path $_.FullName) { + $md = Get-Content -Raw -Path $_.FullName + $yml = [Markdown.MAML.Parser.MarkdownParser]::GetYamlMetadata($md) + $isModulePage = $null -ne $yml.'Module Guid' + + if (-not $isModulePage) { + $MarkdownFiles += $_ + } + } + else { + Write-Error -Message ($LocalizedData.PathNotFound -f $_.FullName) + } + } + } + + return $MarkdownFiles +} + function GetMarkdownFilesFromPath { [CmdletBinding()] @@ -1503,7 +1537,6 @@ function GetMarkdownFilesFromPath $aboutFilePrefixPattern = 'about_*' - $MarkdownFiles = @() if ($Path) { $Path | ForEach-Object { @@ -1830,6 +1863,13 @@ function GetHelpFileName Where-Object {$_.ModuleType -ne 'Manifest'} | Where-Object {$_.ExportedCommands.Keys -contains $CommandInfo.Name} + $nestedModules = @( + ($CommandInfo.Module.NestedModules) | + Where-Object { $_.ModuleType -ne 'Manifest' } | + Where-Object { $_.ExportedCommands.Keys -contains $CommandInfo.Name } | + Select-Object -ExpandProperty Path + ) + if (-not $module) { Write-Warning -Message ($LocalizedData.ModuleNotFoundFromCommand -f '[GetHelpFileName]', $CommandInfo.Name) @@ -1846,7 +1886,12 @@ function GetHelpFileName { # for regular modules, we can deduct the filename from the module path file $moduleItem = Get-Item -Path $module.Path - if ($moduleItem.Extension -eq '.psm1') { + + $isModuleItemNestedModule = + $null -ne ($nestedModules | Where-Object { $_ -eq $module.Path }) -and + $CommandInfo.ModuleName -ne $module.Name + + if ($moduleItem.Extension -eq '.psm1' -and -not $isModuleItemNestedModule) { $fileName = $moduleItem.BaseName } else { $fileName = $moduleItem.Name diff --git a/test/Pester/PlatyPs.Tests.ps1 b/test/Pester/PlatyPs.Tests.ps1 index 153604d0..c5780914 100644 --- a/test/Pester/PlatyPs.Tests.ps1 +++ b/test/Pester/PlatyPs.Tests.ps1 @@ -705,6 +705,18 @@ Get-Alpha [-WhatIf] [[-CCC] ] [[-ddd] ] [] $help.parameters.parameter | Where-Object { $_.Name -eq 'NameNoWildCard' } | ForEach-Object { $_.globbing -eq 'false'} } } + + Context 'External help file metadata' { + BeforeAll { + Import-Module "$PSScriptRoot/assets/NestedMod" -Force + $nestedMd = New-MarkdownHelp -Module "NestedMod" -OutputFolder "$TestDrive\NestedMod" + } + + It 'checks the external help file metadata is correct for nested module' { + $m = Get-MarkdownMetadata -Path $nestedMd + $m['external help file'] | Should -BeExactly 'Nest.psm1-help.xml' + } + } } } @@ -723,6 +735,8 @@ Describe 'New-ExternalHelp' { } $file = New-MarkdownHelp -Command 'Test-OrderFunction' -OutputFolder $TestDrive -Force $maml = $file | New-ExternalHelp -OutputPath "$TestDrive\TestOrderFunction.xml" -Force + + $extHelp = New-ExternalHelp -Path "$PSScriptRoot/assets/ModuleWithDash" -OutputPath "$TestDrive\ModuleWithDash" } It "generates right order for syntax" { @@ -739,6 +753,10 @@ Describe 'New-ExternalHelp' { $xml = [xml] (Get-Content (Join-Path $TestDrive 'TestOrderFunction.xml')) $xml.helpItems.namespaceuri | Should Be 'http://msh' } + + It 'checks that external help can be generated for modules with dash in it' { + $extHelp | Should -Exist + } } Describe 'New-ExternalHelp -ErrorLogFile' { @@ -1612,4 +1630,11 @@ Describe 'New-YamlHelp' { It 'throws for OutputFolder that is a file'{ { New-YamlHelp "$root\docs\New-YamlHelp.md" -OutputFolder "$outFolder\yaml\New-YamlHelp.yml" } | Should Throw } + + It 'does not omit # in output type names' { + + $ymlFile = New-YamlHelp "$PSScriptRoot\assets\New-YamlHelp.md" -OutputFolder "$TestDrive\yaml" -Force + + Get-Content $ymlFile | Should -Contain '- type: IResult\#System.IO.FileInfo[]' + } } diff --git a/test/Pester/assets/ModuleWithDash/Test-Module.md b/test/Pester/assets/ModuleWithDash/Test-Module.md new file mode 100644 index 00000000..95810fd9 --- /dev/null +++ b/test/Pester/assets/ModuleWithDash/Test-Module.md @@ -0,0 +1,16 @@ +--- +Module Name: Test-Module +Module Guid: ad057547-0b77-49d0-b8dd-9ffd6d44b0be +Download Help Link: {{ Update Download Link }} +Help Version: {{ Please enter version of help manually (X.X.X.X) format }} +Locale: en-US +--- + +# Test-Module Module +## Description +{{ Fill in the Description }} + +## Test-Module Cmdlets +### [Test-ModuleCmdlet](Test-ModuleCmdlet.md) +{{ Fill in the Description }} + diff --git a/test/Pester/assets/ModuleWithDash/Test-ModuleCmdlet.md b/test/Pester/assets/ModuleWithDash/Test-ModuleCmdlet.md new file mode 100644 index 00000000..be9093db --- /dev/null +++ b/test/Pester/assets/ModuleWithDash/Test-ModuleCmdlet.md @@ -0,0 +1,46 @@ +--- +external help file: Test-Module-help.xml +Module Name: Test-Module +online version: +schema: 2.0.0 +title: Test-ModuleCmdlet +--- + +# Test-ModuleCmdlet + +## SYNOPSIS +{{ Fill in the Synopsis }} + +## SYNTAX + +``` +Test-ModuleCmdlet [] +``` + +## DESCRIPTION +{{ Fill in the Description }} + +## EXAMPLES + +### Example 1 +```powershell +PS C:\> {{ Add example code here }} +``` + +{{ Add example description here }} + +## PARAMETERS + +### CommonParameters +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). + +## INPUTS + +### None + +## OUTPUTS + +### System.Object +## NOTES + +## RELATED LINKS diff --git a/test/Pester/assets/NestedMod/Nest.psm1 b/test/Pester/assets/NestedMod/Nest.psm1 new file mode 100644 index 00000000..4d31bb9a --- /dev/null +++ b/test/Pester/assets/NestedMod/Nest.psm1 @@ -0,0 +1,7 @@ +function Get-Nest +{ + [CmdletBinding()] + param( + [Parameter()] [string] $str + ) +} \ No newline at end of file diff --git a/test/Pester/assets/NestedMod/NestedMod.psd1 b/test/Pester/assets/NestedMod/NestedMod.psd1 new file mode 100644 index 00000000..dcd2fbfb --- /dev/null +++ b/test/Pester/assets/NestedMod/NestedMod.psd1 @@ -0,0 +1,132 @@ +# +# Module manifest for module 'NestedMod' +# +# Generated by: adity +# +# Generated on: 6/28/2021 +# + +@{ + +# Script module or binary module file associated with this manifest. +# RootModule = '' + +# Version number of this module. +ModuleVersion = '0.0.1' + +# Supported PSEditions +# CompatiblePSEditions = @() + +# ID used to uniquely identify this module +GUID = '5aeb9dc7-b9f0-4bf2-8eb5-13663c1bd458' + +# Author of this module +Author = 'adity' + +# Company or vendor of this module +CompanyName = 'Unknown' + +# Copyright statement for this module +Copyright = '(c) adity. All rights reserved.' + +# Description of the functionality provided by this module +# Description = '' + +# Minimum version of the PowerShell engine required by this module +# PowerShellVersion = '' + +# Name of the PowerShell host required by this module +# PowerShellHostName = '' + +# Minimum version of the PowerShell host required by this module +# PowerShellHostVersion = '' + +# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. +# DotNetFrameworkVersion = '' + +# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. +# ClrVersion = '' + +# Processor architecture (None, X86, Amd64) required by this module +# ProcessorArchitecture = '' + +# Modules that must be imported into the global environment prior to importing this module +# RequiredModules = @() + +# Assemblies that must be loaded prior to importing this module +# RequiredAssemblies = @() + +# Script files (.ps1) that are run in the caller's environment prior to importing this module. +# ScriptsToProcess = @() + +# Type files (.ps1xml) to be loaded when importing this module +# TypesToProcess = @() + +# Format files (.ps1xml) to be loaded when importing this module +# FormatsToProcess = @() + +# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess +NestedModules = @('Nest.psm1') + +# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. +FunctionsToExport = 'Get-Nest' + +# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. +CmdletsToExport = '*' + +# Variables to export from this module +VariablesToExport = '*' + +# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. +AliasesToExport = '*' + +# DSC resources to export from this module +# DscResourcesToExport = @() + +# List of all modules packaged with this module +# ModuleList = @() + +# List of all files packaged with this module +# FileList = @() + +# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. +PrivateData = @{ + + PSData = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + # Tags = @() + + # A URL to the license for this module. + # LicenseUri = '' + + # A URL to the main website for this project. + # ProjectUri = '' + + # A URL to an icon representing this module. + # IconUri = '' + + # ReleaseNotes of this module + # ReleaseNotes = '' + + # Prerelease string of this module + # Prerelease = '' + + # Flag to indicate whether the module requires explicit user acceptance for install/update/save + # RequireLicenseAcceptance = $false + + # External dependent modules of this module + # ExternalModuleDependencies = @() + + } # End of PSData hashtable + +} # End of PrivateData hashtable + +# HelpInfo URI of this module +# HelpInfoURI = '' + +# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. +# DefaultCommandPrefix = '' + +} + diff --git a/test/Pester/assets/New-YamlHelp.md b/test/Pester/assets/New-YamlHelp.md new file mode 100644 index 00000000..b64e0c8d --- /dev/null +++ b/test/Pester/assets/New-YamlHelp.md @@ -0,0 +1,153 @@ +--- +external help file: platyPS-help.xml +Module Name: platyPS +online version: https://github.com/PowerShell/platyPS/blob/master/docs/New-YamlHelp.md +schema: 2.0.0 +--- + +# New-YamlHelp + +## SYNOPSIS +Converts Markdown help into YAML to be read easily by external tools + +## SYNTAX + +``` +New-YamlHelp [-Path] -OutputFolder [-Encoding ] [-Force] [] +``` + +## DESCRIPTION +The **New-YamlHelp** cmdlet works similarly to the **New-ExternalHelp** cmdlet but rather than creating a MAML file to support **Get-Help**, it creates a set of YAML files that can be read by external tools to provide custom rendering of help pages. + +## EXAMPLES + +### Example 1: Create YAML files +``` +PS C:\> New-YamlHelp -Path .\docs -OutputFolder .\out\yaml + + Directory: D:\Working\PlatyPS\out\yaml + + +Mode LastWriteTime Length Name +---- ------------- ------ ---- +-a---- 6/15/2017 11:13 AM 2337 Get-HelpPreview.yml +-a---- 6/15/2017 11:13 AM 3502 Get-MarkdownMetadata.yml +-a---- 6/15/2017 11:13 AM 4143 New-ExternalHelp.yml +-a---- 6/15/2017 11:13 AM 3082 New-ExternalHelpCab.yml +-a---- 6/15/2017 11:13 AM 2581 New-MarkdownAboutHelp.yml +-a---- 6/15/2017 11:13 AM 12356 New-MarkdownHelp.yml +-a---- 6/15/2017 11:13 AM 1681 New-YamlHelp.yml +-a---- 6/15/2017 11:13 AM 5053 Update-MarkdownHelp.yml +-a---- 6/15/2017 11:13 AM 4661 Update-MarkdownHelpModule.yml +-a---- 6/15/2017 11:13 AM 3350 Update-MarkdownHelpSchema.yml +``` + +This creates one YAML file for each cmdlet so external tools can read the structured data for each cmdlet. + +### Example 2: Create YAML files with specific encoding +``` +PS C:\> New-YamlHelp -Path .\docs -OutputFolder .\out\yaml -Force -Encoding ([System.Text.Encoding]::Unicode) + + Directory: D:\Working\PlatyPS\out\yaml + + +Mode LastWriteTime Length Name +---- ------------- ------ ---- +-a---- 6/15/2017 11:13 AM 2337 Get-HelpPreview.yml +-a---- 6/15/2017 11:13 AM 3502 Get-MarkdownMetadata.yml +-a---- 6/15/2017 11:13 AM 4143 New-ExternalHelp.yml +-a---- 6/15/2017 11:13 AM 3082 New-ExternalHelpCab.yml +-a---- 6/15/2017 11:13 AM 2581 New-MarkdownAboutHelp.yml +-a---- 6/15/2017 11:13 AM 12356 New-MarkdownHelp.yml +-a---- 6/15/2017 11:13 AM 1681 New-YamlHelp.yml +-a---- 6/15/2017 11:13 AM 5053 Update-MarkdownHelp.yml +-a---- 6/15/2017 11:13 AM 4661 Update-MarkdownHelpModule.yml +-a---- 6/15/2017 11:13 AM 3350 Update-MarkdownHelpSchema.yml +``` + +This will both read and write the files in the specified -Encoding. +The -Force parameter will overwrite files that already exist. + +## PARAMETERS + +### -Encoding +Specifies the character encoding for your external help file. +Specify a **System.Text.Encoding** object. +For more information, see [Character Encoding in the .NET Framework](https://msdn.microsoft.com/en-us/library/ms404377.aspx) in the Microsoft Developer Network. +For example, you can control Byte Order Mark (BOM) preferences. +For more information, see [Using PowerShell to write a file in UTF-8 without the BOM](http://stackoverflow.com/questions/5596982/using-powershell-to-write-a-file-in-utf-8-without-the-bom) at the Stack Overflow community. + +```yaml +Type: Encoding +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Force +Indicates that this cmdlet overwrites an existing file that has the same name. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Path +Specifies an array of paths of markdown files or folders. +This cmdlet creates external help based on these files and folders. + +```yaml +Type: String[] +Parameter Sets: (All) +Aliases: + +Required: True +Position: 1 +Default value: None +Accept pipeline input: True (ByPropertyName, ByValue) +Accept wildcard characters: False +``` + +### -OutputFolder +Specifies the folder to create the YAML files in + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: True +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### CommonParameters +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). + +## INPUTS + +### System.String[] +You can pipe an array of paths to this cmdlet. + +## OUTPUTS + +### IResult#System.IO.FileInfo[] +This cmdlet returns a **FileInfo[]** object for created files. + +## NOTES + +## RELATED LINKS