From 4010d372541c1b7b3a60077621718ed19ee5d8e7 Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Mon, 23 Dec 2019 19:24:44 +0100 Subject: [PATCH 01/29] refactor: UpdateMarkdownCodeBlocks.ps1 to SetMarkdownCodeBlockMoniker.ps1 --- ...MarkdownCodeBlocks.ps1 => SetMarkdownCodeBlockMoniker.ps1} | 4 ++-- Source/Public/New-DocusaurusHelp.ps1 | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename Source/Private/{UpdateMarkdownCodeBlocks.ps1 => SetMarkdownCodeBlockMoniker.ps1} (86%) diff --git a/Source/Private/UpdateMarkdownCodeBlocks.ps1 b/Source/Private/SetMarkdownCodeBlockMoniker.ps1 similarity index 86% rename from Source/Private/UpdateMarkdownCodeBlocks.ps1 rename to Source/Private/SetMarkdownCodeBlockMoniker.ps1 index 37056de7..a3b884da 100644 --- a/Source/Private/UpdateMarkdownCodeBlocks.ps1 +++ b/Source/Private/SetMarkdownCodeBlockMoniker.ps1 @@ -1,7 +1,7 @@ -function UpdateMarkdownCodeBlocks() { +function SetMarkdownCodeBlockMoniker() { <# .SYNOPSIS - Add `powershell` syntax highlighting to generated code blocks. + Add `powershell` moniker to generated code blocks for correct syntax highlighting. .NOTES 1. unfortunately we need to do this because PlatyPS does not add the language (design choice) diff --git a/Source/Public/New-DocusaurusHelp.ps1 b/Source/Public/New-DocusaurusHelp.ps1 index c548fd55..b88cf056 100644 --- a/Source/Public/New-DocusaurusHelp.ps1 +++ b/Source/Public/New-DocusaurusHelp.ps1 @@ -128,7 +128,7 @@ function New-DocusaurusHelp() { SetMarkdownFrontMatter @frontmatterArgs RemoveMarkdownHeaderOne -MarkdownFile $markdownFile - UpdateMarkdownCodeBlocks -MarkdownFile $markdownFile + SetMarkdownCodeBlockMoniker -MarkdownFile $markdownFile UpdateMarkdownBackticks -MarkdownFile $markdownFile # rename to .mdx From 6e795a16208facbe56047d97ed18e748803a930b Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Fri, 27 Dec 2019 15:31:25 +0100 Subject: [PATCH 02/29] feat: adds support for (code fencing) complex multl-line code examples --- Source/Private/RemoveMarkdownHeaderOne.ps1 | 2 +- Source/Private/ReplaceMarkdownCodeBlocks.ps1 | 102 ++++++++++++++++++ .../Private/SetMarkdownCodeBlockMoniker.ps1 | 9 +- Source/Private/SetMarkdownLineEndings.ps1 | 17 +++ Source/Public/New-DocusaurusHelp.ps1 | 3 + 5 files changed, 128 insertions(+), 5 deletions(-) create mode 100644 Source/Private/ReplaceMarkdownCodeBlocks.ps1 create mode 100644 Source/Private/SetMarkdownLineEndings.ps1 diff --git a/Source/Private/RemoveMarkdownHeaderOne.ps1 b/Source/Private/RemoveMarkdownHeaderOne.ps1 index f81deb29..62139466 100644 --- a/Source/Private/RemoveMarkdownHeaderOne.ps1 +++ b/Source/Private/RemoveMarkdownHeaderOne.ps1 @@ -9,7 +9,7 @@ function RemoveMarkdownHeaderOne() { $content = (Get-Content -Path $MarkdownFile.FullName -Raw).TrimEnd() - $regex = '\n#{1}\s.+\n\r' + $regex = '\n#{1}\s.+' $newContent = [regex]::replace($content, $regex, '') diff --git a/Source/Private/ReplaceMarkdownCodeBlocks.ps1 b/Source/Private/ReplaceMarkdownCodeBlocks.ps1 new file mode 100644 index 00000000..c36b8aee --- /dev/null +++ b/Source/Private/ReplaceMarkdownCodeBlocks.ps1 @@ -0,0 +1,102 @@ +function ReplaceMarkdownCodeBlocks() { + <# + .SYNOPSIS + Replace PlatyPS generated code blocks. + + .DESCRIPTION + Replaces custom fenced code blocks and placeholder examples, otherwise uses PlatyPS generated defaults. + + See link below for a detailed description of the determination process. + + .LINK + https://github.com/alt3/Docusaurus.Powershell/issues/14#issuecomment-568552556 + #> + param( + [Parameter(Mandatory = $True)][System.IO.FileSystemInfo]$MarkdownFile + ) + + $content = (Get-Content -Path $MarkdownFile.FullName -Raw).TrimEnd() + [string]$newExamples = "" + + # --------------------------------------------------------------------- + # extract all EXAMPLE nodes + # https://regex101.com/r/y4UxP8/2 + # --------------------------------------------------------------------- + $regexExtractExamples = [regex]::new('### (EXAMPLE|Example) [0-9][\s\S]*?(?=\n.*?#|$)') + $examples = $regexExtractExamples.Matches($content) + + # process each EXAMPLE node + $examples | ForEach-Object { + $example = $_ + + # --------------------------------------------------------------------- + # do not modify if it's a PlatyPS placeholder example + # https://regex101.com/r/WOQL0l/4 + # --------------------------------------------------------------------- + $regexPlatyPlaceholderExample = [regex]::new('{{ Add example code here }}') + if ($regexPlatyPlaceholderExample.Matches($example)) { + $newExamples += $example + return + } + + # --------------------------------------------------------------------- + # Powershell 6: re-construct custom code-fenced example + # https://regex101.com/r/lHdZHM/2/ => code block with description + # https://regex101.com/r/0a44Tn/2/ => code block without description + # --------------------------------------------------------------------- + $regexCodeFencePowershell6 = [regex]::new('(### EXAMPLE [0-9])\n(```\n(```|```posh|```powershell)\n```\n)\n([\s\S]*?\\`\\`\\`)\n([\s\S]*|\n)') + + if ($example -match $regexCodeFencePowershell6) { + $header = $matches[1] + $code = $matches[4] + $description = $matches[5] + + $example = "$header`n" + '```' + "`n$code`n$description`n" + $newExamples += $example + return + } + + # --------------------------------------------------------------------- + # Powershell 7: re-construct custom code-fenced example + # https://regex101.com/r/oXsGLw/1/ => code block with description + # https://regex101.com/r/Yd1lXR/1/ => code block without description + # --------------------------------------------------------------------- + $regexCodeFencePowershell7 = [regex]::new('(### EXAMPLE [0-9])\n(```\n(```|```posh|```powershell)\n)([\s\S]*?)```\n([\s\S]*?\\`\\`\\`)\n([\s\S]*|\n)') + + if ($example -match $regexCodeFencePowershell7) { + $header = $matches[1] + $codeblock1 = $matches[4] + $codeblock2 = $matches[5] + $description = $matches[6] + + $example = "$header`n" + '```' + "`n$($codeblock1)$($codeblock2)`n$description`n" + $newExamples += $example + return + } + + # --------------------------------------------------------------------- + # no matches so we follow the Comment Based Help standard and thus use + # PlatyPS generated code block. This regex will detect both single- + # line and multi-line code examples and has support for Powershell v7. + # --------------------------------------------------------------------- + $regexDefaultCodeBlocks = [regex]::new('(### EXAMPLE [0-9])\n```\n([\s\S]*)```\n(([\s\S]*|\n|))?(?=\n.*?#|$)') + + if ($example -match $regexDefaultCodeBlocks) { + $newExamples += "$example`n" + return + } + + # we should never reach this point + write-warning "Unsupported code block detected, please file an issue at https://github.com/alt3/Docusaurus.Powershell/issues" + } + + # replace EXAMPLES section in content with updated examples + # https://regex101.com/r/8OEW0w/1/ + $regex = '## EXAMPLES\n[\s\S]+## PARAMETERS' + $replacement = "## EXAMPLES`n`n$($newExamples)## PARAMETERS" + $content = [regex]::replace($content, $regex, $replacement) + + # replace file (UTF-8 without BOM) + $fileEncoding = New-Object System.Text.UTF8Encoding $False + [System.IO.File]::WriteAllLines($markdownFile.FullName, $content, $fileEncoding) +} diff --git a/Source/Private/SetMarkdownCodeBlockMoniker.ps1 b/Source/Private/SetMarkdownCodeBlockMoniker.ps1 index a3b884da..83f94026 100644 --- a/Source/Private/SetMarkdownCodeBlockMoniker.ps1 +++ b/Source/Private/SetMarkdownCodeBlockMoniker.ps1 @@ -13,12 +13,13 @@ function SetMarkdownCodeBlockMoniker() { $content = (Get-Content -Path $MarkdownFile.FullName -Raw).TrimEnd() - # this regex replaces all code blocks without a language (test on https://regex101.com using /$regex/g) - $regex = '(```)\r((?:(?!```)[\s\S])+)(```)\r' + # this regex replaces all opening code fences without a language moniker with "```powershell" + # https://regex101.com/r/AYzALd/1 + $regex = '(```)\n((?:(?!```)[\s\S])+)(```)\n' - $newContent = [regex]::replace($content, $regex, '```powershell$2```') + $content = [regex]::replace($content, $regex, '```powershell' + "`n" + '$2```' + "`n") # replace file (UTF-8 without BOM) $fileEncoding = New-Object System.Text.UTF8Encoding $False - [System.IO.File]::WriteAllLines($markdownFile.FullName, $newContent, $fileEncoding) + [System.IO.File]::WriteAllLines($markdownFile.FullName, $content, $fileEncoding) } diff --git a/Source/Private/SetMarkdownLineEndings.ps1 b/Source/Private/SetMarkdownLineEndings.ps1 new file mode 100644 index 00000000..77bac59a --- /dev/null +++ b/Source/Private/SetMarkdownLineEndings.ps1 @@ -0,0 +1,17 @@ +function SetMarkdownLineEndings() { + <# + .SYNOPSIS + Replaces all CRLF line endings with LF so we can consitently use/expect `n when regexing etc. + #> + param( + [Parameter(Mandatory = $True)][System.IO.FileSystemInfo]$MarkdownFile + ) + + $content = (Get-Content -Path $MarkdownFile.FullName -Raw).TrimEnd() + + $content = $content -replace "`r`n", "`n" + + # replace file (UTF-8 without BOM) + $fileEncoding = New-Object System.Text.UTF8Encoding $False + [System.IO.File]::WriteAllLines($markdownFile.FullName, $content, $fileEncoding) +} diff --git a/Source/Public/New-DocusaurusHelp.ps1 b/Source/Public/New-DocusaurusHelp.ps1 index b88cf056..ed84b0b4 100644 --- a/Source/Public/New-DocusaurusHelp.ps1 +++ b/Source/Public/New-DocusaurusHelp.ps1 @@ -115,6 +115,8 @@ function New-DocusaurusHelp() { # update generated markdown file(s) to make them Docusaurus compatible ForEach ($markdownFile in $markdownFiles) { + SetMarkdownLineEndings -MarkdownFile $markdownFile + $customEditUrl = GetCustomEditUrl -Module $Module -MarkdownFile $markdownFile -EditUrl $EditUrl -Monolithic:$Monolithic $frontMatterArgs = @{ @@ -128,6 +130,7 @@ function New-DocusaurusHelp() { SetMarkdownFrontMatter @frontmatterArgs RemoveMarkdownHeaderOne -MarkdownFile $markdownFile + ReplaceMarkdownCodeBlocks -MarkdownFile $markdownFile SetMarkdownCodeBlockMoniker -MarkdownFile $markdownFile UpdateMarkdownBackticks -MarkdownFile $markdownFile From d5bd980d269ff64b271f2f3b3ba365f17190e114 Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Fri, 27 Dec 2019 17:05:15 +0100 Subject: [PATCH 03/29] docs: describe multi-line-examples --- docusaurus/docs/faq/multi-line-examples.md | 92 ++++++++++++++++++++++ docusaurus/sidebars.js | 1 + 2 files changed, 93 insertions(+) create mode 100644 docusaurus/docs/faq/multi-line-examples.md diff --git a/docusaurus/docs/faq/multi-line-examples.md b/docusaurus/docs/faq/multi-line-examples.md new file mode 100644 index 00000000..ff4380b5 --- /dev/null +++ b/docusaurus/docs/faq/multi-line-examples.md @@ -0,0 +1,92 @@ +--- +id: multi-line-examples +title: Multi-Line Examples +sidebar_label: Multi-Line Examples +--- + +Powershell's Comment Based Help was originally designed for `.EXAMPLE` nodes containing: + +- (only) a **single-line command** +- followed by the command's output and/or a description + +``` +.EXAMPLE + + Get-RealName -NickName "SomeNick" + + Yasmine +``` + +## Code Fence Detection + +Unfortunately these single-line examples no longer suffice as authors are now creating advanced functions +which require **complex multi-lined code examples** to properly inform their end-users. Because Microsoft +does not (and cannot) support these use-cases, Docusaurus comes with `Code Fence Detection`, +allowing you to use common markdown code fences to indicate where your example code block +starts and where it ends. + +A simple example would look similar to: + +``` +.EXAMPLE + ```powershell + $description = 'Code Fenced example with a description' + $names | Foreach-Object {} { + Write-Host 'Indentation and empty newlines within the fenced code block will be respected' + } + + $multipleNewlinesInCode = $True + ``` + + Your description would start here and: + + - is treated as markdown + - can also contain fenced code blocks +``` + +Where you can use any of the following commonly used opening fences: + +- \`\`\` +- \`\`\`powershell +- \`\`\`posh + +## Powershell 7 + +Even though Powershell 7 ships with native support for multi-line code it only +does so in a limited form as can be seen in this example: + +``` +.EXAMPLE + $description = 'Powershell 7+ multi-line example with a description' + $description = 'ONLY Powershell 7 will consider all adjacent first lines to be code' + $description = 'Code block ends (and description begins) at the first two newlines` + + Powershell 7 will use this line, and everything below it, as the description +``` + +**You could use this native form instead of Code Fence Detection if:** + +- you are using Powershell 7 +- your example code does not contain any empty newlines + +## Default Fallback + +Docusuarus.Powershell will fall back to using the unaltered PlatyPS generated code blocks +if code fencing is not detected. + +This is intentional behavior and is done because: + +- it would be impossible to "guess" where the code ends and the description begins +- we can redirect (and fix) bugs in the right place (PlatyPS repository) +- it will automatically support the multi-line examples that ships with Powershell 7 + +## Unexpected Results + +If your example code is not being rendered as expected please make sure to understand why it is +not being recognized as multi-line code before creating an issue or pull request. Most likely, +updating your help to use Code Fence Detection would be the better alternative. + +## Additional Information + +- [Detailed description of the Docusaurus.Powershell determination process](https://github.com/alt3/Docusaurus.Powershell/issues/14#issuecomment-568552556) +- [Confirmation of Powershell 7 native multi-line code](https://github.com/PowerShell/platyPS/issues/180#issuecomment-568877700) diff --git a/docusaurus/sidebars.js b/docusaurus/sidebars.js index a9118abb..ce3fda16 100644 --- a/docusaurus/sidebars.js +++ b/docusaurus/sidebars.js @@ -16,6 +16,7 @@ module.exports = { 'F.A.Q.': [ 'faq/multiple-modules', 'faq/monolithic-modules', + 'faq/multi-line-examples', 'faq/search', 'faq/ci-cd', ], From ca40d4cca28e02f30f7f90a9ddaaf8b50954fefa Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Fri, 27 Dec 2019 17:32:34 +0100 Subject: [PATCH 04/29] feat: add support for ```ps as an opening code fence --- Source/Private/ReplaceMarkdownCodeBlocks.ps1 | 4 ++-- docusaurus/docs/faq/multi-line-examples.md | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Source/Private/ReplaceMarkdownCodeBlocks.ps1 b/Source/Private/ReplaceMarkdownCodeBlocks.ps1 index c36b8aee..9ce3dd99 100644 --- a/Source/Private/ReplaceMarkdownCodeBlocks.ps1 +++ b/Source/Private/ReplaceMarkdownCodeBlocks.ps1 @@ -44,7 +44,7 @@ function ReplaceMarkdownCodeBlocks() { # https://regex101.com/r/lHdZHM/2/ => code block with description # https://regex101.com/r/0a44Tn/2/ => code block without description # --------------------------------------------------------------------- - $regexCodeFencePowershell6 = [regex]::new('(### EXAMPLE [0-9])\n(```\n(```|```posh|```powershell)\n```\n)\n([\s\S]*?\\`\\`\\`)\n([\s\S]*|\n)') + $regexCodeFencePowershell6 = [regex]::new('(### EXAMPLE [0-9])\n(```\n(```|```ps|```posh|```powershell)\n```\n)\n([\s\S]*?\\`\\`\\`)\n([\s\S]*|\n)') if ($example -match $regexCodeFencePowershell6) { $header = $matches[1] @@ -61,7 +61,7 @@ function ReplaceMarkdownCodeBlocks() { # https://regex101.com/r/oXsGLw/1/ => code block with description # https://regex101.com/r/Yd1lXR/1/ => code block without description # --------------------------------------------------------------------- - $regexCodeFencePowershell7 = [regex]::new('(### EXAMPLE [0-9])\n(```\n(```|```posh|```powershell)\n)([\s\S]*?)```\n([\s\S]*?\\`\\`\\`)\n([\s\S]*|\n)') + $regexCodeFencePowershell7 = [regex]::new('(### EXAMPLE [0-9])\n(```\n(```|```ps|```posh|```powershell)\n)([\s\S]*?\\`\\`\\`)\n([\s\S]*|\n)') if ($example -match $regexCodeFencePowershell7) { $header = $matches[1] diff --git a/docusaurus/docs/faq/multi-line-examples.md b/docusaurus/docs/faq/multi-line-examples.md index ff4380b5..d5af3e93 100644 --- a/docusaurus/docs/faq/multi-line-examples.md +++ b/docusaurus/docs/faq/multi-line-examples.md @@ -49,6 +49,7 @@ Where you can use any of the following commonly used opening fences: - \`\`\` - \`\`\`powershell - \`\`\`posh +- \`\`\`ps ## Powershell 7 From 62028904838bef4dc55309e6428973c23011f5fd Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Sat, 28 Dec 2019 11:52:50 +0100 Subject: [PATCH 05/29] test: move unit tests to /Tests/Unit --- Tests/{ => Unit}/Private/GetCustomEditUrl.Tests.ps1 | 6 +++++- Tests/{ => Unit}/Private/GetMdxFilePath.Tests.ps1 | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) rename Tests/{ => Unit}/Private/GetCustomEditUrl.Tests.ps1 (94%) rename Tests/{ => Unit}/Private/GetMdxFilePath.Tests.ps1 (87%) diff --git a/Tests/Private/GetCustomEditUrl.Tests.ps1 b/Tests/Unit/Private/GetCustomEditUrl.Tests.ps1 similarity index 94% rename from Tests/Private/GetCustomEditUrl.Tests.ps1 rename to Tests/Unit/Private/GetCustomEditUrl.Tests.ps1 index c9ad6b7d..91de25c0 100644 --- a/Tests/Private/GetCustomEditUrl.Tests.ps1 +++ b/Tests/Unit/Private/GetCustomEditUrl.Tests.ps1 @@ -1,5 +1,9 @@ Describe "Private$([IO.Path]::DirectorySeparatorChar)GetCustomEditUrl" { - Import-Module Alt3.Docusaurus.Powershell -DisableNameChecking -Verbose:$False + if (-not(Get-Module Alt3.Docusaurus.Powershell)) { + write-host "module not loaded" -ForegroundColor yellow + break + Import-Module Alt3.Docusaurus.Powershell -DisableNameChecking -Verbose:$False + } # up $markdownFilePath = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath 'Dummy-PesterCommand.md' diff --git a/Tests/Private/GetMdxFilePath.Tests.ps1 b/Tests/Unit/Private/GetMdxFilePath.Tests.ps1 similarity index 87% rename from Tests/Private/GetMdxFilePath.Tests.ps1 rename to Tests/Unit/Private/GetMdxFilePath.Tests.ps1 index c7e12a43..f02106d3 100644 --- a/Tests/Private/GetMdxFilePath.Tests.ps1 +++ b/Tests/Unit/Private/GetMdxFilePath.Tests.ps1 @@ -1,5 +1,7 @@ Describe "Private$([IO.Path]::DirectorySeparatorChar)GetMdxFilePath" { - Import-Module Alt3.Docusaurus.Powershell -DisableNameChecking -Verbose:$False + if (-not(Get-Module Alt3.Docusaurus.Powershell)) { + Import-Module Alt3.Docusaurus.Powershell -DisableNameChecking -Verbose:$False + } # up $markdownFilePath = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath 'pester-markdown.md' From 1505f71ff0f92079427876844b0bd8ff9a20fcef Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Sat, 28 Dec 2019 11:53:45 +0100 Subject: [PATCH 06/29] chore: remove orphaned gitkeep file from tests directory --- Tests/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Tests/.gitkeep diff --git a/Tests/.gitkeep b/Tests/.gitkeep deleted file mode 100644 index e69de29b..00000000 From f1d4eafb475648c3a995c1ad50d2dbd24dce5b64 Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Sat, 28 Dec 2019 11:56:15 +0100 Subject: [PATCH 07/29] test: Powershell 7's native support for Multi-Line Code Examples --- .../Powershell7NativeMultiLineCode.Tests.ps1 | 48 +++++++++++++++ ...owershell7NativeMultiLineCode.expected.mdx | 58 +++++++++++++++++++ .../Powershell7NativeMultiLineCode.psm1 | 30 ++++++++++ 3 files changed, 136 insertions(+) create mode 100644 Tests/Integration/Powershell7NativeMultiLineCode.Tests.ps1 create mode 100644 Tests/Integration/Powershell7NativeMultiLineCode.expected.mdx create mode 100644 Tests/Integration/Powershell7NativeMultiLineCode.psm1 diff --git a/Tests/Integration/Powershell7NativeMultiLineCode.Tests.ps1 b/Tests/Integration/Powershell7NativeMultiLineCode.Tests.ps1 new file mode 100644 index 00000000..11ada89e --- /dev/null +++ b/Tests/Integration/Powershell7NativeMultiLineCode.Tests.ps1 @@ -0,0 +1,48 @@ +<# + .SYNOPSIS + This test ensures Powershell 7 native multi-line code examples render as expected. +#> + +# ----------------------------------------------------------------------------- +# skip test on Powershell 6 and lower +# ----------------------------------------------------------------------------- +if ($PSVersionTable.PSVersion.Major -lt 7) { + Write-Host "[+] skipping test because Powershell 6 or lower" -ForegroundColor magenta + return +} + +# ----------------------------------------------------------------------------- +# import the Alt3.Docusaurus.Powershell rendering module +# ----------------------------------------------------------------------------- +if (-not(Get-Module Alt3.Docusaurus.Powershell)) { + Import-Module Alt3.Docusaurus.Powershell -DisableNameChecking -Verbose:$False -Scope Global +} + +# ----------------------------------------------------------------------------- +# import the test module associated with this test +# ----------------------------------------------------------------------------- +${global:testModuleName} = [regex]::replace([System.IO.Path]::GetFileName($PSCommandPath), '.Tests.ps1', '') +${global:testModulePath} = Join-Path -Path $PSScriptRoot -ChildPath "${global:testModuleName}.psm1" +Import-Module ${global:testModulePath} -Force -DisableNameChecking -Verbose:$False -Scope Global + +# ----------------------------------------------------------------------------- +# the actual integration test +# ----------------------------------------------------------------------------- +Describe "Integration Test for Powershell 7" { + Context "for Native Multi-Line Code Support" { + # render the markdown + ${global:outputFolder} = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ${global:testModuleName} + InModuleScope Alt3.Docusaurus.Powershell { + New-DocusaurusHelp -Module ${global:testModulePath} -OutputFolder ${global:outputFolder} + } + + # read markdown + $renderedMdx = Get-Content (Join-Path -Path ${global:outputFolder} -ChildPath "commands" | Join-Path -ChildPath "Test-$(${global:testModuleName}).mdx") + $expectedMdx = Get-Content (Join-Path -Path $PSScriptRoot -ChildPath "$(${global:testModuleName}).expected.mdx") + + # make sure output is identical + It "generates markdown that is identical to the markdown found in our static 'expected' mdx file" { + $renderedMdx | Should -BeExactly $expectedMdx + } + } +} diff --git a/Tests/Integration/Powershell7NativeMultiLineCode.expected.mdx b/Tests/Integration/Powershell7NativeMultiLineCode.expected.mdx new file mode 100644 index 00000000..ab33e46f --- /dev/null +++ b/Tests/Integration/Powershell7NativeMultiLineCode.expected.mdx @@ -0,0 +1,58 @@ +--- +id: Test-Powershell7NativeMultiLineCode +title: Test-Powershell7NativeMultiLineCode +hide_title: false +hide_table_of_contents: false +--- + +## SYNOPSIS +Dummy module to test Powershell 7 NATIVE multi-line code examples + +## SYNTAX + +```powershell +Test-Powershell7NativeMultiLineCode +``` + +## DESCRIPTION +{{ Fill in the Description }} + +## EXAMPLES + +### EXAMPLE 1 +```powershell +$description = 'Powershell 7+ multi-line example WITHOUT a description' + $respecsIndentation = $True +``` + +### EXAMPLE 2 +```powershell +$description = 'Powershell 7+ multi-line example WITH a single-description' + $respecsIndentation = $True +``` + +Powershell 7 will use this line, and everything below it, as the description + +### EXAMPLE 3 +```powershell +$description = 'Powershell 7+ multi-line example WITH a multi-line escription' + $respecsIndentation = $True +``` + +Powershell 7 will use this line, and everything below it, as the description + +This is the second description line + +## PARAMETERS + +## INPUTS + +## OUTPUTS + +## NOTES + +## RELATED LINKS + +[https://github.com/PowerShell/platyPS/issues/180#issuecomment-568877700](https://github.com/PowerShell/platyPS/issues/180#issuecomment-568877700) + +[https://github.com/PowerShell/PowerShell/pull/10776](https://github.com/PowerShell/PowerShell/pull/10776) diff --git a/Tests/Integration/Powershell7NativeMultiLineCode.psm1 b/Tests/Integration/Powershell7NativeMultiLineCode.psm1 new file mode 100644 index 00000000..d8e3ce9e --- /dev/null +++ b/Tests/Integration/Powershell7NativeMultiLineCode.psm1 @@ -0,0 +1,30 @@ +function Test-Powershell7NativeMultiLineCode { +<# + .SYNOPSIS + Dummy module to test Powershell 7 NATIVE multi-line code examples + + .LINK + https://github.com/PowerShell/platyPS/issues/180#issuecomment-568877700 + + .LINK + https://github.com/PowerShell/PowerShell/pull/10776 + + .EXAMPLE + $description = 'Powershell 7+ multi-line example WITHOUT a description' + $respecsIndentation = $True + + .EXAMPLE + $description = 'Powershell 7+ multi-line example WITH a single-description' + $respecsIndentation = $True + + Powershell 7 will use this line, and everything below it, as the description + + .EXAMPLE + $description = 'Powershell 7+ multi-line example WITH a multi-line escription' + $respecsIndentation = $True + + Powershell 7 will use this line, and everything below it, as the description + + This is the second description line +#> +} From bdf4870e6d4eeaa9ddff6b67e761e77152a9b38c Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Sat, 28 Dec 2019 19:55:28 +0100 Subject: [PATCH 08/29] test: all supported Get-Help example variants against Powershell 6 and lower --- Source/Private/NewMarkdownExample.ps1 | 24 +++ Source/Private/ReplaceMarkdownCodeBlocks.ps1 | 38 ++-- .../AllVersionsCodeExamples.Tests.ps1 | 39 ++++ .../AllVersionsCodeExamples.expected.mdx | 172 ++++++++++++++++++ .../Integration/AllVersionsCodeExamples.psm1 | 140 ++++++++++++++ 5 files changed, 386 insertions(+), 27 deletions(-) create mode 100644 Source/Private/NewMarkdownExample.ps1 create mode 100644 Tests/Integration/AllVersionsCodeExamples.Tests.ps1 create mode 100644 Tests/Integration/AllVersionsCodeExamples.expected.mdx create mode 100644 Tests/Integration/AllVersionsCodeExamples.psm1 diff --git a/Source/Private/NewMarkdownExample.ps1 b/Source/Private/NewMarkdownExample.ps1 new file mode 100644 index 00000000..0091aeeb --- /dev/null +++ b/Source/Private/NewMarkdownExample.ps1 @@ -0,0 +1,24 @@ +function NewMarkdownExample() { + <# + .SYNOPSIS + Generates a new markdown example block. + #> + param( + [Parameter(Mandatory = $True)][string]$Header, + [Parameter(Mandatory = $True)][string]$Code, + [Parameter(Mandatory = $False)][string]$Description = $null + ) + + $example = "$Header`n" + $example += '```' + "`n" + $example += $Code + $example += '```' + "`n" + + if ([string]::IsNullOrEmpty($Description)) { + $example += "`n" + } else { + $example += "`n$Description`n" + } + + return $example +} diff --git a/Source/Private/ReplaceMarkdownCodeBlocks.ps1 b/Source/Private/ReplaceMarkdownCodeBlocks.ps1 index 9ce3dd99..28209da5 100644 --- a/Source/Private/ReplaceMarkdownCodeBlocks.ps1 +++ b/Source/Private/ReplaceMarkdownCodeBlocks.ps1 @@ -40,37 +40,21 @@ function ReplaceMarkdownCodeBlocks() { } # --------------------------------------------------------------------- - # Powershell 6: re-construct custom code-fenced example - # https://regex101.com/r/lHdZHM/2/ => code block with description - # https://regex101.com/r/0a44Tn/2/ => code block without description + # Powershell 6: re-construct Code Fenced example + # - https://regex101.com/r/lHdZHM/6 => code block without a description + # - https://regex101.com/r/CGjQco/3 => code block with a description # --------------------------------------------------------------------- - $regexCodeFencePowershell6 = [regex]::new('(### EXAMPLE [0-9])\n(```\n(```|```ps|```posh|```powershell)\n```\n)\n([\s\S]*?\\`\\`\\`)\n([\s\S]*|\n)') + $regexPowershell6CodeFences = [regex]::new('(### EXAMPLE ([0-9|[0-9]+))\n(```\n(```|```ps|```posh|```powershell)\n```\n)\n([\s\S]*?)\\`\\`\\`(\n\n|\n)([\s\S]*|\n)') - if ($example -match $regexCodeFencePowershell6) { + if ($example -match $regexPowershell6CodeFences) { $header = $matches[1] - $code = $matches[4] - $description = $matches[5] + $code = $matches[5] + $description = $matches[7] - $example = "$header`n" + '```' + "`n$code`n$description`n" - $newExamples += $example - return - } + Write-Verbose "=> $($header): applying Powershell 6 Code Fencing Detection" - # --------------------------------------------------------------------- - # Powershell 7: re-construct custom code-fenced example - # https://regex101.com/r/oXsGLw/1/ => code block with description - # https://regex101.com/r/Yd1lXR/1/ => code block without description - # --------------------------------------------------------------------- - $regexCodeFencePowershell7 = [regex]::new('(### EXAMPLE [0-9])\n(```\n(```|```ps|```posh|```powershell)\n)([\s\S]*?\\`\\`\\`)\n([\s\S]*|\n)') - - if ($example -match $regexCodeFencePowershell7) { - $header = $matches[1] - $codeblock1 = $matches[4] - $codeblock2 = $matches[5] - $description = $matches[6] - - $example = "$header`n" + '```' + "`n$($codeblock1)$($codeblock2)`n$description`n" - $newExamples += $example + $newExample = NewMarkdownExample -Header $header -Code $code -Description $description + $newExamples += $newExample return } @@ -87,7 +71,7 @@ function ReplaceMarkdownCodeBlocks() { } # we should never reach this point - write-warning "Unsupported code block detected, please file an issue at https://github.com/alt3/Docusaurus.Powershell/issues" + Write-Warning "Unsupported code block detected, please file an issue at https://github.com/alt3/Docusaurus.Powershell/issues" } # replace EXAMPLES section in content with updated examples diff --git a/Tests/Integration/AllVersionsCodeExamples.Tests.ps1 b/Tests/Integration/AllVersionsCodeExamples.Tests.ps1 new file mode 100644 index 00000000..826ac82f --- /dev/null +++ b/Tests/Integration/AllVersionsCodeExamples.Tests.ps1 @@ -0,0 +1,39 @@ +<# + .SYNOPSIS + This test ensures that ALL Powershell versions render the code examples as expected. +#> + +# ----------------------------------------------------------------------------- +# import the Alt3.Docusaurus.Powershell rendering module +# ----------------------------------------------------------------------------- +if (-not(Get-Module Alt3.Docusaurus.Powershell)) { + Import-Module Alt3.Docusaurus.Powershell -DisableNameChecking -Verbose:$False -Scope Global +} + +# ----------------------------------------------------------------------------- +# import the test module associated with this test +# ----------------------------------------------------------------------------- +${global:testModuleName} = [regex]::replace([System.IO.Path]::GetFileName($PSCommandPath), '.Tests.ps1', '') +${global:testModulePath} = Join-Path -Path $PSScriptRoot -ChildPath "${global:testModuleName}.psm1" +Import-Module ${global:testModulePath} -Force -DisableNameChecking -Verbose:$False -Scope Global + +# ----------------------------------------------------------------------------- +# the actual integration test +# ----------------------------------------------------------------------------- +Describe "Integration Test to ensure all supported Code Example variants render identically on all Powershell versions" { + + # render the markdown + ${global:outputFolder} = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ${global:testModuleName} + InModuleScope Alt3.Docusaurus.Powershell { + New-DocusaurusHelp -Module ${global:testModulePath} -OutputFolder ${global:outputFolder} -Verbose + } + + # read markdown + $renderedMdx = Get-Content (Join-Path -Path ${global:outputFolder} -ChildPath "commands" | Join-Path -ChildPath "Test-$(${global:testModuleName}).mdx") + $expectedMdx = Get-Content (Join-Path -Path $PSScriptRoot -ChildPath "$(${global:testModuleName}).expected.mdx") + + # make sure output is identical + It "generates markdown that is identical to the markdown found in our static 'expected' mdx file" { + $renderedMdx | Should -BeExactly $expectedMdx + } +} diff --git a/Tests/Integration/AllVersionsCodeExamples.expected.mdx b/Tests/Integration/AllVersionsCodeExamples.expected.mdx new file mode 100644 index 00000000..f6ff5c63 --- /dev/null +++ b/Tests/Integration/AllVersionsCodeExamples.expected.mdx @@ -0,0 +1,172 @@ +--- +id: Test-AllVersionsCodeExamples +title: Test-AllVersionsCodeExamples +hide_title: false +hide_table_of_contents: false +--- + +## SYNOPSIS +Dummy module to ensure all supported Get-Help example variations render identically on all Powershell versions. + +## SYNTAX + +```powershell +Test-AllVersionsCodeExamples +``` + +## DESCRIPTION +{{ Fill in the Description }} + +## EXAMPLES + +### EXAMPLE 1 +```powershell +$description = 'Native single-line example without description' +``` + +### EXAMPLE 2 +```powershell +$description = 'Native single-line example with single-line description' +``` + +This is description line 1 + +### EXAMPLE 3 +```powershell +$description = 'Native single-line example with non-adjacent multi-line description' +``` + +This is description line 1 + +This is description line 2 + +### EXAMPLE 4 +```powershell +$description = 'Native single-line example with adjacent multi-line description' +``` + +This is description line 1 +This is description line 2 + +### EXAMPLE 5 +```powershell +$description = 'Code-fenced single-line example without description' +``` + +### EXAMPLE 6 +```powershell +$description = 'Code-fenced single-line example with single-line description' +``` + +This is description line 1 + +### EXAMPLE 7 +```powershell +$description = 'Code-fenced single-line example with non-adjacent multi-line description' +``` + +This is description line 1 + +This is description line 2 + +### EXAMPLE 8 +```powershell +$description = 'Code-fenced single-line example with adjacent multi-line description' +``` + +This is description line 1 +This is description line 2 + +### EXAMPLE 9 +```powershell +$description = 'Complex code-fenced example without description' +$names | Foreach-Object {} { + write-host 'indentation is respected' + Write-Host 'enormously long lines will not get cut off by our PlatyPS friends, ftw' +} + +$multipleNewlinesInCode = $True +``` + +### EXAMPLE 10 +```powershell +$description = 'Complex code-fenced example with a complex markdown description' +$names | Foreach-Object {} { + write-host 'indentation is respected' + Write-Host 'enormously long lines should not get cut off by our PlatyPS friends, ftw' +} + +$multipleNewlinesInCode = $True +``` + +The description would continue after first closing code fence. + +This solution: + +- respects indentation +- will treat description as markdown +- seems close to what comes natural + +With this solution, the description itself could even contain code blocks: + +```js +$var = docusaurus.New($config); +``` + +Pretty cool and one could argue that the console becomes more readable too +as you can now at least see where the code ends and the explanation begins + +``` +$unMonicked = "this code block should stay unmonicked, in other words powershell should not be added" + $indentationRespected = $True +$theBadNews - "that PlatyPS seems to cut off this line if a . +is detected, wtf" +``` + +### EXAMPLE 11 +```powershell +$description = 'Code-fenced single line example using POWERSHELL MONIKER without description' +``` + +### EXAMPLE 12 +```powershell +$description = 'Code-fenced single line example using POWERSHELL MONIKER with single-line description' +``` + +This is description line 1 + +### EXAMPLE 13 +```powershell +$description = 'Code-fenced single line example using POSH MONIKER without description' +``` + +### EXAMPLE 14 +```powershell +$description = 'Code-fenced single line example using POSH MONIKER with single-line description' +``` + +This is description line 1 + +### EXAMPLE 15 +```powershell +$description = 'Code-fenced single line example using PS MONIKER without description' +``` + +### EXAMPLE 16 +```powershell +$description = 'Code-fenced single line example using PS MONIKER with single-line description' +``` + +This is description line 1 + +## PARAMETERS + +## INPUTS + +## OUTPUTS + +## NOTES + +## RELATED LINKS + +[https://github.com/alt3/Docusaurus.Powershell/issues/14#issuecomment-568552556](https://github.com/alt3/Docusaurus.Powershell/issues/14#issuecomment-568552556) diff --git a/Tests/Integration/AllVersionsCodeExamples.psm1 b/Tests/Integration/AllVersionsCodeExamples.psm1 new file mode 100644 index 00000000..759806d4 --- /dev/null +++ b/Tests/Integration/AllVersionsCodeExamples.psm1 @@ -0,0 +1,140 @@ +function Test-AllVersionsCodeExamples { +<# + .SYNOPSIS + Dummy module to ensure all supported Get-Help example variations render identically on all Powershell versions. + + .LINK + https://github.com/alt3/Docusaurus.Powershell/issues/14#issuecomment-568552556 + + .EXAMPLE + $description = 'Native single-line example without description' + + .EXAMPLE + $description = 'Native single-line example with single-line description' + + This is description line 1 + + .EXAMPLE + $description = 'Native single-line example with non-adjacent multi-line description' + + This is description line 1 + + This is description line 2 + + .EXAMPLE + $description = 'Native single-line example with adjacent multi-line description' + + This is description line 1 + This is description line 2 + + .EXAMPLE + ``` + $description = 'Code-fenced single-line example without description' + ``` + + .EXAMPLE + ``` + $description = 'Code-fenced single-line example with single-line description' + ``` + + This is description line 1 + + .EXAMPLE + ``` + $description = 'Code-fenced single-line example with non-adjacent multi-line description' + ``` + + This is description line 1 + + This is description line 2 + + .EXAMPLE + ``` + $description = 'Code-fenced single-line example with adjacent multi-line description' + ``` + + This is description line 1 + This is description line 2 + + .EXAMPLE + ``` + $description = 'Complex code-fenced example without description' + $names | Foreach-Object {} { + write-host 'indentation is respected' + Write-Host 'enormously long lines will not get cut off by our PlatyPS friends, ftw' + } + + $multipleNewlinesInCode = $True + ``` + + .EXAMPLE + ``` + $description = 'Complex code-fenced example with a complex markdown description' + $names | Foreach-Object {} { + write-host 'indentation is respected' + Write-Host 'enormously long lines should not get cut off by our PlatyPS friends, ftw' + } + + $multipleNewlinesInCode = $True + ``` + + The description would continue after first closing code fence. + + This solution: + + - respects indentation + - will treat description as markdown + - seems close to what comes natural + + With this solution, the description itself could even contain code blocks: + + ```js + $var = docusaurus.New($config); + ``` + + Pretty cool and one could argue that the console becomes more readable too + as you can now at least see where the code ends and the explanation begins + + ``` + $unMonicked = "this code block should stay unmonicked, in other words powershell should not be added" + $indentationRespected = $True + $theBadNews - "that PlatyPS seems to cut off this line if a . is detected, wtf" + ``` + + .EXAMPLE + ```powershell + $description = 'Code-fenced single line example using POWERSHELL MONIKER without description' + ``` + + .EXAMPLE + ```powershell + $description = 'Code-fenced single line example using POWERSHELL MONIKER with single-line description' + ``` + + This is description line 1 + + .EXAMPLE + ```posh + $description = 'Code-fenced single line example using POSH MONIKER without description' + ``` + + .EXAMPLE + ```posh + $description = 'Code-fenced single line example using POSH MONIKER with single-line description' + ``` + + This is description line 1 + + .EXAMPLE + ```ps + $description = 'Code-fenced single line example using PS MONIKER without description' + ``` + + .EXAMPLE + ```ps + $description = 'Code-fenced single line example using PS MONIKER with single-line description' + ``` + + This is description line 1 +#> +} From 3b3752699fbe95962cf839e46eae523d7ee9e0f1 Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Sat, 28 Dec 2019 21:36:37 +0100 Subject: [PATCH 09/29] fix: NewMarkdownExample not adding powershell moniker --- Source/Private/NewMarkdownExample.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Private/NewMarkdownExample.ps1 b/Source/Private/NewMarkdownExample.ps1 index 0091aeeb..c18a4db7 100644 --- a/Source/Private/NewMarkdownExample.ps1 +++ b/Source/Private/NewMarkdownExample.ps1 @@ -10,7 +10,7 @@ function NewMarkdownExample() { ) $example = "$Header`n" - $example += '```' + "`n" + $example += '```powershell' + "`n" $example += $Code $example += '```' + "`n" From e8238c1ae1c7600a2035edb1a5abc59bf3d827e0 Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Sat, 28 Dec 2019 21:39:02 +0100 Subject: [PATCH 10/29] fix: example rendering for Powershell 7 and related tests --- Source/Private/ReplaceMarkdownCodeBlocks.ps1 | 67 ++++++++++++++++---- 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/Source/Private/ReplaceMarkdownCodeBlocks.ps1 b/Source/Private/ReplaceMarkdownCodeBlocks.ps1 index 28209da5..2f81f212 100644 --- a/Source/Private/ReplaceMarkdownCodeBlocks.ps1 +++ b/Source/Private/ReplaceMarkdownCodeBlocks.ps1 @@ -41,17 +41,17 @@ function ReplaceMarkdownCodeBlocks() { # --------------------------------------------------------------------- # Powershell 6: re-construct Code Fenced example - # - https://regex101.com/r/lHdZHM/6 => code block without a description - # - https://regex101.com/r/CGjQco/3 => code block with a description + # - https://regex101.com/r/lHdZHM/6 => without a description + # - https://regex101.com/r/CGjQco/3 => with a description # --------------------------------------------------------------------- - $regexPowershell6CodeFences = [regex]::new('(### EXAMPLE ([0-9|[0-9]+))\n(```\n(```|```ps|```posh|```powershell)\n```\n)\n([\s\S]*?)\\`\\`\\`(\n\n|\n)([\s\S]*|\n)') + $regexPowershell6TripleCodeFence = [regex]::new('(### EXAMPLE ([0-9|[0-9]+))\n(```\n(```|```ps|```posh|```powershell)\n```\n)\n([\s\S]*?)\\`\\`\\`(\n\n|\n)([\s\S]*|\n)') - if ($example -match $regexPowershell6CodeFences) { + if ($example -match $regexPowershell6TripleCodeFence) { $header = $matches[1] $code = $matches[5] $description = $matches[7] - Write-Verbose "=> $($header): applying Powershell 6 Code Fencing Detection" + Write-Verbose "=> $($header): Triple Code Fence (Powershell 6 and lower)" $newExample = NewMarkdownExample -Header $header -Code $code -Description $description $newExamples += $newExample @@ -59,19 +59,64 @@ function ReplaceMarkdownCodeBlocks() { } # --------------------------------------------------------------------- - # no matches so we follow the Comment Based Help standard and thus use - # PlatyPS generated code block. This regex will detect both single- - # line and multi-line code examples and has support for Powershell v7. + # Powershell 7: re-construct PlatyPS Paired Code Fences example + # - https://regex101.com/r/FRA139/1 => without a description + # - https://regex101.com/r/YIIwUs/5 => with a description # --------------------------------------------------------------------- - $regexDefaultCodeBlocks = [regex]::new('(### EXAMPLE [0-9])\n```\n([\s\S]*)```\n(([\s\S]*|\n|))?(?=\n.*?#|$)') + $regexPowershell7PairedCodeFences = [regex]::new('(### EXAMPLE ([0-9]|[0-9]+))\n(```\n(```|```ps|```posh|```powershell)\n)([\s\S]*?)```\n```(\n\n|\n)([\s\S]*|\n)') + + if ($example -match $regexPowershell7PairedCodeFences) { + $header = $matches[1] + $code = $matches[5] + $description = $matches[7] + + Write-Verbose "=> $($header): Paired Code Fences (Powershell 7)" + + $newExample = NewMarkdownExample -Header $header -Code $code -Description $description + $newExamples += $newExample + return + } + + # --------------------------------------------------------------------- + # Powershell 7: re-construct non-adjacent Code Fenced example + # - https://regex101.com/r/kLr98l/3 => without a description + # - https://regex101.com/r/eJH4cQ/6 => with a complex description + # --------------------------------------------------------------------- + $regexPowershell7NonAdjacentCodeBlock = [regex]::new('(### EXAMPLE ([0-9]|[0-9]+))\n(```\n(```|```ps|```posh|```powershell)\n)([\s\S]*?)\\`\\`\\`(\n\n([\s\S]*)|\n)') + + if ($example -match $regexPowershell7NonAdjacentCodeBlock) { + $header = $matches[1] + $code = $matches[5] -replace ('```' + "`n"), '' + $description = $matches[7] + + Write-Verbose "=> $($header): Non-Adjacent Code Block (Powershell 7)" + + $newExample = NewMarkdownExample -Header $header -Code $code -Description $description + $newExamples += $newExample + return + } + + # --------------------------------------------------------------------- + # no matches so we simply use the unaltered PlatyPS generated example + # - https://regex101.com/r/rllmTj/1 => without a decription + # - https://regex101.com/r/kTH75U/1 => with a description + # --------------------------------------------------------------------- + $regexPlatyPsDefaults = [regex]::new('(### EXAMPLE ([0-9]|[0-9]+))\n```\n([\s\S]*)```\n([\s\S]*)') + + if ($example -match $regexPlatyPsDefaults) { + $header = $matches[1] + $code = $matches[5] -replace ('```' + "`n"), '' + $description = $matches[7] + + Write-Verbose "=> $($header): PlatyPS Default (all Powershell versions)" - if ($example -match $regexDefaultCodeBlocks) { $newExamples += "$example`n" return } # we should never reach this point - Write-Warning "Unsupported code block detected, please file an issue at https://github.com/alt3/Docusaurus.Powershell/issues" + Write-Warning "Unsupported code block detected, please file an issue containing the error message below at https://github.com/alt3/Docusaurus.Powershell/issues" + Write-Warning $example } # replace EXAMPLES section in content with updated examples From 51f006145f4b63512b4d3e88bb47d33f32b27f3f Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Sat, 28 Dec 2019 22:10:28 +0100 Subject: [PATCH 11/29] test: refactor and cleanup of integration tests --- ...ps1 => CrossVersionCodeExamples.Tests.ps1} | 7 +- ... => CrossVersionCodeExamples.expected.mdx} | 66 +++++++++---------- ...les.psm1 => CrossVersionCodeExamples.psm1} | 62 ++++++++--------- .../Powershell7NativeMultiLineCode.Tests.ps1 | 36 +++++----- ...owershell7NativeMultiLineCode.expected.mdx | 8 +-- .../Powershell7NativeMultiLineCode.psm1 | 8 +-- 6 files changed, 98 insertions(+), 89 deletions(-) rename Tests/Integration/{AllVersionsCodeExamples.Tests.ps1 => CrossVersionCodeExamples.Tests.ps1} (89%) rename Tests/Integration/{AllVersionsCodeExamples.expected.mdx => CrossVersionCodeExamples.expected.mdx} (59%) rename Tests/Integration/{AllVersionsCodeExamples.psm1 => CrossVersionCodeExamples.psm1} (59%) diff --git a/Tests/Integration/AllVersionsCodeExamples.Tests.ps1 b/Tests/Integration/CrossVersionCodeExamples.Tests.ps1 similarity index 89% rename from Tests/Integration/AllVersionsCodeExamples.Tests.ps1 rename to Tests/Integration/CrossVersionCodeExamples.Tests.ps1 index 826ac82f..cef7b00a 100644 --- a/Tests/Integration/AllVersionsCodeExamples.Tests.ps1 +++ b/Tests/Integration/CrossVersionCodeExamples.Tests.ps1 @@ -25,7 +25,7 @@ Describe "Integration Test to ensure all supported Code Example variants render # render the markdown ${global:outputFolder} = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ${global:testModuleName} InModuleScope Alt3.Docusaurus.Powershell { - New-DocusaurusHelp -Module ${global:testModulePath} -OutputFolder ${global:outputFolder} -Verbose + New-DocusaurusHelp -Module ${global:testModulePath} -OutputFolder ${global:outputFolder} } # read markdown @@ -37,3 +37,8 @@ Describe "Integration Test to ensure all supported Code Example variants render $renderedMdx | Should -BeExactly $expectedMdx } } + +# ----------------------------------------------------------------------------- +# cleanup +# ----------------------------------------------------------------------------- +Remove-Item ${global:outputFolder} -Recurse -Force diff --git a/Tests/Integration/AllVersionsCodeExamples.expected.mdx b/Tests/Integration/CrossVersionCodeExamples.expected.mdx similarity index 59% rename from Tests/Integration/AllVersionsCodeExamples.expected.mdx rename to Tests/Integration/CrossVersionCodeExamples.expected.mdx index f6ff5c63..7e7a7dc2 100644 --- a/Tests/Integration/AllVersionsCodeExamples.expected.mdx +++ b/Tests/Integration/CrossVersionCodeExamples.expected.mdx @@ -1,6 +1,6 @@ --- -id: Test-AllVersionsCodeExamples -title: Test-AllVersionsCodeExamples +id: Test-CrossVersionCodeExamples +title: Test-CrossVersionCodeExamples hide_title: false hide_table_of_contents: false --- @@ -11,7 +11,7 @@ Dummy module to ensure all supported Get-Help example variations render identica ## SYNTAX ```powershell -Test-AllVersionsCodeExamples +Test-CrossVersionCodeExamples ``` ## DESCRIPTION @@ -21,65 +21,65 @@ Test-AllVersionsCodeExamples ### EXAMPLE 1 ```powershell -$description = 'Native single-line example without description' +$exampleType = 'Native single-line example without description' ``` ### EXAMPLE 2 ```powershell -$description = 'Native single-line example with single-line description' +$exampleType = 'Native single-line example with single-line description' ``` -This is description line 1 +Description starts on this line ### EXAMPLE 3 ```powershell -$description = 'Native single-line example with non-adjacent multi-line description' +$exampleType = 'Native single-line example with non-adjacent multi-line description' ``` -This is description line 1 +Description starts on this line -This is description line 2 +Description line 2 ### EXAMPLE 4 ```powershell -$description = 'Native single-line example with adjacent multi-line description' +$exampleType = 'Native single-line example with adjacent multi-line description' ``` -This is description line 1 -This is description line 2 +Description starts on this line +Description line 2 ### EXAMPLE 5 ```powershell -$description = 'Code-fenced single-line example without description' +$exampleType = 'Code-fenced single-line example without description' ``` ### EXAMPLE 6 ```powershell -$description = 'Code-fenced single-line example with single-line description' +$exampleType = 'Code-fenced single-line example with single-line description' ``` -This is description line 1 +Description starts on this line ### EXAMPLE 7 ```powershell -$description = 'Code-fenced single-line example with non-adjacent multi-line description' +$exampleType = 'Code-fenced single-line example with non-adjacent multi-line description' ``` -This is description line 1 +Description starts on this line -This is description line 2 +Description line 2 ### EXAMPLE 8 ```powershell -$description = 'Code-fenced single-line example with adjacent multi-line description' +$exampleType = 'Code-fenced single-line example with adjacent multi-line description' ``` -This is description line 1 -This is description line 2 +Description starts on this line +Description line 2 ### EXAMPLE 9 ```powershell -$description = 'Complex code-fenced example without description' +$exampleType = 'Complex non-adjacent code-fenced example without description' $names | Foreach-Object {} { write-host 'indentation is respected' Write-Host 'enormously long lines will not get cut off by our PlatyPS friends, ftw' @@ -90,7 +90,7 @@ $multipleNewlinesInCode = $True ### EXAMPLE 10 ```powershell -$description = 'Complex code-fenced example with a complex markdown description' +$exampleType = 'Complex non-adjacent code-fenced example with a complex markdown description' $names | Foreach-Object {} { write-host 'indentation is respected' Write-Host 'enormously long lines should not get cut off by our PlatyPS friends, ftw' @@ -99,7 +99,7 @@ $names | Foreach-Object {} { $multipleNewlinesInCode = $True ``` -The description would continue after first closing code fence. +Description starts on this line This solution: @@ -125,39 +125,39 @@ is detected, wtf" ### EXAMPLE 11 ```powershell -$description = 'Code-fenced single line example using POWERSHELL MONIKER without description' +$exampleType = 'Code-fenced single line example using POWERSHELL MONIKER without description' ``` ### EXAMPLE 12 ```powershell -$description = 'Code-fenced single line example using POWERSHELL MONIKER with single-line description' +$exampleType = 'Code-fenced single line example using POWERSHELL MONIKER with single-line description' ``` -This is description line 1 +Description starts on this line ### EXAMPLE 13 ```powershell -$description = 'Code-fenced single line example using POSH MONIKER without description' +$exampleType = 'Code-fenced single line example using POSH MONIKER without description' ``` ### EXAMPLE 14 ```powershell -$description = 'Code-fenced single line example using POSH MONIKER with single-line description' +$exampleType = 'Code-fenced single line example using POSH MONIKER with single-line description' ``` -This is description line 1 +Description starts on this line ### EXAMPLE 15 ```powershell -$description = 'Code-fenced single line example using PS MONIKER without description' +$exampleType = 'Code-fenced single line example using PS MONIKER without description' ``` ### EXAMPLE 16 ```powershell -$description = 'Code-fenced single line example using PS MONIKER with single-line description' +$exampleType = 'Code-fenced single line example using PS MONIKER with single-line description' ``` -This is description line 1 +Description starts on this line ## PARAMETERS diff --git a/Tests/Integration/AllVersionsCodeExamples.psm1 b/Tests/Integration/CrossVersionCodeExamples.psm1 similarity index 59% rename from Tests/Integration/AllVersionsCodeExamples.psm1 rename to Tests/Integration/CrossVersionCodeExamples.psm1 index 759806d4..36f7fedb 100644 --- a/Tests/Integration/AllVersionsCodeExamples.psm1 +++ b/Tests/Integration/CrossVersionCodeExamples.psm1 @@ -1,4 +1,4 @@ -function Test-AllVersionsCodeExamples { +function Test-CrossVersionCodeExamples { <# .SYNOPSIS Dummy module to ensure all supported Get-Help example variations render identically on all Powershell versions. @@ -7,58 +7,58 @@ function Test-AllVersionsCodeExamples { https://github.com/alt3/Docusaurus.Powershell/issues/14#issuecomment-568552556 .EXAMPLE - $description = 'Native single-line example without description' + $exampleType = 'Native single-line example without description' .EXAMPLE - $description = 'Native single-line example with single-line description' + $exampleType = 'Native single-line example with single-line description' - This is description line 1 + Description starts on this line .EXAMPLE - $description = 'Native single-line example with non-adjacent multi-line description' + $exampleType = 'Native single-line example with non-adjacent multi-line description' - This is description line 1 + Description starts on this line - This is description line 2 + Description line 2 .EXAMPLE - $description = 'Native single-line example with adjacent multi-line description' + $exampleType = 'Native single-line example with adjacent multi-line description' - This is description line 1 - This is description line 2 + Description starts on this line + Description line 2 .EXAMPLE ``` - $description = 'Code-fenced single-line example without description' + $exampleType = 'Code-fenced single-line example without description' ``` .EXAMPLE ``` - $description = 'Code-fenced single-line example with single-line description' + $exampleType = 'Code-fenced single-line example with single-line description' ``` - This is description line 1 + Description starts on this line .EXAMPLE ``` - $description = 'Code-fenced single-line example with non-adjacent multi-line description' + $exampleType = 'Code-fenced single-line example with non-adjacent multi-line description' ``` - This is description line 1 + Description starts on this line - This is description line 2 + Description line 2 .EXAMPLE ``` - $description = 'Code-fenced single-line example with adjacent multi-line description' + $exampleType = 'Code-fenced single-line example with adjacent multi-line description' ``` - This is description line 1 - This is description line 2 + Description starts on this line + Description line 2 .EXAMPLE ``` - $description = 'Complex code-fenced example without description' + $exampleType = 'Complex non-adjacent code-fenced example without description' $names | Foreach-Object {} { write-host 'indentation is respected' Write-Host 'enormously long lines will not get cut off by our PlatyPS friends, ftw' @@ -69,7 +69,7 @@ function Test-AllVersionsCodeExamples { .EXAMPLE ``` - $description = 'Complex code-fenced example with a complex markdown description' + $exampleType = 'Complex non-adjacent code-fenced example with a complex markdown description' $names | Foreach-Object {} { write-host 'indentation is respected' Write-Host 'enormously long lines should not get cut off by our PlatyPS friends, ftw' @@ -78,7 +78,7 @@ function Test-AllVersionsCodeExamples { $multipleNewlinesInCode = $True ``` - The description would continue after first closing code fence. + Description starts on this line This solution: @@ -103,38 +103,38 @@ function Test-AllVersionsCodeExamples { .EXAMPLE ```powershell - $description = 'Code-fenced single line example using POWERSHELL MONIKER without description' + $exampleType = 'Code-fenced single line example using POWERSHELL MONIKER without description' ``` .EXAMPLE ```powershell - $description = 'Code-fenced single line example using POWERSHELL MONIKER with single-line description' + $exampleType = 'Code-fenced single line example using POWERSHELL MONIKER with single-line description' ``` - This is description line 1 + Description starts on this line .EXAMPLE ```posh - $description = 'Code-fenced single line example using POSH MONIKER without description' + $exampleType = 'Code-fenced single line example using POSH MONIKER without description' ``` .EXAMPLE ```posh - $description = 'Code-fenced single line example using POSH MONIKER with single-line description' + $exampleType = 'Code-fenced single line example using POSH MONIKER with single-line description' ``` - This is description line 1 + Description starts on this line .EXAMPLE ```ps - $description = 'Code-fenced single line example using PS MONIKER without description' + $exampleType = 'Code-fenced single line example using PS MONIKER without description' ``` .EXAMPLE ```ps - $description = 'Code-fenced single line example using PS MONIKER with single-line description' + $exampleType = 'Code-fenced single line example using PS MONIKER with single-line description' ``` - This is description line 1 + Description starts on this line #> } diff --git a/Tests/Integration/Powershell7NativeMultiLineCode.Tests.ps1 b/Tests/Integration/Powershell7NativeMultiLineCode.Tests.ps1 index 11ada89e..5c650d67 100644 --- a/Tests/Integration/Powershell7NativeMultiLineCode.Tests.ps1 +++ b/Tests/Integration/Powershell7NativeMultiLineCode.Tests.ps1 @@ -28,21 +28,25 @@ Import-Module ${global:testModulePath} -Force -DisableNameChecking -Verbose:$Fal # ----------------------------------------------------------------------------- # the actual integration test # ----------------------------------------------------------------------------- -Describe "Integration Test for Powershell 7" { - Context "for Native Multi-Line Code Support" { - # render the markdown - ${global:outputFolder} = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ${global:testModuleName} - InModuleScope Alt3.Docusaurus.Powershell { - New-DocusaurusHelp -Module ${global:testModulePath} -OutputFolder ${global:outputFolder} - } - - # read markdown - $renderedMdx = Get-Content (Join-Path -Path ${global:outputFolder} -ChildPath "commands" | Join-Path -ChildPath "Test-$(${global:testModuleName}).mdx") - $expectedMdx = Get-Content (Join-Path -Path $PSScriptRoot -ChildPath "$(${global:testModuleName}).expected.mdx") - - # make sure output is identical - It "generates markdown that is identical to the markdown found in our static 'expected' mdx file" { - $renderedMdx | Should -BeExactly $expectedMdx - } +Describe "Integration Test to ensure Powershell 7's Native Multi-Line Code Examples render as expected" { + + # render the markdown + ${global:outputFolder} = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ${global:testModuleName} + InModuleScope Alt3.Docusaurus.Powershell { + New-DocusaurusHelp -Module ${global:testModulePath} -OutputFolder ${global:outputFolder} + } + + # read markdown + $renderedMdx = Get-Content (Join-Path -Path ${global:outputFolder} -ChildPath "commands" | Join-Path -ChildPath "Test-$(${global:testModuleName}).mdx") + $expectedMdx = Get-Content (Join-Path -Path $PSScriptRoot -ChildPath "$(${global:testModuleName}).expected.mdx") + + # make sure output is identical + It "generates markdown that is identical to the markdown found in our static 'expected' mdx file" { + $renderedMdx | Should -BeExactly $expectedMdx } } + +# ----------------------------------------------------------------------------- +# cleanup +# ----------------------------------------------------------------------------- +Remove-Item ${global:outputFolder} -Recurse -Force diff --git a/Tests/Integration/Powershell7NativeMultiLineCode.expected.mdx b/Tests/Integration/Powershell7NativeMultiLineCode.expected.mdx index ab33e46f..415d7a66 100644 --- a/Tests/Integration/Powershell7NativeMultiLineCode.expected.mdx +++ b/Tests/Integration/Powershell7NativeMultiLineCode.expected.mdx @@ -21,13 +21,13 @@ Test-Powershell7NativeMultiLineCode ### EXAMPLE 1 ```powershell -$description = 'Powershell 7+ multi-line example WITHOUT a description' +$exampleType = 'Powershell 7 multi-line example WITHOUT a description' $respecsIndentation = $True ``` ### EXAMPLE 2 ```powershell -$description = 'Powershell 7+ multi-line example WITH a single-description' +$exampleType = 'Powershell 7 multi-line example WITH a single-description' $respecsIndentation = $True ``` @@ -35,13 +35,13 @@ Powershell 7 will use this line, and everything below it, as the description ### EXAMPLE 3 ```powershell -$description = 'Powershell 7+ multi-line example WITH a multi-line escription' +$exampleType = 'Powershell 7 multi-line example WITH a multi-line escription' $respecsIndentation = $True ``` Powershell 7 will use this line, and everything below it, as the description -This is the second description line +Description line 2 ## PARAMETERS diff --git a/Tests/Integration/Powershell7NativeMultiLineCode.psm1 b/Tests/Integration/Powershell7NativeMultiLineCode.psm1 index d8e3ce9e..afa80fb1 100644 --- a/Tests/Integration/Powershell7NativeMultiLineCode.psm1 +++ b/Tests/Integration/Powershell7NativeMultiLineCode.psm1 @@ -10,21 +10,21 @@ function Test-Powershell7NativeMultiLineCode { https://github.com/PowerShell/PowerShell/pull/10776 .EXAMPLE - $description = 'Powershell 7+ multi-line example WITHOUT a description' + $exampleType = 'Powershell 7 multi-line example WITHOUT a description' $respecsIndentation = $True .EXAMPLE - $description = 'Powershell 7+ multi-line example WITH a single-description' + $exampleType = 'Powershell 7 multi-line example WITH a single-description' $respecsIndentation = $True Powershell 7 will use this line, and everything below it, as the description .EXAMPLE - $description = 'Powershell 7+ multi-line example WITH a multi-line escription' + $exampleType = 'Powershell 7 multi-line example WITH a multi-line escription' $respecsIndentation = $True Powershell 7 will use this line, and everything below it, as the description - This is the second description line + Description line 2 #> } From 3c60d459405a81f639be21f94352242f61f4bfae Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Sat, 28 Dec 2019 22:46:45 +0100 Subject: [PATCH 12/29] site: bump docusaurus to 2.0.0-alpha.40 --- docusaurus/package.json | 4 +- docusaurus/yarn.lock | 155 +++++++++++++++++++--------------------- 2 files changed, 76 insertions(+), 83 deletions(-) diff --git a/docusaurus/package.json b/docusaurus/package.json index 063e0101..48bb3a97 100644 --- a/docusaurus/package.json +++ b/docusaurus/package.json @@ -10,8 +10,8 @@ "deploy": "docusaurus deploy" }, "dependencies": { - "@docusaurus/core": "^2.0.0-alpha.39", - "@docusaurus/preset-classic": "^2.0.0-alpha.39", + "@docusaurus/core": "^2.0.0-alpha.40", + "@docusaurus/preset-classic": "^2.0.0-alpha.40", "classnames": "^2.2.6", "prismjs": "^1.17.1", "react": "^16.8.4", diff --git a/docusaurus/yarn.lock b/docusaurus/yarn.lock index d9f4c337..d23c3af3 100644 --- a/docusaurus/yarn.lock +++ b/docusaurus/yarn.lock @@ -859,10 +859,10 @@ resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7" integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw== -"@docusaurus/core@^2.0.0-alpha.39": - version "2.0.0-alpha.39" - resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-2.0.0-alpha.39.tgz#672310dba296ede738d9788acf13722aa4a43cb9" - integrity sha512-ZIW+TXBi+ZYGuOGUrIDCtVHmhJt4FTjr5YIOtKl1tjWBjidyIFjttkCP07SPEprHtVeXghZ/LeX6gq38kWrTBw== +"@docusaurus/core@^2.0.0-alpha.40": + version "2.0.0-alpha.40" + resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-2.0.0-alpha.40.tgz#cefc79156b89316317aee289fc68547b1d0ced04" + integrity sha512-3mVw7vXm6Ad53+1qKvYD3EzULC/JyWH8dUlysLzbsWx3M6+ZJ4NNdNTtLM4Uuug8OdnbhIJL244O4wSeRT5U3Q== dependencies: "@babel/core" "^7.7.4" "@babel/plugin-syntax-dynamic-import" "^7.7.4" @@ -870,7 +870,7 @@ "@babel/preset-env" "^7.7.4" "@babel/preset-react" "^7.7.4" "@babel/runtime" "^7.7.4" - "@docusaurus/utils" "^2.0.0-alpha.39" + "@docusaurus/utils" "^2.0.0-alpha.40" "@endiliey/static-site-generator-webpack-plugin" "^4.0.0" babel-loader "^8.0.6" babel-plugin-dynamic-import-node "^2.3.0" @@ -887,6 +887,7 @@ express "^4.17.1" fs-extra "^8.1.0" globby "^10.0.1" + html-minifier-terser "^5.0.2" html-tags "^3.1.0" html-webpack-plugin "^4.0.0-beta.11" import-fresh "^3.2.1" @@ -908,7 +909,6 @@ semver "^6.3.0" shelljs "^0.8.3" std-env "^2.2.1" - style-loader "^1.0.1" terser-webpack-plugin "^2.2.1" wait-file "^1.0.5" webpack "^4.41.2" @@ -917,16 +917,17 @@ webpack-merge "^4.2.2" webpackbar "^4.0.0" -"@docusaurus/mdx-loader@^2.0.0-alpha.39": - version "2.0.0-alpha.39" - resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-alpha.39.tgz#31237b83fadf79ed8e4897401888583fd8532f76" - integrity sha512-rYT5Q3Ryk1FWdxOKbOGVRbC4aNr49C8KmzmjHSCX2ke0FXEgGrPaCtMN9n38zADtJ1a63ZFr3eQqPmyX2sEX5g== +"@docusaurus/mdx-loader@^2.0.0-alpha.40": + version "2.0.0-alpha.40" + resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-alpha.40.tgz#26670dd07ff4b91831257f9b375400fe05a10e0c" + integrity sha512-v63OQKDf2DxN5SG9brKC2h5xDY9I8e0CGs/uNMF6txpVA/XYTNc2yP+XXUZS3Vx9xVIPH8uLruTZr5/bx2XH7w== dependencies: "@babel/parser" "^7.7.4" "@babel/traverse" "^7.7.4" "@mdx-js/mdx" "^1.5.1" "@mdx-js/react" "^1.5.1" escape-html "^1.0.3" + fs-extra "^8.1.0" github-slugger "^1.2.1" gray-matter "^4.0.2" loader-utils "^1.2.3" @@ -936,26 +937,26 @@ stringify-object "^3.3.0" unist-util-visit "^2.0.1" -"@docusaurus/plugin-content-blog@^2.0.0-alpha.39": - version "2.0.0-alpha.39" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.0.0-alpha.39.tgz#0ab951136147efb4f17307b45eb1f0133c40c86d" - integrity sha512-Z95KD553HCGhQjMY6ytU+ses/7SgF5umIXW+22L5nVemwmF4huAfQhy1ekBPxyfojPH/1Yc+IKdEr85hjTcxwA== +"@docusaurus/plugin-content-blog@^2.0.0-alpha.40": + version "2.0.0-alpha.40" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.0.0-alpha.40.tgz#e586f2af7e4736094eb4af5d2cc305877e4ef80a" + integrity sha512-iLCWtkQNe08+kYWlZC52WE3b3LDoYqh7mQYr2sOPmuZYmUv6wm88I7QMP3FlEpSIsYrIVy6yRoOGpD7Lf43wlA== dependencies: - "@docusaurus/mdx-loader" "^2.0.0-alpha.39" - "@docusaurus/utils" "^2.0.0-alpha.39" + "@docusaurus/mdx-loader" "^2.0.0-alpha.40" + "@docusaurus/utils" "^2.0.0-alpha.40" feed "^4.0.0" fs-extra "^8.1.0" globby "^10.0.1" loader-utils "^1.2.3" lodash "^4.17.15" -"@docusaurus/plugin-content-docs@^2.0.0-alpha.39": - version "2.0.0-alpha.39" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.0.0-alpha.39.tgz#5b538b0c37ccd6b26114670642b01f6ff43b4528" - integrity sha512-LUaNXneUoG4M1S+o3XsEr35MHp+pIHtjQZ3Y7x48datfUasXrr4iQqaL2bP/Poc6gEU7sedIxKruTm3KK79GcA== +"@docusaurus/plugin-content-docs@^2.0.0-alpha.40": + version "2.0.0-alpha.40" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.0.0-alpha.40.tgz#acec3e8b7c9deba415131fb8b53b618c039b06b5" + integrity sha512-cZgGJGNtYXlR2CQI7EuPyzf7DV1RvX+gRSRcPn979XxuLyk2GRWJ1/ODS3jkjQOfTat1QMFYvFrF5vYAgN6Drg== dependencies: - "@docusaurus/mdx-loader" "^2.0.0-alpha.39" - "@docusaurus/utils" "^2.0.0-alpha.39" + "@docusaurus/mdx-loader" "^2.0.0-alpha.40" + "@docusaurus/utils" "^2.0.0-alpha.40" execa "^3.4.0" fs-extra "^8.1.0" globby "^10.0.1" @@ -964,51 +965,51 @@ lodash "^4.17.15" shelljs "^0.8.3" -"@docusaurus/plugin-content-pages@^2.0.0-alpha.39": - version "2.0.0-alpha.39" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.0.0-alpha.39.tgz#1139f38f5a773b35a50a482253a8403f8542c55e" - integrity sha512-68MXNYAfcbI395AF3bzbrVljLico57QhOufkPIhgq3eRE26lMsX21K2zqRrBytxuMrmAc2hEBEX6m44Wj2YEWQ== +"@docusaurus/plugin-content-pages@^2.0.0-alpha.40": + version "2.0.0-alpha.40" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.0.0-alpha.40.tgz#2edc4f906d9e30d4adac834d1a5ac8fab54b703e" + integrity sha512-igSyxGgzuJASLJ5969hyYx2x5B2jNDPu28BEiDbWP3sx1hwVZ+p+kXB8BlY1zlQob/NCGRH2LAR2Cyyb6o3Ntg== dependencies: - "@docusaurus/types" "^2.0.0-alpha.39" - "@docusaurus/utils" "^2.0.0-alpha.39" + "@docusaurus/types" "^2.0.0-alpha.40" + "@docusaurus/utils" "^2.0.0-alpha.40" globby "^10.0.1" -"@docusaurus/plugin-google-analytics@^2.0.0-alpha.39": - version "2.0.0-alpha.39" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.0.0-alpha.39.tgz#82be38d748f9886fcbdc9b9082cdcb77c2b79c5b" - integrity sha512-cbNVu1PSYsbuLV9Xr2eY1I6OaUmZkq5tn2ggClMwZz1r+NcqkAiMsOQdNX7cLkcQiptKwQWUik16NxHbT2PeTg== +"@docusaurus/plugin-google-analytics@^2.0.0-alpha.40": + version "2.0.0-alpha.40" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.0.0-alpha.40.tgz#1967ff433c1dfc3d0cf29e17bc078232f2344119" + integrity sha512-vWkx63QadZgxTi2J+nLRnAd4uuCJT/F1rhRB8wVoUR/Vkeo463oufNWQL5yDpC1FA2d54zAwaLbjSbTSyuD4TA== -"@docusaurus/plugin-google-gtag@^2.0.0-alpha.39": - version "2.0.0-alpha.39" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.0.0-alpha.39.tgz#35566402cfabcea36ae84e7ecdb1e2045ae6cacf" - integrity sha512-p2qDx1JHTcoTPfdEcuYM1KY8pe2HayCVCu/PYiB5tkLEhATDiv/7TEDry1/cuvx+YQcg98E7amiCofWtZkYgkQ== +"@docusaurus/plugin-google-gtag@^2.0.0-alpha.40": + version "2.0.0-alpha.40" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.0.0-alpha.40.tgz#9f6e372c39175615a70f53cdd4d4bb91fbbb07ac" + integrity sha512-2cBdCAsgLGg2uqSFf85GfUxsuqlmBIpmJhQrA/4Bc+ECc9mPxVq4UdD3C8YafUbiUzgNB2GTRv1igMBM4d7hEQ== -"@docusaurus/plugin-sitemap@^2.0.0-alpha.39": - version "2.0.0-alpha.39" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.0.0-alpha.39.tgz#9401d4564064bf398c2fcca927837884ba6f6ed2" - integrity sha512-qvDOmXTLVy5iwRRhV/S642iszxvtiQNmQwqoTpP4mjYzNIoPs/F0Dsc0VN2K0XW6dLtJsRl+wrTCNvwPY7cFng== +"@docusaurus/plugin-sitemap@^2.0.0-alpha.40": + version "2.0.0-alpha.40" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.0.0-alpha.40.tgz#32c9fdff8fee20fbebb18f15fd49a2b01a2560b5" + integrity sha512-Z7VoC1o8+9gsy8LCiqgkYJmWKqzpIKjfydD5AX0D46vWMohfCnDIvWPKS4uN7BcCm9HRL786tJu3v3821N8I0A== dependencies: - "@docusaurus/types" "^2.0.0-alpha.39" + "@docusaurus/types" "^2.0.0-alpha.40" sitemap "^3.2.2" -"@docusaurus/preset-classic@^2.0.0-alpha.39": - version "2.0.0-alpha.39" - resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-2.0.0-alpha.39.tgz#ff2c458e4c39276c6146574f2ec8bfded49b7ea6" - integrity sha512-nJZ3Ze5/DEi6sCkr3s4JfYXBXqvS9kJ48SFl8Bkvxs5iamuVRI1AZZWcyJhIGtJxV6TJNLdp0SHu7NM0XU50Mw== - dependencies: - "@docusaurus/plugin-content-blog" "^2.0.0-alpha.39" - "@docusaurus/plugin-content-docs" "^2.0.0-alpha.39" - "@docusaurus/plugin-content-pages" "^2.0.0-alpha.39" - "@docusaurus/plugin-google-analytics" "^2.0.0-alpha.39" - "@docusaurus/plugin-google-gtag" "^2.0.0-alpha.39" - "@docusaurus/plugin-sitemap" "^2.0.0-alpha.39" - "@docusaurus/theme-classic" "^2.0.0-alpha.39" - "@docusaurus/theme-search-algolia" "^2.0.0-alpha.39" - -"@docusaurus/theme-classic@^2.0.0-alpha.39": - version "2.0.0-alpha.39" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-2.0.0-alpha.39.tgz#f13f36784f396561fa3601f1978f3ee396478475" - integrity sha512-yGdpNQINC5Db5hBA/CXrgcWlS2Y4lKgllMhXaT5KwM4ZMa6TLlo+P4mSRPnxCuPslg4vRWnd5QOiQ9AykXUNWw== +"@docusaurus/preset-classic@^2.0.0-alpha.40": + version "2.0.0-alpha.40" + resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-2.0.0-alpha.40.tgz#7b45eb699c8512a3601c9dd2707b1c283edd8d6a" + integrity sha512-CALOb3aB1WR9JbK6ogMosy4ReZnkvtfCOJy49ibQqdVcJnmI46CbBscjHgbNph87tY9U/uzRb32XlP7mcScmng== + dependencies: + "@docusaurus/plugin-content-blog" "^2.0.0-alpha.40" + "@docusaurus/plugin-content-docs" "^2.0.0-alpha.40" + "@docusaurus/plugin-content-pages" "^2.0.0-alpha.40" + "@docusaurus/plugin-google-analytics" "^2.0.0-alpha.40" + "@docusaurus/plugin-google-gtag" "^2.0.0-alpha.40" + "@docusaurus/plugin-sitemap" "^2.0.0-alpha.40" + "@docusaurus/theme-classic" "^2.0.0-alpha.40" + "@docusaurus/theme-search-algolia" "^2.0.0-alpha.40" + +"@docusaurus/theme-classic@^2.0.0-alpha.40": + version "2.0.0-alpha.40" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-2.0.0-alpha.40.tgz#e6b6ee684d9499a895d2df894b4772db9d299939" + integrity sha512-kksNoAD4AD/klNJAuMWIWvkTP3aV85iozoNeihLALbTGQejEWxCbRL+dBjUflhF9zrKcvZP3s905hKj7Xt3B3g== dependencies: "@mdx-js/mdx" "^1.5.1" "@mdx-js/react" "^1.5.1" @@ -1019,27 +1020,27 @@ prism-react-renderer "^1.0.2" react-toggle "^4.1.1" -"@docusaurus/theme-search-algolia@^2.0.0-alpha.39": - version "2.0.0-alpha.39" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.0.0-alpha.39.tgz#1fc292b39ce627abb07193c0cf37a019cb7be5ae" - integrity sha512-Ssr3lZ178+Kd4rxDp0X4DmH1TjzSdJk3elOiE5ozmjDM49yEbRiAQ7u7C9h+QC+m14xi+UFa67+8oLRKLYJ2qA== +"@docusaurus/theme-search-algolia@^2.0.0-alpha.40": + version "2.0.0-alpha.40" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.0.0-alpha.40.tgz#f3f133d8ff392cfee5d5e1f7c102f6800bf54516" + integrity sha512-dCCu7JN5/WmJv6bBTpgbCuvz6LlQr6/pRMsWsShQPxal7JpgMAyVjLCdqL9byY+mJONQrWbpxPTWEHl9nZ9Mdw== dependencies: classnames "^2.2.6" docsearch.js "^2.6.3" -"@docusaurus/types@^2.0.0-alpha.39": - version "2.0.0-alpha.39" - resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-2.0.0-alpha.39.tgz#1bcbbbb337ba409adb510fdfeb8d0756d5677310" - integrity sha512-LSGwhk63KIhH3haVsTb3W7ttIZD0Vxu831LvBW1OAYm9POY9tC1sAcHbnAxnbGDL5K9QO4GNciiYW2CAoqhO8A== +"@docusaurus/types@^2.0.0-alpha.40": + version "2.0.0-alpha.40" + resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-2.0.0-alpha.40.tgz#be0af577dd6f4ef3202620f7e21acc7843a56bee" + integrity sha512-CcEVeONauYMaqECauAwt9p9ux4r8C7ww+ipaSLxG9wwzeYVgoVPWnIDlKSBIyx2UBWzGz4er+V6eGpHLY15x8Q== dependencies: "@types/webpack" "^4.41.0" commander "^4.0.1" querystring "0.2.0" -"@docusaurus/utils@^2.0.0-alpha.39": - version "2.0.0-alpha.39" - resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-2.0.0-alpha.39.tgz#2a354137abc0b54e0f2a38280ac1ae897d97759d" - integrity sha512-mG7Cp60VlTALPBfxDqds57lCsmhDvzVlGZ+gTWFhGgyr9G/Go9faHh8gZnVl4Wdjd1jGM4Pw52tT8tUjnEXwHg== +"@docusaurus/utils@^2.0.0-alpha.40": + version "2.0.0-alpha.40" + resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-2.0.0-alpha.40.tgz#fbbde31886ea1076a8d14e2133f07a6d35cf158e" + integrity sha512-MR1nD3o23PuyWuSX0n+bGXlGfWt08w1xrVDRb+J4M3LrOflSlgI2RaT2p3J7V/czNWcvfCjhknVNXqpVTViw6A== dependencies: escape-string-regexp "^2.0.0" fs-extra "^8.1.0" @@ -4324,7 +4325,7 @@ html-entities@^1.2.1: resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" integrity sha1-DfKTUfByEWNRXfueVUPl9u7VFi8= -html-minifier-terser@^5.0.1: +html-minifier-terser@^5.0.1, html-minifier-terser@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-5.0.2.tgz#0e67a0b062ae1dd0719fc73199479298f807ae16" integrity sha512-VAaitmbBuHaPKv9bj47XKypRhgDxT/cDLvsPiiF7w+omrN3K0eQhpigV9Z1ilrmHa9e0rOYcD6R/+LCDADGcnQ== @@ -7891,7 +7892,7 @@ schema-utils@^1.0.0: ajv-errors "^1.0.0" ajv-keywords "^3.1.0" -schema-utils@^2.0.0, schema-utils@^2.0.1, schema-utils@^2.5.0: +schema-utils@^2.0.0, schema-utils@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.5.0.tgz#8f254f618d402cc80257486213c8970edfd7c22f" integrity sha512-32ISrwW2scPXHUSusP8qMg5dLUawKkyV+/qIEV9JdXKx+rsM6mi8vZY8khg2M69Qom16rtroWXD3Ybtiws38gQ== @@ -8450,14 +8451,6 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= -style-loader@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.0.1.tgz#aec6d4c61d0ed8d0a442faed741d4dfc6573888a" - integrity sha512-CnpEkSR1C+REjudiTWCv4+ssP7SCiuaQZJTZDWBRwTJoS90mdqkB8uOGMHKgVeUzpaU7IfLWoyQbvvs5Joj3Xw== - dependencies: - loader-utils "^1.2.3" - schema-utils "^2.0.1" - style-to-object@0.2.3, style-to-object@^0.2.1: version "0.2.3" resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.2.3.tgz#afcf42bc03846b1e311880c55632a26ad2780bcb" From 72f06febdd7c45c237aa855beffd633e2346b54d Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Sat, 28 Dec 2019 22:57:04 +0100 Subject: [PATCH 13/29] site: rename sidebar home to 'Docs' --- docusaurus/sidebars.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docusaurus/sidebars.js b/docusaurus/sidebars.js index ce3fda16..e4dfa6f5 100644 --- a/docusaurus/sidebars.js +++ b/docusaurus/sidebars.js @@ -8,7 +8,7 @@ const commands = require('./docs/commands/docusaurus.sidebar.js'); module.exports = { docs: { - 'Docusaurus.Powershell': [ + 'Docs': [ 'introduction', 'installation', 'usage' From 4d8af6be4b2ebd560c6723cf879a70983a006df7 Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Sat, 28 Dec 2019 23:15:15 +0100 Subject: [PATCH 14/29] site: add links to the test files as multi-line usage examples --- docusaurus/docs/faq/multi-line-examples.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docusaurus/docs/faq/multi-line-examples.md b/docusaurus/docs/faq/multi-line-examples.md index d5af3e93..a9278341 100644 --- a/docusaurus/docs/faq/multi-line-examples.md +++ b/docusaurus/docs/faq/multi-line-examples.md @@ -44,7 +44,11 @@ A simple example would look similar to: - can also contain fenced code blocks ``` -Where you can use any of the following commonly used opening fences: +> For more usage examples see +> [this test module](https://github.com/alt3/Docusaurus.Powershell/blob/master/Tests/Integration/CrossVersionCodeExamples.psm1) +> and the corresponding [rendered markdown](https://github.com/alt3/Docusaurus.Powershell/blob/master/Tests/Integration/CrossVersionCodeExamples.expected.mdx) + +**Please note** that you may use any of the following commonly used opening fences: - \`\`\` - \`\`\`powershell @@ -65,7 +69,7 @@ does so in a limited form as can be seen in this example: Powershell 7 will use this line, and everything below it, as the description ``` -**You could use this native form instead of Code Fence Detection if:** +**You could consider using it instead of Code Fence Detection if:** - you are using Powershell 7 - your example code does not contain any empty newlines From 7729f511270463f4dba2e78e26753f998d749df2 Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Sat, 28 Dec 2019 23:15:49 +0100 Subject: [PATCH 15/29] site: mention multi-line support in introduction --- docusaurus/docs/introduction.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docusaurus/docs/introduction.md b/docusaurus/docs/introduction.md index 47c57759..e8c9f990 100644 --- a/docusaurus/docs/introduction.md +++ b/docusaurus/docs/introduction.md @@ -17,7 +17,8 @@ to worry about frontend development and maintenance, all handled by the Docusaur Some of the features you will get: - a website for promoting your module -- autogenerated Get-Help documentation +- auto-generated Get-Help documentation +- support for complex multi-line Get-Help code examples - authoring pages in both Markdown and Powershell source files - localization, versioning and fully indexed (Algolia) search - simplified publishing (Netlify, Github Pages) From f773a34f56fc1d82bddd8d3942890f2f0d07bd0f Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Sat, 28 Dec 2019 23:16:06 +0100 Subject: [PATCH 16/29] site: add Powershell 7 as a supported version --- docusaurus/docs/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docusaurus/docs/installation.md b/docusaurus/docs/installation.md index 23c73271..40e7979b 100644 --- a/docusaurus/docs/installation.md +++ b/docusaurus/docs/installation.md @@ -5,7 +5,7 @@ title: Installation ## Requirements -- [Powershell](https://docs.microsoft.com/en-us/powershell/) / [Powershell Core](https://github.com/PowerShell/PowerShell) +- [Powershell](https://docs.microsoft.com/en-us/powershell/) (version 5, 6 or 7) - [Node.js](https://nodejs.org/en/download/) - [Yarn](https://yarnpkg.com/en/) From 425af7c4c6225f5d739595ad39ea37aceffeac23 Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Sat, 28 Dec 2019 23:26:20 +0100 Subject: [PATCH 17/29] docs: add meta keywords for the command reference pages --- docusaurus/docs/commands/New-DocusaurusHelp.mdx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docusaurus/docs/commands/New-DocusaurusHelp.mdx b/docusaurus/docs/commands/New-DocusaurusHelp.mdx index f616b548..ef925b49 100644 --- a/docusaurus/docs/commands/New-DocusaurusHelp.mdx +++ b/docusaurus/docs/commands/New-DocusaurusHelp.mdx @@ -1,6 +1,14 @@ --- id: New-DocusaurusHelp title: New-DocusaurusHelp +description: Help page for the Alt3.Docusaurus.Powershell "New-DocusaurusHelp" command +keywords: + - Alt3 + - Documentation + - Docusaurus + - Get-Help + - Modules + - Powershell hide_title: false hide_table_of_contents: false custom_edit_url: https://github.com/alt3/Docusaurus.Powershell/edit/master/Source/Public From 3084fe2db5e5676b5253eb5c495b3c82a0adfd07 Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Sat, 28 Dec 2019 23:43:39 +0100 Subject: [PATCH 18/29] docs: rename nav item Commands to Get-Help --- README.md | 2 +- docusaurus/docusaurus.config.js | 6 +++--- docusaurus/sidebars.js | 2 +- docusaurus/src/pages/index.js | 4 ++-- docusaurus/static/img/screenshot.png | Bin 60939 -> 58837 bytes 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index b419a3b2..59f85599 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![Azure DevOps coverage](https://img.shields.io/azure-devops/coverage/alt3bv/Docusaurus.Powershell/2?style=flat-square)](https://dev.azure.com/alt3bv/Docusaurus.Powershell/_build) [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-v1.4%20adopted-ff69b4.svg?style=flat-square)](code-of-conduct.md) -Showcase websites for Powershell Modules. +Documentation websites for Powershell Modules. ## Live Demo diff --git a/docusaurus/docusaurus.config.js b/docusaurus/docusaurus.config.js index d020934b..61545650 100644 --- a/docusaurus/docusaurus.config.js +++ b/docusaurus/docusaurus.config.js @@ -7,7 +7,7 @@ module.exports = { title: 'Docusaurus.Powershell', - tagline: 'Awesome documentation for Powershell Modules', + tagline: 'Documentation websites for Powershell Modules', url: 'https://docusaurus-powershell.netlify.com/', baseUrl: '/', favicon: 'img/favicon.ico', @@ -22,7 +22,7 @@ module.exports = { }, links: [ {to: 'docs/introduction', label: 'Docs', position: 'right'}, - {to: 'docs/commands/New-DocusaurusHelp', label: 'Commands', position: 'right'}, + {to: 'docs/commands/New-DocusaurusHelp', label: 'Get-Help', position: 'right'}, { href: 'https://github.com/alt3/Docusaurus.Powershell', label: 'GitHub', @@ -54,7 +54,7 @@ module.exports = { to: 'docs/usage', }, { - label: 'Commands', + label: 'Get-Help', to: 'docs/commands/New-DocusaurusHelp', }, ], diff --git a/docusaurus/sidebars.js b/docusaurus/sidebars.js index e4dfa6f5..92b7d276 100644 --- a/docusaurus/sidebars.js +++ b/docusaurus/sidebars.js @@ -20,6 +20,6 @@ module.exports = { 'faq/search', 'faq/ci-cd', ], - "Command Reference": commands, + "Get-Help": commands, }, }; diff --git a/docusaurus/src/pages/index.js b/docusaurus/src/pages/index.js index 04712d3a..9abfe695 100644 --- a/docusaurus/src/pages/index.js +++ b/docusaurus/src/pages/index.js @@ -24,11 +24,11 @@ const features = [ ), }, { - title: <>Focus on What Matters, + title: <>Autogenerated Get-Help, imageUrl: 'img/undraw_docusaurus_tree.svg', description: ( <> - Write Get-Help documentation, nothing else. + Document your Powershell code, nothing else. ), }, diff --git a/docusaurus/static/img/screenshot.png b/docusaurus/static/img/screenshot.png index 1380770dbb7bcad4f67f492504b4a8772f693b22..708d14046d1264d698fa7ce1271829b133054257 100644 GIT binary patch literal 58837 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 literal 60939 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 F?=Rz{8tDK4 From 43fd661df4b6433c16ea2d2e2a95686f3f5955b2 Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Sun, 29 Dec 2019 00:02:57 +0100 Subject: [PATCH 19/29] docs: add a Get-Help example demonstrating splatting (complex multi-line code example) --- Source/Public/New-DocusaurusHelp.ps1 | 28 ++++++++++++++++++- .../docs/commands/New-DocusaurusHelp.mdx | 28 ++++++++++++++++++- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/Source/Public/New-DocusaurusHelp.ps1 b/Source/Public/New-DocusaurusHelp.ps1 index ed84b0b4..8fe33701 100644 --- a/Source/Public/New-DocusaurusHelp.ps1 +++ b/Source/Public/New-DocusaurusHelp.ps1 @@ -14,7 +14,33 @@ function New-DocusaurusHelp() { System.Object .EXAMPLE - New-DocusaurusHelp -Module Alt3.Docusaurus.Powershell -EditUrl "https://github.com/alt3/Docusaurus.Powershell/edit/master/source/Public" + New-DocusaurusHelp -Module Alt3.Docusaurus.Powershell + + This example uses default settings to generate a Get-Help page for each command exported by + the Alt3.Docusaurus.Powershell module. + + .EXAMPLE + ``` + $arguments = @{ + Module = "Alt3.Docusaurus.Powershell" + OutputFolder = "D:\my-project\docs" + SideBar = "commands" + Exclude = @( + "Get-SomeCommand" + ) + MetaDescription = 'Help page for the Powershell command "%1"' + MetaKeywords = @( + "Powershell" + "Documentation" + ) + } + + New-DocusaurusHelp @arguments + ``` + + This example uses splatting to override default settings. + + See the list of Parameters below for all available overrides. .PARAMETER Module Specifies the module this cmdlet will generate Docusaurus documentation for. diff --git a/docusaurus/docs/commands/New-DocusaurusHelp.mdx b/docusaurus/docs/commands/New-DocusaurusHelp.mdx index ef925b49..a5c74c51 100644 --- a/docusaurus/docs/commands/New-DocusaurusHelp.mdx +++ b/docusaurus/docs/commands/New-DocusaurusHelp.mdx @@ -36,9 +36,35 @@ Also creates a `sidebar.js` file for simplified integration into the Docusaurus ### EXAMPLE 1 ```powershell -New-DocusaurusHelp -Module Alt3.Docusaurus.Powershell -EditUrl "https://github.com/alt3/Docusaurus.Powershell/edit/master/source/Public" +New-DocusaurusHelp -Module Alt3.Docusaurus.Powershell ``` +This example uses default settings to generate a Get-Help page for each command exported by +the Alt3.Docusaurus.Powershell module. + +### EXAMPLE 2 +```powershell +$arguments = @{ + Module = "Alt3.Docusaurus.Powershell" + OutputFolder = "D:\my-project\docs" + SideBar = "commands" + Exclude = @( + "Get-SomeCommand" + ) + MetaDescription = 'Help page for the Powershell command "%1"' + MetaKeywords = @( + "Powershell" + "Documentation" + ) +} + +New-DocusaurusHelp @arguments +``` + +This example uses splatting to override default settings. + +See the list of Parameters below for all available overrides. + ## PARAMETERS ### -Module From 4365d7d96c8490a434258d47cb922101d404bc32 Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Sun, 29 Dec 2019 12:32:36 +0100 Subject: [PATCH 20/29] refactor: use temp folder to generate mdx files for future debugging --- Source/Private/CreateOrCleanFolder.ps1 | 21 +++++++ Source/Private/InitializeTempFolder.ps1 | 37 ++++++++++++ Source/Private/NewSidebarIncludeFile.ps1 | 5 +- Source/Private/RemoveFile.ps1 | 15 +++++ Source/Public/New-DocusaurusHelp.ps1 | 74 ++++++++++++++++-------- 5 files changed, 124 insertions(+), 28 deletions(-) create mode 100644 Source/Private/CreateOrCleanFolder.ps1 create mode 100644 Source/Private/InitializeTempFolder.ps1 create mode 100644 Source/Private/RemoveFile.ps1 diff --git a/Source/Private/CreateOrCleanFolder.ps1 b/Source/Private/CreateOrCleanFolder.ps1 new file mode 100644 index 00000000..abeafce5 --- /dev/null +++ b/Source/Private/CreateOrCleanFolder.ps1 @@ -0,0 +1,21 @@ +function CreateOrCleanFolder() { + <# + .SYNOPSIS + Helper function to create a folder OR remove it's contents if it already exists. + #> + param( + [Parameter(Mandatory = $True)][string]$Path + ) + + # create the folder if it does not exist + if (-not(Test-Path -Path $Path)) { + Write-Verbose "=> creating folder $($Path)" + New-Item -Path $Path -ItemType Directory -Force + + return + } + + # otherwise remove it's contents + Write-Verbose "=> cleaning folder $($Path)" + Remove-Item -Path (Join-Path -Path $Path -ChildPath *.*) +} diff --git a/Source/Private/InitializeTempFolder.ps1 b/Source/Private/InitializeTempFolder.ps1 new file mode 100644 index 00000000..a3354562 --- /dev/null +++ b/Source/Private/InitializeTempFolder.ps1 @@ -0,0 +1,37 @@ +function InitializeTempFolder() { + <# + .SYNOPSIS + Creates the temp folder and the `debug.info` file. + + .DESCRIPTION + The temp folder is where all work is done before the enriched mdx files are copied + to the docusaurus sidebar folder. We use this approach to support future debugging + as it will be near impossible to reason about bugs without looking at the initial + PlatyPS files, knowing which Powershell version was used etc. + + We might even instruct users to send us the files when reporting issues (which + would require re-generating using the `-KeepTempFiles` switch). + #> + param( + [Parameter(Mandatory = $True)][string]$Path + ) + + Write-Verbose "Initializing temp folder:" + CreateOrCleanFolder -Path $Path + + # prepare the debug info + Write-Verbose "=> creating debug file" + $debugInfo = [ordered]@{ + ModuleVersions = [ordered]@{ + "Alt3.Docusarus.Powershell" = (Get-Module "Alt3.Docusaurus.Powershell").Version + PlatyPs = (Get-Module PlatyPs).Version + Pester = (Get-Module Pester).Version + } + PSVersionTable = $PSVersionTable + } | ConvertTo-Json + + # create the debug file + $debugFile = Join-Path -Path $Path -ChildPath "debug.json" + $fileEncoding = New-Object System.Text.UTF8Encoding $False + [System.IO.File]::WriteAllLines($debugFile, $debugInfo, $fileEncoding) +} diff --git a/Source/Private/NewSidebarIncludeFile.ps1 b/Source/Private/NewSidebarIncludeFile.ps1 index e32fd7b2..fd1545ff 100644 --- a/Source/Private/NewSidebarIncludeFile.ps1 +++ b/Source/Private/NewSidebarIncludeFile.ps1 @@ -12,6 +12,8 @@ function NewSidebarIncludeFile() { [Parameter(Mandatory = $True)][Object]$MarkdownFiles ) + Write-Verbose "Generating docusaurus.sidebar.js" + # generate a list of Powershell commands by stripping .md from the generated PlatyPs files [array]$commands = $MarkdownFiles | Select-Object @{ Name = "PowershellCommand"; Expression={ "'$Sidebar/" + [System.IO.Path]::GetFileNameWithoutExtension($_) + "'" } } | Select-Object -Expand PowershellCommand @@ -42,7 +44,4 @@ module.exports = [ # create the file $fileEncoding = New-Object System.Text.UTF8Encoding $False [System.IO.File]::WriteAllLines($filePath, $content, $fileEncoding) - - # add created file to output - Get-Item $filePath } diff --git a/Source/Private/RemoveFile.ps1 b/Source/Private/RemoveFile.ps1 new file mode 100644 index 00000000..42832494 --- /dev/null +++ b/Source/Private/RemoveFile.ps1 @@ -0,0 +1,15 @@ +function RemoveFile() { + <# + .SYNOPSIS + Helper function to remove a file if it exists. + #> + param( + [Parameter(Mandatory = $True)][string]$Path + ) + + Write-Verbose "=> removing $Path" + + if (Test-Path -Path $Path) { + Remove-Item -Path $Path -Force + } +} diff --git a/Source/Public/New-DocusaurusHelp.ps1 b/Source/Public/New-DocusaurusHelp.ps1 index 8fe33701..8aed5c88 100644 --- a/Source/Public/New-DocusaurusHelp.ps1 +++ b/Source/Public/New-DocusaurusHelp.ps1 @@ -122,31 +122,49 @@ function New-DocusaurusHelp() { throw "New-DocusaurusHelp: Specified module '$Module' is not loaded" } - # markdown for the module will be isolated in a subfolder - $markdownFolder = Join-Path -Path $OutputFolder -ChildPath $Sidebar + $moduleName = [io.path]::GetFileName($module) + + # markdown for the module will be copied into the sidebar subfolder + Write-Verbose "Initializing sidebar folder:" + $sidebarFolder = Join-Path -Path $OutputFolder -ChildPath $Sidebar + CreateOrCleanFolder -Path $sidebarFolder + + # create tempfolder used for generating the PlatyPS files and creating the mdx files + $tempFolder = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath "Alt3.Docusaurus.Powershell" | Join-Path -ChildPath $moduleName + InitializeTempFolder -Path $tempFolder # generate PlatyPs markdown files - New-MarkdownHelp -Module $Module -OutputFolder $markdownFolder -Force | Out-Null + Write-Verbose "Generating PlatyPS files." + New-MarkdownHelp -Module $Module -OutputFolder $tempFolder -Force | Out-Null # remove excluded files + Write-Verbose "Removing excluded files:" $Exclude | ForEach-Object { - $excludedFile = Join-Path -Path $markdownFolder -ChildPath "$($_).md" - if (Test-Path -Path $excludedFile) { - Remove-Item -Path $excludedFile - } + RemoveFile -Path (Join-Path -Path $tempFolder -ChildPath "$($_).md") + } + + # rename PlatyPS files and create an `.mdx` copy we will transform + Write-Verbose "Cloning PlatyPS files." + Get-ChildItem -Path $tempFolder -Filter *.md | ForEach-Object { + $platyPsFile = $_.FullName -replace '.md', '.PlatyPS.md' + $mdxFile = $_.FullName -replace '.md', '.mdx' + Move-Item -Path $_.FullName -Destination $platyPsFile + Copy-Item -Path $platyPsFile -Destination $mdxFile } - # process remaining files - $markdownFiles = Get-ChildItem -Path $markdownFolder -Filter *.md + # update all remaining mdx files to make them Docusaurus compatible + Write-Verbose "Updating mdx files." + $mdxFiles = Get-ChildItem -Path $tempFolder -Filter *.mdx - # update generated markdown file(s) to make them Docusaurus compatible - ForEach ($markdownFile in $markdownFiles) { - SetMarkdownLineEndings -MarkdownFile $markdownFile + ForEach ($mdxFile in $mdxFiles) { + Write-Verbose "Processing $($mdxFile.Name):" - $customEditUrl = GetCustomEditUrl -Module $Module -MarkdownFile $markdownFile -EditUrl $EditUrl -Monolithic:$Monolithic + SetMarkdownLineEndings -MarkdownFile $mdxFile + + $customEditUrl = GetCustomEditUrl -Module $Module -MarkdownFile $mdxFile -EditUrl $EditUrl -Monolithic:$Monolithic $frontMatterArgs = @{ - MarkdownFile = $markdownFile + MarkdownFile = $mdxFile MetaDescription = $metaDescription CustomEditUrl = $customEditUrl MetaKeywords = $metaKeywords @@ -155,19 +173,25 @@ function New-DocusaurusHelp() { } SetMarkdownFrontMatter @frontmatterArgs - RemoveMarkdownHeaderOne -MarkdownFile $markdownFile - ReplaceMarkdownCodeBlocks -MarkdownFile $markdownFile - SetMarkdownCodeBlockMoniker -MarkdownFile $markdownFile - UpdateMarkdownBackticks -MarkdownFile $markdownFile - - # rename to .mdx - $mdxFilePath = GetMdxFilePath -MarkdownFile $markdownFile - Move-Item -Path $markdownFile.FullName -Destination $mdxFilePath -Force | Out-Null + RemoveMarkdownHeaderOne -MarkdownFile $mdxFile + ReplaceMarkdownCodeBlocks -MarkdownFile $mdxFile + SetMarkdownCodeBlockMoniker -MarkdownFile $mdxFile + UpdateMarkdownBackticks -MarkdownFile $mdxFile + } - # output .mdx item so end-user can post-process files as they see fit - Get-Item $mdxFilePath + # copy updated mdx files to the target folder + Write-Verbose "Copying mdx files to sidebar folder." + Get-ChildItem -Path $tempFolder -Filter *.mdx | ForEach-Object { + # $mdxFile = $_.FullName -replace '.md', '.mdx' + Copy-Item -Path $_.FullName -Destination (Join-Path -Path $sidebarFolder -ChildPath ($_.Name)) } # generate the `.js` file used for the docusaurus sidebar - NewSidebarIncludeFile -MarkdownFiles $markdownFiles -OutputFolder $markdownFolder -Sidebar $Sidebar + NewSidebarIncludeFile -MarkdownFiles $mdxFiles -OutputFolder $sidebarFolder -Sidebar $Sidebar + + # zip temp files in case we need them + Compress-Archive -Path (Join-Path -Path $tempFolder -ChildPath *.*) -DestinationPath (Join-Path $tempFolder -ChildPath "$moduleName.zip") + + # output Get-ChildItem so end-user can post-process generated files as they see fit + Get-ChildItem -Path $sidebarFolder } From ba6f99f3c620d1b8af84791c9a76cc4a0761db6a Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Sun, 29 Dec 2019 12:44:10 +0100 Subject: [PATCH 21/29] chore: remove orphaned GetMdxFilePath function --- Source/Private/GetMdxFilePath.ps1 | 11 ------- Tests/Unit/Private/GetMdxFilePath.Tests.ps1 | 35 --------------------- 2 files changed, 46 deletions(-) delete mode 100644 Source/Private/GetMdxFilePath.ps1 delete mode 100644 Tests/Unit/Private/GetMdxFilePath.Tests.ps1 diff --git a/Source/Private/GetMdxFilePath.ps1 b/Source/Private/GetMdxFilePath.ps1 deleted file mode 100644 index f5b60742..00000000 --- a/Source/Private/GetMdxFilePath.ps1 +++ /dev/null @@ -1,11 +0,0 @@ -function GetMdxFilePath() { - <# - .SYNOPSIS - Returns the .mdx file path for a given .md file. - #> - param( - [Parameter(Mandatory = $True)][System.IO.FileSystemInfo]$MarkdownFile - ) - - Join-Path $MarkdownFile.DirectoryName -ChildPath "$([System.IO.Path]::GetFileNameWithoutExtension($MarkdownFile.Name)).mdx" -} diff --git a/Tests/Unit/Private/GetMdxFilePath.Tests.ps1 b/Tests/Unit/Private/GetMdxFilePath.Tests.ps1 deleted file mode 100644 index f02106d3..00000000 --- a/Tests/Unit/Private/GetMdxFilePath.Tests.ps1 +++ /dev/null @@ -1,35 +0,0 @@ -Describe "Private$([IO.Path]::DirectorySeparatorChar)GetMdxFilePath" { - if (-not(Get-Module Alt3.Docusaurus.Powershell)) { - Import-Module Alt3.Docusaurus.Powershell -DisableNameChecking -Verbose:$False - } - - # up - $markdownFilePath = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath 'pester-markdown.md' - - "Dummy file" | Out-File -FilePath $markdownFilePath - if (-Not(Test-Path -Path $markdownFilePath)) { - throw "temporary markdown file was not created" - } - - ${global:markdownFileItem} = Get-Item -Path $markdownFilePath - - # the actual tests - $mdxFilePath = InModuleScope Alt3.Docusaurus.Powershell { - GetMdxFilePath -MarkdownFile ${global:markdownFileItem} - } - - It "does not change the filename" { - [System.IO.Path]::GetFileNameWithoutExtension($mdxFilePath) | Should -Be 'pester-markdown' - } - - It "does change the file extension to .mdx" { - [System.IO.Path]::GetExtension($mdxFilePath) | Should -Be '.mdx' - } - - It "does not change the full path" { - $mdxFilePath.Substring(0, $mdxFilePath.length - 1) | Should -Be ${global:markdownFileItem}.FullName - } - - # down - Remove-Item -Path ${global:markdownFileItem} -} From a0b98644e3c53f9a6905d9c7d51540ad22fb27c3 Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Sun, 29 Dec 2019 13:04:05 +0100 Subject: [PATCH 22/29] refactor: rename the -OutputFolder swith to -DocsFolder --- Source/Private/NewSidebarIncludeFile.ps1 | 4 ++-- Source/Public/New-DocusaurusHelp.ps1 | 10 +++++----- Tests/Integration/CrossVersionCodeExamples.Tests.ps1 | 8 ++++---- .../Powershell7NativeMultiLineCode.Tests.ps1 | 8 ++++---- docusaurus/docs/commands/New-DocusaurusHelp.mdx | 8 ++++---- docusaurus/docs/faq/ci-cd.md | 8 +------- 6 files changed, 20 insertions(+), 26 deletions(-) diff --git a/Source/Private/NewSidebarIncludeFile.ps1 b/Source/Private/NewSidebarIncludeFile.ps1 index fd1545ff..e078df60 100644 --- a/Source/Private/NewSidebarIncludeFile.ps1 +++ b/Source/Private/NewSidebarIncludeFile.ps1 @@ -34,12 +34,12 @@ module.exports = [ ]; "@ - # generate file path, convert relative outputfolder to absolute if needed + # generate file path, convert relative output folder to absolute if needed if (-Not([System.IO.Path]::IsPathRooted($OutputFolder))) { $outputFolder = Join-Path "$(Get-Location)" -ChildPath $OutputFolder } - $filePath = Join-Path -Path $OutputFolder -ChildPath "docusaurus.sidebar.js" + $filePath = Join-Path -Path $outputFolder -ChildPath "docusaurus.sidebar.js" # create the file $fileEncoding = New-Object System.Text.UTF8Encoding $False diff --git a/Source/Public/New-DocusaurusHelp.ps1 b/Source/Public/New-DocusaurusHelp.ps1 index 8aed5c88..9aaf3330 100644 --- a/Source/Public/New-DocusaurusHelp.ps1 +++ b/Source/Public/New-DocusaurusHelp.ps1 @@ -23,7 +23,7 @@ function New-DocusaurusHelp() { ``` $arguments = @{ Module = "Alt3.Docusaurus.Powershell" - OutputFolder = "D:\my-project\docs" + DocsFolder = "D:\my-project\docs" SideBar = "commands" Exclude = @( "Get-SomeCommand" @@ -47,8 +47,8 @@ function New-DocusaurusHelp() { You may specify a module name, a `.psd1` file or a `.psm1` file. - .PARAMETER OutputFolder - Specifies the folder where the Docusaurus sidebar subfolder will be created. + .PARAMETER DocsFolder + Specifies the Docusaurus `docs` folder in which the sidebar folder will be created. Optional, defaults to `docusaurus/docs`, case sensitive. @@ -100,7 +100,7 @@ function New-DocusaurusHelp() { [cmdletbinding()] param( [Parameter(Mandatory = $True)][string]$Module, - [Parameter(Mandatory = $False)][string]$OutputFolder = "docusaurus/docs", + [Parameter(Mandatory = $False)][string]$DocsFolder = "docusaurus/docs", [Parameter(Mandatory = $False)][string]$Sidebar = "commands", [Parameter(Mandatory = $False)][array]$Exclude = @(), [Parameter(Mandatory = $False)][string]$MetaDescription, @@ -126,7 +126,7 @@ function New-DocusaurusHelp() { # markdown for the module will be copied into the sidebar subfolder Write-Verbose "Initializing sidebar folder:" - $sidebarFolder = Join-Path -Path $OutputFolder -ChildPath $Sidebar + $sidebarFolder = Join-Path -Path $DocsFolder -ChildPath $Sidebar CreateOrCleanFolder -Path $sidebarFolder # create tempfolder used for generating the PlatyPS files and creating the mdx files diff --git a/Tests/Integration/CrossVersionCodeExamples.Tests.ps1 b/Tests/Integration/CrossVersionCodeExamples.Tests.ps1 index cef7b00a..fc6ce952 100644 --- a/Tests/Integration/CrossVersionCodeExamples.Tests.ps1 +++ b/Tests/Integration/CrossVersionCodeExamples.Tests.ps1 @@ -23,13 +23,13 @@ Import-Module ${global:testModulePath} -Force -DisableNameChecking -Verbose:$Fal Describe "Integration Test to ensure all supported Code Example variants render identically on all Powershell versions" { # render the markdown - ${global:outputFolder} = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ${global:testModuleName} + ${global:DocsFolder} = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ${global:testModuleName} InModuleScope Alt3.Docusaurus.Powershell { - New-DocusaurusHelp -Module ${global:testModulePath} -OutputFolder ${global:outputFolder} + New-DocusaurusHelp -Module ${global:testModulePath} -DocsFolder ${global:DocsFolder} } # read markdown - $renderedMdx = Get-Content (Join-Path -Path ${global:outputFolder} -ChildPath "commands" | Join-Path -ChildPath "Test-$(${global:testModuleName}).mdx") + $renderedMdx = Get-Content (Join-Path -Path ${global:DocsFolder} -ChildPath "commands" | Join-Path -ChildPath "Test-$(${global:testModuleName}).mdx") $expectedMdx = Get-Content (Join-Path -Path $PSScriptRoot -ChildPath "$(${global:testModuleName}).expected.mdx") # make sure output is identical @@ -41,4 +41,4 @@ Describe "Integration Test to ensure all supported Code Example variants render # ----------------------------------------------------------------------------- # cleanup # ----------------------------------------------------------------------------- -Remove-Item ${global:outputFolder} -Recurse -Force +Remove-Item ${global:DocsFolder} -Recurse -Force diff --git a/Tests/Integration/Powershell7NativeMultiLineCode.Tests.ps1 b/Tests/Integration/Powershell7NativeMultiLineCode.Tests.ps1 index 5c650d67..3f259ee0 100644 --- a/Tests/Integration/Powershell7NativeMultiLineCode.Tests.ps1 +++ b/Tests/Integration/Powershell7NativeMultiLineCode.Tests.ps1 @@ -31,13 +31,13 @@ Import-Module ${global:testModulePath} -Force -DisableNameChecking -Verbose:$Fal Describe "Integration Test to ensure Powershell 7's Native Multi-Line Code Examples render as expected" { # render the markdown - ${global:outputFolder} = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ${global:testModuleName} + ${global:DocsFolder} = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ${global:testModuleName} InModuleScope Alt3.Docusaurus.Powershell { - New-DocusaurusHelp -Module ${global:testModulePath} -OutputFolder ${global:outputFolder} + New-DocusaurusHelp -Module ${global:testModulePath} -DocsFolder ${global:DocsFolder} } # read markdown - $renderedMdx = Get-Content (Join-Path -Path ${global:outputFolder} -ChildPath "commands" | Join-Path -ChildPath "Test-$(${global:testModuleName}).mdx") + $renderedMdx = Get-Content (Join-Path -Path ${global:DocsFolder} -ChildPath "commands" | Join-Path -ChildPath "Test-$(${global:testModuleName}).mdx") $expectedMdx = Get-Content (Join-Path -Path $PSScriptRoot -ChildPath "$(${global:testModuleName}).expected.mdx") # make sure output is identical @@ -49,4 +49,4 @@ Describe "Integration Test to ensure Powershell 7's Native Multi-Line Code Examp # ----------------------------------------------------------------------------- # cleanup # ----------------------------------------------------------------------------- -Remove-Item ${global:outputFolder} -Recurse -Force +Remove-Item ${global:DocsFolder} -Recurse -Force diff --git a/docusaurus/docs/commands/New-DocusaurusHelp.mdx b/docusaurus/docs/commands/New-DocusaurusHelp.mdx index a5c74c51..952cfdea 100644 --- a/docusaurus/docs/commands/New-DocusaurusHelp.mdx +++ b/docusaurus/docs/commands/New-DocusaurusHelp.mdx @@ -20,7 +20,7 @@ Generates Get-Help documentation in Docusaurus compatible `.mdx` format. ## SYNTAX ```powershell -New-DocusaurusHelp [-Module] [[-OutputFolder] ] [[-Sidebar] ] [[-Exclude] ] +New-DocusaurusHelp [-Module] [[-DocsFolder] ] [[-Sidebar] ] [[-Exclude] ] [[-MetaDescription] ] [[-MetaKeywords] ] [[-EditUrl] ] [-HideTitle] [-HideTableOfContents] [-Monolithic] [] ``` @@ -46,7 +46,7 @@ the Alt3.Docusaurus.Powershell module. ```powershell $arguments = @{ Module = "Alt3.Docusaurus.Powershell" - OutputFolder = "D:\my-project\docs" + DocsFolder = "D:\my-project\docs" SideBar = "commands" Exclude = @( "Get-SomeCommand" @@ -84,8 +84,8 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -OutputFolder -Specifies the folder where the Docusaurus sidebar subfolder will be created. +### -DocsFolder +Specifies the Docusaurus `docs` folder in which the sidebar folder will be created. Optional, defaults to `docusaurus/docs`, case sensitive. diff --git a/docusaurus/docs/faq/ci-cd.md b/docusaurus/docs/faq/ci-cd.md index 77cd2ad3..f65a4d65 100644 --- a/docusaurus/docs/faq/ci-cd.md +++ b/docusaurus/docs/faq/ci-cd.md @@ -24,7 +24,7 @@ Import-Module Pester -NoClobber -Force $arguments = @{ Module = "Pester" - OutputFolder = "./docs" + DocsFolder = "./docs" SideBar = "commands" Exclude = @( "Get-MockDynamicParameter" @@ -41,12 +41,6 @@ $arguments = @{ ) } -Write-Host "Removing existing files" -ForegroundColor Magenta -$outputFolder = Join-Path -Path $arguments.OutputFolder -ChildPath $arguments.Sidebar | Join-Path -ChildPath "*.*" -if (Test-Path -Path $outputFolder) { - Remove-Item -Path $outputFolder -} - Write-Host "Generating Command Reference" -ForegroundColor Magenta New-DocusaurusHelp @arguments From 1aeb6d22a90bd7fc7280cbe7851f7bdaf9515fae Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Sun, 29 Dec 2019 13:24:47 +0100 Subject: [PATCH 23/29] docs: more logical order of command line arguments/Parameters --- Source/Public/New-DocusaurusHelp.ps1 | 8 ++--- .../docs/commands/New-DocusaurusHelp.mdx | 34 +++++++++---------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Source/Public/New-DocusaurusHelp.ps1 b/Source/Public/New-DocusaurusHelp.ps1 index 9aaf3330..cfec6a54 100644 --- a/Source/Public/New-DocusaurusHelp.ps1 +++ b/Source/Public/New-DocusaurusHelp.ps1 @@ -24,7 +24,7 @@ function New-DocusaurusHelp() { $arguments = @{ Module = "Alt3.Docusaurus.Powershell" DocsFolder = "D:\my-project\docs" - SideBar = "commands" + Sidebar = "commands" Exclude = @( "Get-SomeCommand" ) @@ -48,12 +48,12 @@ function New-DocusaurusHelp() { You may specify a module name, a `.psd1` file or a `.psm1` file. .PARAMETER DocsFolder - Specifies the Docusaurus `docs` folder in which the sidebar folder will be created. + Specifies the absolute or relative **path** to the Docusaurus `docs` folder. Optional, defaults to `docusaurus/docs`, case sensitive. .PARAMETER Sidebar - Specifies the subfolder where the Get-Help `.mdx` files for the module will be created. + Specifies the **name** of the docs subfolder in which the `.mdx` files will be created. Optional, defaults to `commands`, case sensitive. @@ -103,9 +103,9 @@ function New-DocusaurusHelp() { [Parameter(Mandatory = $False)][string]$DocsFolder = "docusaurus/docs", [Parameter(Mandatory = $False)][string]$Sidebar = "commands", [Parameter(Mandatory = $False)][array]$Exclude = @(), + [Parameter(Mandatory = $False)][string]$EditUrl, [Parameter(Mandatory = $False)][string]$MetaDescription, [Parameter(Mandatory = $False)][array]$MetaKeywords = @(), - [Parameter(Mandatory = $False)][string]$EditUrl, [switch]$HideTitle, [switch]$HideTableOfContents, [switch]$Monolithic diff --git a/docusaurus/docs/commands/New-DocusaurusHelp.mdx b/docusaurus/docs/commands/New-DocusaurusHelp.mdx index 952cfdea..b0d6d93f 100644 --- a/docusaurus/docs/commands/New-DocusaurusHelp.mdx +++ b/docusaurus/docs/commands/New-DocusaurusHelp.mdx @@ -21,7 +21,7 @@ Generates Get-Help documentation in Docusaurus compatible `.mdx` format. ```powershell New-DocusaurusHelp [-Module] [[-DocsFolder] ] [[-Sidebar] ] [[-Exclude] ] - [[-MetaDescription] ] [[-MetaKeywords] ] [[-EditUrl] ] [-HideTitle] + [[-EditUrl] ] [[-MetaDescription] ] [[-MetaKeywords] ] [-HideTitle] [-HideTableOfContents] [-Monolithic] [] ``` @@ -47,7 +47,7 @@ the Alt3.Docusaurus.Powershell module. $arguments = @{ Module = "Alt3.Docusaurus.Powershell" DocsFolder = "D:\my-project\docs" - SideBar = "commands" + Sidebar = "commands" Exclude = @( "Get-SomeCommand" ) @@ -85,7 +85,7 @@ Accept wildcard characters: False ``` ### -DocsFolder -Specifies the Docusaurus `docs` folder in which the sidebar folder will be created. +Specifies the absolute or relative **path** to the Docusaurus `docs` folder. Optional, defaults to `docusaurus/docs`, case sensitive. @@ -102,7 +102,7 @@ Accept wildcard characters: False ``` ### -Sidebar -Specifies the subfolder where the Get-Help `.mdx` files for the module will be created. +Specifies the **name** of the docs subfolder in which the `.mdx` files will be created. Optional, defaults to `commands`, case sensitive. @@ -133,10 +133,10 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -MetaDescription -Optional string that will be inserted into Docusaurus front matter to be used as html meta tag 'description'. +### -EditUrl +Specifies the URL prefixed to all Docusaurus `custom_edit_url` front matter variables. -If placeholder `%1` is detected in the string, it will be replaced by the command name. +Optional, defaults to `null`. ```yaml Type: String @@ -150,34 +150,34 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -MetaKeywords -Optional array of keywords inserted into Docusaurus front matter to be used as html meta tag `keywords`. +### -MetaDescription +Optional string that will be inserted into Docusaurus front matter to be used as html meta tag 'description'. + +If placeholder `%1` is detected in the string, it will be replaced by the command name. ```yaml -Type: Array +Type: String Parameter Sets: (All) Aliases: Required: False Position: 6 -Default value: @() +Default value: None Accept pipeline input: False Accept wildcard characters: False ``` -### -EditUrl -Specifies the URL prefixed to all Docusaurus `custom_edit_url` front matter variables. - -Optional, defaults to `null`. +### -MetaKeywords +Optional array of keywords inserted into Docusaurus front matter to be used as html meta tag `keywords`. ```yaml -Type: String +Type: Array Parameter Sets: (All) Aliases: Required: False Position: 7 -Default value: None +Default value: @() Accept pipeline input: False Accept wildcard characters: False ``` From 838d0f6744508c1eb83a10aecf116ca717d30bd8 Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Sun, 29 Dec 2019 14:08:41 +0100 Subject: [PATCH 24/29] docs: use ps moniker as default, describe limitations of PS7 Native Multi-Line --- docusaurus/docs/faq/multi-line-examples.md | 42 ++++++++++++---------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/docusaurus/docs/faq/multi-line-examples.md b/docusaurus/docs/faq/multi-line-examples.md index a9278341..cb3399ec 100644 --- a/docusaurus/docs/faq/multi-line-examples.md +++ b/docusaurus/docs/faq/multi-line-examples.md @@ -20,16 +20,18 @@ Powershell's Comment Based Help was originally designed for `.EXAMPLE` nodes con ## Code Fence Detection Unfortunately these single-line examples no longer suffice as authors are now creating advanced functions -which require **complex multi-lined code examples** to properly inform their end-users. Because Microsoft +which require **complex multi-lined code examples** to properly inform their end-users. + +Because Microsoft does not (and cannot) support these use-cases, Docusaurus comes with `Code Fence Detection`, -allowing you to use common markdown code fences to indicate where your example code block -starts and where it ends. +allowing you to use markdown code fences to indicate where your example code block starts +and where it ends. -A simple example would look similar to: +Code fencing ensures identical rendering across all Powershell versions and looks similar to: ``` .EXAMPLE - ```powershell + ```ps $description = 'Code Fenced example with a description' $names | Foreach-Object {} { Write-Host 'Indentation and empty newlines within the fenced code block will be respected' @@ -41,7 +43,7 @@ A simple example would look similar to: Your description would start here and: - is treated as markdown - - can also contain fenced code blocks + - could also contain fenced code blocks itself ``` > For more usage examples see @@ -51,28 +53,31 @@ A simple example would look similar to: **Please note** that you may use any of the following commonly used opening fences: - \`\`\` -- \`\`\`powershell -- \`\`\`posh - \`\`\`ps +- \`\`\`posh +- \`\`\`powershell -## Powershell 7 +## Powershell 7 Native Multi-Lines -Even though Powershell 7 ships with native support for multi-line code it only -does so in a limited form as can be seen in this example: +Even though Powershell 7 ships with +[native support for multi-line code examples](https://github.com/PowerShell/platyPS/issues/180#issuecomment-569119138) +it only supports a single use-case as can be seen in this example: ``` .EXAMPLE - $description = 'Powershell 7+ multi-line example with a description' - $description = 'ONLY Powershell 7 will consider all adjacent first lines to be code' - $description = 'Code block ends (and description begins) at the first two newlines` + $exampleType = 'Powershell 7+ multi-line example with a description' + $info = 'PS7 will treat all adjecent lines as code' + $info = 'The code block will end at the first double-newline` - Powershell 7 will use this line, and everything below it, as the description + PS7 will thus use this line, and everything below it, as the description ``` -**You could consider using it instead of Code Fence Detection if:** +You could consider using PS7 multi-lines instead of Code Fence Detection if: + +- you will (only) use Powershell 7 to generate your documentation +- your example code does not contain any empty lines -- you are using Powershell 7 -- your example code does not contain any empty newlines +> Do not use native PS7 multi-lines if you intend to generate/test documentation using other Powershell versions! ## Default Fallback @@ -94,4 +99,3 @@ updating your help to use Code Fence Detection would be the better alternative. ## Additional Information - [Detailed description of the Docusaurus.Powershell determination process](https://github.com/alt3/Docusaurus.Powershell/issues/14#issuecomment-568552556) -- [Confirmation of Powershell 7 native multi-line code](https://github.com/PowerShell/platyPS/issues/180#issuecomment-568877700) From 066e4ea1bf1eda99c4ff0e75976c443471a53012 Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Sun, 29 Dec 2019 14:12:46 +0100 Subject: [PATCH 25/29] docs: usage example improvements --- docusaurus/docs/faq/multiple-modules.md | 4 ++-- docusaurus/docs/usage.md | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docusaurus/docs/faq/multiple-modules.md b/docusaurus/docs/faq/multiple-modules.md index 65bcbb3a..00df6074 100644 --- a/docusaurus/docs/faq/multiple-modules.md +++ b/docusaurus/docs/faq/multiple-modules.md @@ -9,8 +9,8 @@ For example, the following commands would generate module documentation for both `ModuleA` and `ModuleB`, each contained within their own sidebar subfolder. ```powershell -New-DocusaurusHelp -Module "ModuleA" -Sidebar "SidebarA" -EditUrl "http://some.url" -New-DocusaurusHelp -Module "ModuleB" -Sidebar "SidebarB" -EditUrl "http://some.url" +New-DocusaurusHelp -Module "ModuleA" -Sidebar "SidebarA" -EditUrl "http://some.url/ModuleA" +New-DocusaurusHelp -Module "ModuleB" -Sidebar "SidebarB" -EditUrl "http://some.url/ModuleB" ``` After that, `docusaurus/sidebars.js` would need to be updated to include both sidebar specifications. diff --git a/docusaurus/docs/usage.md b/docusaurus/docs/usage.md index f61c7fd2..7cbfbec6 100644 --- a/docusaurus/docs/usage.md +++ b/docusaurus/docs/usage.md @@ -39,14 +39,14 @@ module.exports = { To generate Get-Help pages for any Powershell module run the following command. +> For demo data, replace `YourModuleName` with e.g. `Microsoft.PowerShell.Management` + ```powershell -New-DocusaurusHelp -Module "ModuleName" -EditUrl "http://github.com/your/repo/sources" +New-DocusaurusHelp -Module "YourModuleName" ``` -> For demo data, replace `ModuleName` with e.g. `Microsoft.PowerShell.Management` - -> After the command has completed, the `docusaurus/docs/commands` folder -> should contain one `.mdx` file for each command exported by the Powershell module. +After the command has completed, the `docusaurus/docs/commands` folder +should contain one `.mdx` file for each command exported by the Powershell module. ## Starting the Website From 971d4764bd2e9e6dd72485033d91614a62d6ed3d Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Sun, 29 Dec 2019 17:34:44 +0100 Subject: [PATCH 26/29] fix: stop logging used module versions until we have a rock-solid solution --- Source/Private/InitializeTempFolder.ps1 | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Source/Private/InitializeTempFolder.ps1 b/Source/Private/InitializeTempFolder.ps1 index a3354562..915aa4ba 100644 --- a/Source/Private/InitializeTempFolder.ps1 +++ b/Source/Private/InitializeTempFolder.ps1 @@ -11,6 +11,9 @@ function InitializeTempFolder() { We might even instruct users to send us the files when reporting issues (which would require re-generating using the `-KeepTempFiles` switch). + + .NOTES + Ideally we would also log used module versions for Alt3, PlatyPS and Pester. #> param( [Parameter(Mandatory = $True)][string]$Path @@ -22,11 +25,6 @@ function InitializeTempFolder() { # prepare the debug info Write-Verbose "=> creating debug file" $debugInfo = [ordered]@{ - ModuleVersions = [ordered]@{ - "Alt3.Docusarus.Powershell" = (Get-Module "Alt3.Docusaurus.Powershell").Version - PlatyPs = (Get-Module PlatyPs).Version - Pester = (Get-Module Pester).Version - } PSVersionTable = $PSVersionTable } | ConvertTo-Json From a19ffea76e6e2678b60e74228ff910655d16ad14 Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Sun, 29 Dec 2019 17:35:37 +0100 Subject: [PATCH 27/29] fix: test cases for Powershell 5 --- Source/Private/ReplaceMarkdownCodeBlocks.ps1 | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Source/Private/ReplaceMarkdownCodeBlocks.ps1 b/Source/Private/ReplaceMarkdownCodeBlocks.ps1 index 2f81f212..1f1deb57 100644 --- a/Source/Private/ReplaceMarkdownCodeBlocks.ps1 +++ b/Source/Private/ReplaceMarkdownCodeBlocks.ps1 @@ -25,6 +25,10 @@ function ReplaceMarkdownCodeBlocks() { $regexExtractExamples = [regex]::new('### (EXAMPLE|Example) [0-9][\s\S]*?(?=\n.*?#|$)') $examples = $regexExtractExamples.Matches($content) + if ($examples.Count -eq 0) { + Write-Warning "Unable to find any EXAMPLE nodes. Please check your Get-Help definitions before filing an issue!" + } + # process each EXAMPLE node $examples | ForEach-Object { $example = $_ @@ -34,7 +38,10 @@ function ReplaceMarkdownCodeBlocks() { # https://regex101.com/r/WOQL0l/4 # --------------------------------------------------------------------- $regexPlatyPlaceholderExample = [regex]::new('{{ Add example code here }}') - if ($regexPlatyPlaceholderExample.Matches($example)) { + if ($example -match $regexPlatyPlaceholderExample) { + + Write-Verbose "=> Example 1: PlatyPS Placeholder" + $newExamples += $example return } From c15bd39c2ff14a33cac91f6eb21a2bf33fe7d5fd Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Sun, 29 Dec 2019 17:41:43 +0100 Subject: [PATCH 28/29] test: rename Powershell 7 native multi-line test to PS7NativeMultiLineCode --- ...MultiLineCode.Tests.ps1 => PS7NativeMultiLineCode.Tests.ps1} | 0 ...ineCode.expected.mdx => PS7NativeMultiLineCode.expected.mdx} | 0 ...ell7NativeMultiLineCode.psm1 => PS7NativeMultiLineCode.psm1} | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename Tests/Integration/{Powershell7NativeMultiLineCode.Tests.ps1 => PS7NativeMultiLineCode.Tests.ps1} (100%) rename Tests/Integration/{Powershell7NativeMultiLineCode.expected.mdx => PS7NativeMultiLineCode.expected.mdx} (100%) rename Tests/Integration/{Powershell7NativeMultiLineCode.psm1 => PS7NativeMultiLineCode.psm1} (94%) diff --git a/Tests/Integration/Powershell7NativeMultiLineCode.Tests.ps1 b/Tests/Integration/PS7NativeMultiLineCode.Tests.ps1 similarity index 100% rename from Tests/Integration/Powershell7NativeMultiLineCode.Tests.ps1 rename to Tests/Integration/PS7NativeMultiLineCode.Tests.ps1 diff --git a/Tests/Integration/Powershell7NativeMultiLineCode.expected.mdx b/Tests/Integration/PS7NativeMultiLineCode.expected.mdx similarity index 100% rename from Tests/Integration/Powershell7NativeMultiLineCode.expected.mdx rename to Tests/Integration/PS7NativeMultiLineCode.expected.mdx diff --git a/Tests/Integration/Powershell7NativeMultiLineCode.psm1 b/Tests/Integration/PS7NativeMultiLineCode.psm1 similarity index 94% rename from Tests/Integration/Powershell7NativeMultiLineCode.psm1 rename to Tests/Integration/PS7NativeMultiLineCode.psm1 index afa80fb1..951d1f59 100644 --- a/Tests/Integration/Powershell7NativeMultiLineCode.psm1 +++ b/Tests/Integration/PS7NativeMultiLineCode.psm1 @@ -1,4 +1,4 @@ -function Test-Powershell7NativeMultiLineCode { +function Test-PS7NativeMultiLineCode { <# .SYNOPSIS Dummy module to test Powershell 7 NATIVE multi-line code examples From 9701b3fe7b91bb5a5370a88d4d1a749762d801a4 Mon Sep 17 00:00:00 2001 From: bravo-kernel Date: Sun, 29 Dec 2019 18:32:20 +0100 Subject: [PATCH 29/29] feat: adds the -NoPlaceholderExamples switch and related integration tests --- ...Blocks.ps1 => ReplaceMarkdownExamples.ps1} | 15 +++-- Source/Public/New-DocusaurusHelp.ps1 | 15 +++-- .../PlaceholderExamples.DISABLED.expected.mdx | 30 +++++++++ .../PlaceholderExamples.ENABLED.expected.mdx | 37 +++++++++++ .../Integration/PlaceholderExamples.Tests.ps1 | 66 +++++++++++++++++++ Tests/Integration/PlaceholderExamples.psm1 | 6 ++ .../docs/commands/New-DocusaurusHelp.mdx | 26 ++++++-- 7 files changed, 182 insertions(+), 13 deletions(-) rename Source/Private/{ReplaceMarkdownCodeBlocks.ps1 => ReplaceMarkdownExamples.ps1} (93%) create mode 100644 Tests/Integration/PlaceholderExamples.DISABLED.expected.mdx create mode 100644 Tests/Integration/PlaceholderExamples.ENABLED.expected.mdx create mode 100644 Tests/Integration/PlaceholderExamples.Tests.ps1 create mode 100644 Tests/Integration/PlaceholderExamples.psm1 diff --git a/Source/Private/ReplaceMarkdownCodeBlocks.ps1 b/Source/Private/ReplaceMarkdownExamples.ps1 similarity index 93% rename from Source/Private/ReplaceMarkdownCodeBlocks.ps1 rename to Source/Private/ReplaceMarkdownExamples.ps1 index 1f1deb57..a6274dfb 100644 --- a/Source/Private/ReplaceMarkdownCodeBlocks.ps1 +++ b/Source/Private/ReplaceMarkdownExamples.ps1 @@ -1,7 +1,7 @@ -function ReplaceMarkdownCodeBlocks() { +function ReplaceMarkdownExamples() { <# .SYNOPSIS - Replace PlatyPS generated code blocks. + Replace PlatyPS generated code block examples. .DESCRIPTION Replaces custom fenced code blocks and placeholder examples, otherwise uses PlatyPS generated defaults. @@ -12,7 +12,8 @@ function ReplaceMarkdownCodeBlocks() { https://github.com/alt3/Docusaurus.Powershell/issues/14#issuecomment-568552556 #> param( - [Parameter(Mandatory = $True)][System.IO.FileSystemInfo]$MarkdownFile + [Parameter(Mandatory = $True)][System.IO.FileSystemInfo]$MarkdownFile, + [switch]$NoPlaceHolderExamples ) $content = (Get-Content -Path $MarkdownFile.FullName -Raw).TrimEnd() @@ -40,9 +41,13 @@ function ReplaceMarkdownCodeBlocks() { $regexPlatyPlaceholderExample = [regex]::new('{{ Add example code here }}') if ($example -match $regexPlatyPlaceholderExample) { - Write-Verbose "=> Example 1: PlatyPS Placeholder" + if ($NoPlaceHolderExamples) { + Write-Verbose "=> Example 1: PlatyPS Placeholder (dropping)" + return + } - $newExamples += $example + Write-Verbose "=> Example 1: PlatyPS Placeholder (keeping)" + $newExamples += "$example`n" return } diff --git a/Source/Public/New-DocusaurusHelp.ps1 b/Source/Public/New-DocusaurusHelp.ps1 index cfec6a54..0f1a214d 100644 --- a/Source/Public/New-DocusaurusHelp.ps1 +++ b/Source/Public/New-DocusaurusHelp.ps1 @@ -21,7 +21,7 @@ function New-DocusaurusHelp() { .EXAMPLE ``` - $arguments = @{ + $parameters = @{ Module = "Alt3.Docusaurus.Powershell" DocsFolder = "D:\my-project\docs" Sidebar = "commands" @@ -35,7 +35,7 @@ function New-DocusaurusHelp() { ) } - New-DocusaurusHelp @arguments + New-DocusaurusHelp @parameters ``` This example uses splatting to override default settings. @@ -83,8 +83,14 @@ function New-DocusaurusHelp() { Optional, defaults to `false`. + .PARAMETER NoPlaceholderExamples + By default, Docusaurus will generate a placeholder example if your Get-Help + definition does not contain any `EXAMPLE` nodes. + + You can use this switch to disable that behavior which will result in an empty `EXAMPLES` section. + .PARAMETER Monolithic - Use this optional argument if the Powershell module source is monolithic. + Use this optional parameter if the Powershell module source is monolithic. Will point all `custom_edit_url` front matter variables to the `.psm1` file. @@ -108,6 +114,7 @@ function New-DocusaurusHelp() { [Parameter(Mandatory = $False)][array]$MetaKeywords = @(), [switch]$HideTitle, [switch]$HideTableOfContents, + [switch]$NoPlaceHolderExamples, [switch]$Monolithic ) @@ -174,7 +181,7 @@ function New-DocusaurusHelp() { SetMarkdownFrontMatter @frontmatterArgs RemoveMarkdownHeaderOne -MarkdownFile $mdxFile - ReplaceMarkdownCodeBlocks -MarkdownFile $mdxFile + ReplaceMarkdownExamples -MarkdownFile $mdxFile -NoPlaceholderExamples:$NoPlaceholderExamples SetMarkdownCodeBlockMoniker -MarkdownFile $mdxFile UpdateMarkdownBackticks -MarkdownFile $mdxFile } diff --git a/Tests/Integration/PlaceholderExamples.DISABLED.expected.mdx b/Tests/Integration/PlaceholderExamples.DISABLED.expected.mdx new file mode 100644 index 00000000..fde5e253 --- /dev/null +++ b/Tests/Integration/PlaceholderExamples.DISABLED.expected.mdx @@ -0,0 +1,30 @@ +--- +id: Test-PlaceholderExamples +title: Test-PlaceholderExamples +hide_title: false +hide_table_of_contents: false +--- + +## SYNOPSIS +Dummy module to test PlatyPS generated placeholder examples (and the -NoPlaceholderExamples switch) + +## SYNTAX + +```powershell +Test-PlaceholderExamples +``` + +## DESCRIPTION +{{ Fill in the Description }} + +## EXAMPLES + +## PARAMETERS + +## INPUTS + +## OUTPUTS + +## NOTES + +## RELATED LINKS diff --git a/Tests/Integration/PlaceholderExamples.ENABLED.expected.mdx b/Tests/Integration/PlaceholderExamples.ENABLED.expected.mdx new file mode 100644 index 00000000..665430da --- /dev/null +++ b/Tests/Integration/PlaceholderExamples.ENABLED.expected.mdx @@ -0,0 +1,37 @@ +--- +id: Test-PlaceholderExamples +title: Test-PlaceholderExamples +hide_title: false +hide_table_of_contents: false +--- + +## SYNOPSIS +Dummy module to test PlatyPS generated placeholder examples (and the -NoPlaceholderExamples switch) + +## SYNTAX + +```powershell +Test-PlaceholderExamples +``` + +## DESCRIPTION +{{ Fill in the Description }} + +## EXAMPLES + +### Example 1 +```powershell +PS C:\> {{ Add example code here }} +``` + +{{ Add example description here }} + +## PARAMETERS + +## INPUTS + +## OUTPUTS + +## NOTES + +## RELATED LINKS diff --git a/Tests/Integration/PlaceholderExamples.Tests.ps1 b/Tests/Integration/PlaceholderExamples.Tests.ps1 new file mode 100644 index 00000000..e986b7c1 --- /dev/null +++ b/Tests/Integration/PlaceholderExamples.Tests.ps1 @@ -0,0 +1,66 @@ +<# + .SYNOPSIS + This test ensures: + - PlatyPS generated placeholder examples render as expected on all platforms + - the `-NoPlaceHolderExamples` leads to an empty `EXAMPLES` section +#> + +# ----------------------------------------------------------------------------- +# import the Alt3.Docusaurus.Powershell rendering module +# ----------------------------------------------------------------------------- +if (-not(Get-Module Alt3.Docusaurus.Powershell)) { + Import-Module Alt3.Docusaurus.Powershell -DisableNameChecking -Verbose:$False -Scope Global +} + +# ----------------------------------------------------------------------------- +# import the test module associated with this test +# ----------------------------------------------------------------------------- +${global:testModuleName} = [regex]::replace([System.IO.Path]::GetFileName($PSCommandPath), '.Tests.ps1', '') +${global:testModulePath} = Join-Path -Path $PSScriptRoot -ChildPath "${global:testModuleName}.psm1" +Import-Module ${global:testModulePath} -Force -DisableNameChecking -Verbose:$False -Scope Global + +# ----------------------------------------------------------------------------- +# the actual integration test +# ----------------------------------------------------------------------------- +Describe "Integration Test for PlatyPS generated placeholder examples" { + Context "when using default settings" { + + # render the markdown + ${global:DocsFolder} = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ${global:testModuleName} + InModuleScope Alt3.Docusaurus.Powershell { + New-DocusaurusHelp -Module ${global:testModulePath} -DocsFolder ${global:DocsFolder} + } + + # read markdown + $renderedMdx = Get-Content (Join-Path -Path ${global:DocsFolder} -ChildPath "commands" | Join-Path -ChildPath "Test-$(${global:testModuleName}).mdx") + $expectedMdx = Get-Content (Join-Path -Path $PSScriptRoot -ChildPath "$(${global:testModuleName}).ENABLED.expected.mdx") + + # make sure output is identical + It "renders placeholder markdown that is identical to the markdown found in our static 'ENABLED.expected' mdx file" { + $renderedMdx | Should -BeExactly $expectedMdx + } + } + + Context "when using the -NoPlaceholderExamples switch parameter" { + + # render the markdown + ${global:DocsFolder} = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ${global:testModuleName} + InModuleScope Alt3.Docusaurus.Powershell { + New-DocusaurusHelp -Module ${global:testModulePath} -DocsFolder ${global:DocsFolder} -NoPlaceHolderExamples + } + + # read markdown + $renderedMdx = Get-Content (Join-Path -Path ${global:DocsFolder} -ChildPath "commands" | Join-Path -ChildPath "Test-$(${global:testModuleName}).mdx") + $expectedMdx = Get-Content (Join-Path -Path $PSScriptRoot -ChildPath "$(${global:testModuleName}).DISABLED.expected.mdx") + + # make sure output is identical + It "renders empty EXAMPLES section markdown that is identical to the markdown found in our static 'DISABLED.expected' mdx file" { + $renderedMdx | Should -BeExactly $expectedMdx + } + } +} + +# ----------------------------------------------------------------------------- +# cleanup +# ----------------------------------------------------------------------------- +Remove-Item ${global:DocsFolder} -Recurse -Force diff --git a/Tests/Integration/PlaceholderExamples.psm1 b/Tests/Integration/PlaceholderExamples.psm1 new file mode 100644 index 00000000..9a6281da --- /dev/null +++ b/Tests/Integration/PlaceholderExamples.psm1 @@ -0,0 +1,6 @@ +function Test-PlaceholderExamples { +<# + .SYNOPSIS + Dummy module to test PlatyPS generated placeholder examples (and the -NoPlaceholderExamples switch) +#> +} diff --git a/docusaurus/docs/commands/New-DocusaurusHelp.mdx b/docusaurus/docs/commands/New-DocusaurusHelp.mdx index b0d6d93f..a72d929d 100644 --- a/docusaurus/docs/commands/New-DocusaurusHelp.mdx +++ b/docusaurus/docs/commands/New-DocusaurusHelp.mdx @@ -22,7 +22,7 @@ Generates Get-Help documentation in Docusaurus compatible `.mdx` format. ```powershell New-DocusaurusHelp [-Module] [[-DocsFolder] ] [[-Sidebar] ] [[-Exclude] ] [[-EditUrl] ] [[-MetaDescription] ] [[-MetaKeywords] ] [-HideTitle] - [-HideTableOfContents] [-Monolithic] [] + [-HideTableOfContents] [-NoPlaceHolderExamples] [-Monolithic] [] ``` ## DESCRIPTION @@ -44,7 +44,7 @@ the Alt3.Docusaurus.Powershell module. ### EXAMPLE 2 ```powershell -$arguments = @{ +$parameters = @{ Module = "Alt3.Docusaurus.Powershell" DocsFolder = "D:\my-project\docs" Sidebar = "commands" @@ -58,7 +58,7 @@ $arguments = @{ ) } -New-DocusaurusHelp @arguments +New-DocusaurusHelp @parameters ``` This example uses splatting to override default settings. @@ -216,8 +216,26 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -NoPlaceHolderExamples +By default, Docusaurus will generate a placeholder example if your Get-Help +definition does not contain any `EXAMPLE` nodes. + +You can use this switch to disable that behavior which will result in an empty `EXAMPLES` section. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: False +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -Monolithic -Use this optional argument if the Powershell module source is monolithic. +Use this optional parameter if the Powershell module source is monolithic. Will point all `custom_edit_url` front matter variables to the `.psm1` file.