Skip to content

Commit ff1d54a

Browse files
Parse the multiline metadata correctly (#756)
1 parent 069f4d7 commit ff1d54a

File tree

7 files changed

+121
-31
lines changed

7 files changed

+121
-31
lines changed

src/MarkdownReader/CommandHelpMarkdownReader.cs

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
using Markdig.Syntax.Inlines;
1313
using Microsoft.PowerShell.PlatyPS.MarkdownWriter;
1414
using Microsoft.PowerShell.PlatyPS.Model;
15-
using Markdig.Renderers;
15+
using System.Collections;
1616

1717
namespace Microsoft.PowerShell.PlatyPS
1818
{
@@ -198,7 +198,7 @@ internal static CommandHelp GetCommandHelpFromMarkdown(ParsedMarkdownContent mar
198198

199199
CommandHelp commandHelp;
200200

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

328328
}
329329

330-
internal static OrderedDictionary? GetMetadata(MarkdownDocument ast)
330+
internal static OrderedDictionary? GetMetadata(ParsedMarkdownContent md)
331331
{
332+
var ast = md.Ast;
332333
// The metadata must be the first block in the markdown
333334
if (ast.Count < 2)
334335
{
@@ -353,33 +354,36 @@ internal static CommandHelp GetCommandHelpFromMarkdown(ParsedMarkdownContent mar
353354
}
354355
else if (ast[2] is Markdig.Syntax.ListBlock && ast[1] is ParagraphBlock paragraphWithList)
355356
{
356-
List<string> listItems = new();
357-
358-
if (ast[2] is Markdig.Syntax.ListBlock listBlock)
357+
if (paragraphWithList.Inline?.FirstChild is LiteralInline metadataAsParagraph)
359358
{
360-
foreach (var listItem in listBlock)
359+
var metadataDictionary = ConvertTextToOrderedDictionary(metadataAsParagraph.Content.Text);
360+
361+
StringBuilder? sb = null;
362+
363+
try
361364
{
362-
if (listItem is ListItemBlock listItemBlock)
365+
sb = Constants.StringBuilderPool.Get();
366+
int startIndex = ast[2].Line - 1; // -1 because we are 0 based
367+
int endIndex = ast[3].Line;
368+
for (int i = startIndex; i < endIndex; i++)
369+
{
370+
sb.AppendLine(md.MarkdownLines[i].TrimEnd());
371+
}
372+
string blockContent = sb.ToString().Replace("\r", "").Trim();
373+
374+
foreach(DictionaryEntry kv in ConvertTextToOrderedDictionary(blockContent))
363375
{
364-
if (listItemBlock is ContainerBlock containerBlock)
365-
{
366-
if (containerBlock.LastChild is ParagraphBlock paragraphListItem)
367-
{
368-
if (paragraphListItem.Inline?.FirstChild is LiteralInline listItemText)
369-
{
370-
listItems.Add(listItemText.Content.ToString().Trim());
371-
}
372-
}
373-
}
376+
metadataDictionary[kv.Key] = kv.Value;
377+
}
378+
}
379+
finally
380+
{
381+
if (sb is not null)
382+
{
383+
Constants.StringBuilderPool.Return(sb);
374384
}
375385
}
376-
}
377386

378-
if (paragraphWithList.Inline?.FirstChild is LiteralInline metadataAsParagraph)
379-
{
380-
var metadataDictionary = ConvertTextToOrderedDictionary(metadataAsParagraph.Content.Text);
381-
// update the metadata dictionary with the list items of aliases
382-
metadataDictionary["aliases"] = listItems;
383387
return metadataDictionary;
384388
}
385389
}

src/MarkdownReader/MarkdownProbeInfo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public MarkdownProbeInfo(string filePath)
6868
FilePath = filePath;
6969
DiagnosticMessages = new();
7070
MarkdownContent = ParsedMarkdownContent.ParseFile(filePath);
71-
MetaData = MarkdownConverter.GetMetadata(MarkdownContent.Ast);
71+
MetaData = MarkdownConverter.GetMetadata(MarkdownContent);
7272
DetermineContentType();
7373
}
7474

src/MarkdownReader/ModuleFileMarkdownReader.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ internal static ModuleFileInfo GetModuleFileInfoFromMarkdown(ParsedMarkdownConte
3333
*/
3434

3535
ModuleFileInfo moduleFileInfo = new();
36-
OrderedDictionary? metadata = GetMetadata(markdownContent.Ast);
36+
OrderedDictionary? metadata = GetMetadata(markdownContent);
3737
if (metadata is null)
3838
{
3939
throw new InvalidDataException("null metadata");
@@ -151,7 +151,7 @@ internal static string GetModuleFileTitleFromMarkdown(ParsedMarkdownContent md,
151151
return string.Empty;
152152
}
153153

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

192192
/// <summary>
193-
/// Read the module file looking for
193+
/// Read the module file looking for
194194
/// "### [name](markdownfile.md)
195195
/// Description
196196
/// </summary>

test/Pester/ImportMarkdownCommandHelp.Tests.ps1

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ Describe 'Import-MarkdownCommandHelp Tests' {
2424
BeforeAll {
2525
$result = Import-MarkdownCommandHelp -Path $goodMarkdownPath
2626
$metadata = $result.GetType().GetProperty('Metadata', [System.Reflection.BindingFlags]'Public,NonPublic,Instance').GetValue($result, $null)
27+
28+
$md = Import-MarkdownModuleFile -Path "$assetdir/CimCmdlets2.md"
2729
}
2830

2931
It 'Should be a valid CommandHelp object' {
@@ -59,6 +61,10 @@ Describe 'Import-MarkdownCommandHelp Tests' {
5961
$result.Metadata.aliases[1] | Should -Be "ls"
6062
$result.Metadata.aliases[2] | Should -Be "gci"
6163
}
64+
65+
It 'Should be able to read multiline metadata' {
66+
$md.Metadata['foo'] | Should -Be "bar"
67+
}
6268
}
6369

6470
Context "Validate Aliases" {

test/Pester/ImportMarkdownModuleFile.Tests.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Describe "Import-ModuleFile tests" {
99
Context "File creation" {
1010
It "Should be able to read module files" {
1111
$results = $modFiles.FullName | Import-MarkdownModuleFile
12-
$results.Count | Should -Be 13
12+
$results.Count | Should -Be 14
1313
}
1414

1515
It "Should produce the correct type of object" {

test/Pester/MeasurePlatyPSMarkdown.Tests.ps1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ Describe "Export-MarkdownModuleFile" {
1414
It "Should identify all the '<fileType>' assets" -TestCases @(
1515
@{ fileType = "unknown"; expectedCount = 2 }
1616
@{ fileType = "CommandHelp"; expectedCount = 40 }
17-
@{ fileType = "ModuleFile"; expectedCount = 14 }
18-
@{ fileType = "V1Schema"; expectedCount = 49 }
17+
@{ fileType = "ModuleFile"; expectedCount = 15 }
18+
@{ fileType = "V1Schema"; expectedCount = 50 }
1919
@{ fileType = "V2Schema"; expectedCount = 5 }
2020
) {
2121
param ($fileType, $expectedCount)

test/Pester/assets/CimCmdlets2.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
---
2+
Download Help Link: https://aka.ms/powershell74-help
3+
Help Version: 7.4.0.0
4+
Locale: en-US
5+
Module Guid: fb6cc51d-c096-4b38-b78d-0fed6277096a
6+
Module Name: CimCmdlets2
7+
ms.date: 02/20/2019
8+
schema: 2.0.0
9+
title: CimCmdlets Module
10+
isPreview: true
11+
foo:
12+
- bar
13+
test: true
14+
---
15+
# CimCmdlets2 Module
16+
17+
## Description
18+
19+
Contains cmdlets that interact with Common Information Model (CIM) Servers like the Windows
20+
Management Instrumentation (WMI) service.
21+
22+
This module is only available on the Windows platform.
23+
24+
## CimCmdlets Cmdlets
25+
26+
### [Export-BinaryMiLog](Export-BinaryMiLog.md)
27+
28+
Creates a binary encoded representation of an object or objects and stores it in a file.
29+
30+
### [Get-CimAssociatedInstance](Get-CimAssociatedInstance.md)
31+
32+
Retrieves the CIM instances that are connected to a specific CIM instance by an association.
33+
34+
### [Get-CimClass](Get-CimClass.md)
35+
36+
Gets a list of CIM classes in a specific namespace.
37+
38+
### [Get-CimInstance](Get-CimInstance.md)
39+
40+
Gets the CIM instances of a class from a CIM server.
41+
42+
### [Get-CimSession](Get-CimSession.md)
43+
44+
Gets the CIM session objects from the current session.
45+
46+
### [Import-BinaryMiLog](Import-BinaryMiLog.md)
47+
48+
Used to re-create the saved objects based on the contents of an export file.
49+
50+
### [Invoke-CimMethod](Invoke-CimMethod.md)
51+
52+
Invokes a method of a CIM class.
53+
54+
### [New-CimInstance](New-CimInstance.md)
55+
56+
Creates a CIM instance.
57+
58+
### [New-CimSession](New-CimSession.md)
59+
60+
Creates a CIM session.
61+
62+
### [New-CimSessionOption](New-CimSessionOption.md)
63+
64+
Specifies advanced options for the `New-CimSession` cmdlet.
65+
66+
### [Register-CimIndicationEvent](Register-CimIndicationEvent.md)
67+
68+
Subscribes to indications using a filter expression or a query expression.
69+
70+
### [Remove-CimInstance](Remove-CimInstance.md)
71+
72+
Removes a CIM instance from a computer.
73+
74+
### [Remove-CimSession](Remove-CimSession.md)
75+
76+
Removes one or more CIM sessions.
77+
78+
### [Set-CimInstance](Set-CimInstance.md)
79+
80+
Modifies a CIM instance on a CIM server by calling the **ModifyInstance** method of the CIM class.

0 commit comments

Comments
 (0)