Skip to content

Multiline yaml #756

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 28 additions & 24 deletions src/MarkdownReader/CommandHelpMarkdownReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
using Markdig.Syntax.Inlines;
using Microsoft.PowerShell.PlatyPS.MarkdownWriter;
using Microsoft.PowerShell.PlatyPS.Model;
using Markdig.Renderers;
using System.Collections;

namespace Microsoft.PowerShell.PlatyPS
{
Expand Down Expand Up @@ -198,7 +198,7 @@ internal static CommandHelp GetCommandHelpFromMarkdown(ParsedMarkdownContent mar

CommandHelp commandHelp;

OrderedDictionary? metadata = GetMetadata(markdownContent.Ast);
OrderedDictionary? metadata = GetMetadata(markdownContent);
if (metadata is null)
{
throw new InvalidDataException($"No metadata found in {markdownContent.FilePath}");
Expand Down Expand Up @@ -327,8 +327,9 @@ internal static CommandHelp GetCommandHelpFromMarkdown(ParsedMarkdownContent mar

}

internal static OrderedDictionary? GetMetadata(MarkdownDocument ast)
internal static OrderedDictionary? GetMetadata(ParsedMarkdownContent md)
{
var ast = md.Ast;
// The metadata must be the first block in the markdown
if (ast.Count < 2)
{
Expand All @@ -353,33 +354,36 @@ internal static CommandHelp GetCommandHelpFromMarkdown(ParsedMarkdownContent mar
}
else if (ast[2] is Markdig.Syntax.ListBlock && ast[1] is ParagraphBlock paragraphWithList)
{
List<string> listItems = new();

if (ast[2] is Markdig.Syntax.ListBlock listBlock)
if (paragraphWithList.Inline?.FirstChild is LiteralInline metadataAsParagraph)
{
foreach (var listItem in listBlock)
var metadataDictionary = ConvertTextToOrderedDictionary(metadataAsParagraph.Content.Text);

StringBuilder? sb = null;

try
{
if (listItem is ListItemBlock listItemBlock)
sb = Constants.StringBuilderPool.Get();
int startIndex = ast[2].Line - 1; // -1 because we are 0 based
int endIndex = ast[3].Line;
for (int i = startIndex; i < endIndex; i++)
{
sb.AppendLine(md.MarkdownLines[i].TrimEnd());
}
string blockContent = sb.ToString().Replace("\r", "").Trim();

foreach(DictionaryEntry kv in ConvertTextToOrderedDictionary(blockContent))
{
if (listItemBlock is ContainerBlock containerBlock)
{
if (containerBlock.LastChild is ParagraphBlock paragraphListItem)
{
if (paragraphListItem.Inline?.FirstChild is LiteralInline listItemText)
{
listItems.Add(listItemText.Content.ToString().Trim());
}
}
}
metadataDictionary[kv.Key] = kv.Value;
}
}
finally
{
if (sb is not null)
{
Constants.StringBuilderPool.Return(sb);
}
}
}

if (paragraphWithList.Inline?.FirstChild is LiteralInline metadataAsParagraph)
{
var metadataDictionary = ConvertTextToOrderedDictionary(metadataAsParagraph.Content.Text);
// update the metadata dictionary with the list items of aliases
metadataDictionary["aliases"] = listItems;
return metadataDictionary;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/MarkdownReader/MarkdownProbeInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public MarkdownProbeInfo(string filePath)
FilePath = filePath;
DiagnosticMessages = new();
MarkdownContent = ParsedMarkdownContent.ParseFile(filePath);
MetaData = MarkdownConverter.GetMetadata(MarkdownContent.Ast);
MetaData = MarkdownConverter.GetMetadata(MarkdownContent);
DetermineContentType();
}

Expand Down
6 changes: 3 additions & 3 deletions src/MarkdownReader/ModuleFileMarkdownReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ internal static ModuleFileInfo GetModuleFileInfoFromMarkdown(ParsedMarkdownConte
*/

ModuleFileInfo moduleFileInfo = new();
OrderedDictionary? metadata = GetMetadata(markdownContent.Ast);
OrderedDictionary? metadata = GetMetadata(markdownContent);
if (metadata is null)
{
throw new InvalidDataException("null metadata");
Expand Down Expand Up @@ -151,7 +151,7 @@ internal static string GetModuleFileTitleFromMarkdown(ParsedMarkdownContent md,
return string.Empty;
}

var titleString = titleBlock.Inline?.FirstChild?.ToString().Trim();
var titleString = titleBlock.Inline?.FirstChild?.ToString().Trim();
if (titleString is null)
{
diagnostics.Add(new DiagnosticMessage(DiagnosticMessageSource.ModuleFileTitle, "Null title", DiagnosticSeverity.Error, "GetModuleFileTitle", -1));
Expand Down Expand Up @@ -190,7 +190,7 @@ internal static string GetModuleFileDescriptionFromMarkdown(ParsedMarkdownConten
}

/// <summary>
/// Read the module file looking for
/// Read the module file looking for
/// "### [name](markdownfile.md)
/// Description
/// </summary>
Expand Down
6 changes: 6 additions & 0 deletions test/Pester/ImportMarkdownCommandHelp.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ Describe 'Import-MarkdownCommandHelp Tests' {
BeforeAll {
$result = Import-MarkdownCommandHelp -Path $goodMarkdownPath
$metadata = $result.GetType().GetProperty('Metadata', [System.Reflection.BindingFlags]'Public,NonPublic,Instance').GetValue($result, $null)

$md = Import-MarkdownModuleFile -Path "$assetdir/CimCmdlets2.md"
}

It 'Should be a valid CommandHelp object' {
Expand Down Expand Up @@ -59,6 +61,10 @@ Describe 'Import-MarkdownCommandHelp Tests' {
$result.Metadata.aliases[1] | Should -Be "ls"
$result.Metadata.aliases[2] | Should -Be "gci"
}

It 'Should be able to read multiline metadata' {
$md.Metadata['foo'] | Should -Be "bar"
}
}

Context "Validate Aliases" {
Expand Down
2 changes: 1 addition & 1 deletion test/Pester/ImportMarkdownModuleFile.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Describe "Import-ModuleFile tests" {
Context "File creation" {
It "Should be able to read module files" {
$results = $modFiles.FullName | Import-MarkdownModuleFile
$results.Count | Should -Be 13
$results.Count | Should -Be 14
}

It "Should produce the correct type of object" {
Expand Down
4 changes: 2 additions & 2 deletions test/Pester/MeasurePlatyPSMarkdown.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ Describe "Export-MarkdownModuleFile" {
It "Should identify all the '<fileType>' assets" -TestCases @(
@{ fileType = "unknown"; expectedCount = 2 }
@{ fileType = "CommandHelp"; expectedCount = 40 }
@{ fileType = "ModuleFile"; expectedCount = 14 }
@{ fileType = "V1Schema"; expectedCount = 49 }
@{ fileType = "ModuleFile"; expectedCount = 15 }
@{ fileType = "V1Schema"; expectedCount = 50 }
@{ fileType = "V2Schema"; expectedCount = 5 }
) {
param ($fileType, $expectedCount)
Expand Down
80 changes: 80 additions & 0 deletions test/Pester/assets/CimCmdlets2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
Download Help Link: https://aka.ms/powershell74-help
Help Version: 7.4.0.0
Locale: en-US
Module Guid: fb6cc51d-c096-4b38-b78d-0fed6277096a
Module Name: CimCmdlets2
ms.date: 02/20/2019
schema: 2.0.0
title: CimCmdlets Module
isPreview: true
foo:
- bar
test: true
---
# CimCmdlets2 Module

## Description

Contains cmdlets that interact with Common Information Model (CIM) Servers like the Windows
Management Instrumentation (WMI) service.

This module is only available on the Windows platform.

## CimCmdlets Cmdlets

### [Export-BinaryMiLog](Export-BinaryMiLog.md)

Creates a binary encoded representation of an object or objects and stores it in a file.

### [Get-CimAssociatedInstance](Get-CimAssociatedInstance.md)

Retrieves the CIM instances that are connected to a specific CIM instance by an association.

### [Get-CimClass](Get-CimClass.md)

Gets a list of CIM classes in a specific namespace.

### [Get-CimInstance](Get-CimInstance.md)

Gets the CIM instances of a class from a CIM server.

### [Get-CimSession](Get-CimSession.md)

Gets the CIM session objects from the current session.

### [Import-BinaryMiLog](Import-BinaryMiLog.md)

Used to re-create the saved objects based on the contents of an export file.

### [Invoke-CimMethod](Invoke-CimMethod.md)

Invokes a method of a CIM class.

### [New-CimInstance](New-CimInstance.md)

Creates a CIM instance.

### [New-CimSession](New-CimSession.md)

Creates a CIM session.

### [New-CimSessionOption](New-CimSessionOption.md)

Specifies advanced options for the `New-CimSession` cmdlet.

### [Register-CimIndicationEvent](Register-CimIndicationEvent.md)

Subscribes to indications using a filter expression or a query expression.

### [Remove-CimInstance](Remove-CimInstance.md)

Removes a CIM instance from a computer.

### [Remove-CimSession](Remove-CimSession.md)

Removes one or more CIM sessions.

### [Set-CimInstance](Set-CimInstance.md)

Modifies a CIM instance on a CIM server by calling the **ModifyInstance** method of the CIM class.