Skip to content

Commit eedeaf0

Browse files
author
Daniel Hughes
committed
Fix DscClass Doc Generation
1 parent 41f267c commit eedeaf0

7 files changed

+420
-17
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
function Get-ClassPropertyCustomAttribute {
2+
[CmdletBinding()]
3+
param (
4+
[Parameter(Mandatory = $true)]
5+
[System.Reflection.CustomAttributeData[]]
6+
$Attributes,
7+
8+
[Parameter(Mandatory = $true)]
9+
[System.String]
10+
$AttributeType
11+
)
12+
13+
process {
14+
return $Attributes | Where-Object {$_.AttributeType.Name -eq $AttributeType}
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
<#
2+
.SYNOPSIS
3+
Returns DSC class resource properties from the provided class or classes.
4+
5+
.DESCRIPTION
6+
Returns DSC class resource properties from the provided class or classes.
7+
8+
.PARAMETER SourcePath
9+
The path to the source folder (in which the child folder 'Classes' exist).
10+
11+
.PARAMETER BuiltModuleScriptFilePath
12+
The path to the built module script file that contains the class.
13+
14+
.PARAMETER ClassName
15+
One or more class names to return properties for.
16+
17+
.EXAMPLE
18+
Get-ClassResourceProperty -ClassName @('myParentClass', 'myClass') -BuiltModuleScriptFilePath '.\output\MyModule\1.0.0\MyModule.psm1' -SourcePath '.\source'
19+
20+
Returns all DSC class resource properties.
21+
#>
22+
function Get-ClassResourcePropertyNew
23+
{
24+
[CmdletBinding()]
25+
[OutputType([System.Collections.Hashtable[]])]
26+
param
27+
(
28+
[Parameter(Mandatory = $true)]
29+
[System.String]
30+
$SourcePath,
31+
32+
# [Parameter(Mandatory = $true)]
33+
# [System.String]
34+
# $BuiltModuleScriptFilePath,
35+
36+
[Parameter(Mandatory = $true)]
37+
[System.Reflection.PropertyInfo[]]
38+
$Properties
39+
40+
41+
)
42+
43+
$resourceProperty = [System.Collections.Hashtable[]] @()
44+
45+
$className = ($dscProperties | Select-Object -Unique DeclaringType).DeclaringType.Name
46+
47+
foreach ($currentClassName in $className)
48+
{
49+
#$dscResourceAst = Get-ClassAst -ClassName $currentClassName -ScriptFile $BuiltModuleScriptFilePath
50+
51+
$classExists = $false
52+
$sourceFilePath = ''
53+
$childPaths = @(
54+
('Classes/???.{0}.ps1' -f $currentClassName)
55+
('Classes/{0}.ps1' -f $currentClassName)
56+
)
57+
58+
foreach ($childPath in $childPaths)
59+
{
60+
$sourceFilePath = Join-Path -Path $SourcePath -ChildPath $childPath
61+
62+
if ((Test-Path -Path $sourceFilePath))
63+
{
64+
$classExists = $true
65+
break
66+
}
67+
}
68+
69+
<#
70+
Skip if the class's source file does not exist. This can happen if the
71+
class uses a parent class from a different module.
72+
#>
73+
if (-not $classExists)
74+
{
75+
continue
76+
}
77+
78+
$dscResourceCommentBasedHelp = Get-CommentBasedHelp -Path $sourceFilePath
79+
80+
# $astFilter = {
81+
# $args[0] -is [System.Management.Automation.Language.PropertyMemberAst] `
82+
# -and $args[0].Attributes.TypeName.Name -eq 'DscProperty'
83+
# }
84+
85+
# $propertyMemberAsts = $dscResourceAst.FindAll($astFilter, $true)
86+
$propertyMembers = $Properties | Where-Object { $_.DeclaringType.Name -eq $currentClassName }
87+
88+
<#
89+
Looping through each resource property to build the resulting
90+
hashtable. Hashtable will be in the format:
91+
92+
@{
93+
Name = <System.String>
94+
State = 'Key' | 'Required' |'Write' | 'Read'
95+
Description = <System.String>
96+
EmbeddedInstance = 'MSFT_Credential' | $null
97+
DataType = 'System.String' | 'System.String[] | etc.
98+
IsArray = $true | $false
99+
ValueMap = @(<System.String> | ...)
100+
}
101+
#>
102+
foreach ($propertyMember in $propertyMembers)
103+
{
104+
Write-Verbose -Message ($script:localizedData.FoundClassResourcePropertyMessage -f $propertyMember.Name, $currentClassName)
105+
106+
$propertyAttribute = @{
107+
Name = $propertyMember.Name
108+
DataType = Get-DscPropertyType -PropertyType $propertyMember.PropertyType
109+
110+
# Always set to null, correct type name is set in DataType.
111+
EmbeddedInstance = $null
112+
113+
# Always set to $false - correct type name is set in DataType.
114+
IsArray = $false
115+
}
116+
117+
$propertyAttribute.State = Get-ClassResourcePropertyState2 -PropertyInfo $propertyMember
118+
119+
$valueMapValues = $null
120+
if ($propertyMember.PropertyType.IsEnum)
121+
{
122+
$valueMapValues = $propertyMember.PropertyType.GetEnumNames()
123+
}
124+
125+
$validateSet = Get-ClassPropertyCustomAttribute -Attributes $propertyMember.CustomAttributes -AttributeType 'ValidateSetAttribute'
126+
if ($validateSet)
127+
{
128+
$valueMapValues = $validateSet.ConstructorArguments.Value.Value
129+
}
130+
131+
if ($valueMapValues)
132+
{
133+
$propertyAttribute.ValueMap = $valueMapValues
134+
}
135+
136+
if ($dscResourceCommentBasedHelp -and $dscResourceCommentBasedHelp.Parameters.Count -gt 0)
137+
{
138+
# The key name must be upper-case for it to match the right item in the list of parameters.
139+
$propertyDescription = $dscResourceCommentBasedHelp.Parameters[$propertyMember.Name.ToUpper()]
140+
141+
if ($propertyDescription)
142+
{
143+
$propertyDescription = Format-Text -Text $propertyDescription -Format @(
144+
'Remove_Blank_Rows_At_End_Of_String',
145+
'Remove_Indentation_From_Blank_Rows',
146+
'Replace_NewLine_With_One_Whitespace',
147+
'Replace_Vertical_Bar_With_One_Whitespace',
148+
'Replace_Multiple_Whitespace_With_One',
149+
'Remove_Whitespace_From_End_Of_String'
150+
)
151+
}
152+
}
153+
else
154+
{
155+
$propertyDescription = ''
156+
}
157+
158+
$propertyAttribute.Description = $propertyDescription
159+
160+
$resourceProperty += $propertyAttribute
161+
}
162+
}
163+
164+
return $resourceProperty
165+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<#
2+
.SYNOPSIS
3+
This function returns the property state value of an class-based DSC
4+
resource property.
5+
6+
.DESCRIPTION
7+
This function returns the property state value of an DSC class-based
8+
resource property.
9+
10+
.PARAMETER Ast
11+
The Abstract Syntax Tree (AST) for class-based DSC resource property.
12+
The passed value must be an AST of the type 'PropertyMemberAst'.
13+
14+
.EXAMPLE
15+
Get-ClassResourcePropertyState -Ast {
16+
[DscResource()]
17+
class NameOfResource {
18+
[DscProperty(Key)]
19+
[string] $KeyName
20+
21+
[NameOfResource] Get() {
22+
return $this
23+
}
24+
25+
[void] Set() {}
26+
27+
[bool] Test() {
28+
return $true
29+
}
30+
}
31+
}.Ast.Find({$args[0] -is [System.Management.Automation.Language.PropertyMemberAst]}, $false)
32+
33+
Returns the property state for the property 'KeyName'.
34+
#>
35+
function Get-ClassResourcePropertyState2
36+
{
37+
[CmdletBinding()]
38+
[OutputType([System.String])]
39+
param
40+
(
41+
[Parameter(Mandatory = $true)]
42+
[System.Reflection.PropertyInfo]
43+
$PropertyInfo
44+
)
45+
46+
<#
47+
Check for Key first since it it possible to use both Key and Mandatory
48+
on a property and in that case we want to return just 'Key'.
49+
#>
50+
# Data lives in $PropertyInfo.CustomProperties.NamedArguments
51+
# Need to check attribute type is correct
52+
# TODO: Need to deal with Attribute = False??
53+
54+
$attributeParams = @{
55+
PropertyAttributes = $PropertyInfo.CustomAttributes
56+
}
57+
58+
if ((Test-ClassPropertyDscAttributeArgument -IsKey @attributeParams))
59+
{
60+
$propertyState = 'Key'
61+
}
62+
elseif ((Test-ClassPropertyDscAttributeArgument -IsMandatory @attributeParams))
63+
{
64+
$propertyState = 'Required'
65+
}
66+
elseif ((Test-ClassPropertyDscAttributeArgument -IsRead @attributeParams))
67+
{
68+
$propertyState = 'Read'
69+
}
70+
elseif ((Test-ClassPropertyDscAttributeArgument -IsWrite @attributeParams))
71+
{
72+
$propertyState = 'Write'
73+
}
74+
75+
return $propertyState
76+
}
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
3+
# takes a System.RuntimeType - a System.Reflection.PropertyInfo .PropertyType
4+
5+
# Check PropertyType.Name = 'Nullable`1'
6+
# Get value from GenericTypeArgument.FullName
7+
8+
# else return FullName
9+
10+
function Get-DscPropertyType
11+
{
12+
[CmdletBinding()]
13+
[OutputType([System.String])]
14+
param (
15+
[Parameter(Mandatory = $true)]
16+
[System.Type]
17+
$PropertyType
18+
)
19+
20+
switch ($PropertyType.Name)
21+
{
22+
'Nullable`1'
23+
{
24+
return $PropertyType.GenericTypeArguments.Name
25+
}
26+
Default
27+
{
28+
return $PropertyType.Name
29+
}
30+
}
31+
}

source/Private/Get-DscResourceSchemaPropertyContent.ps1

+14-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,20 @@ function Get-DscResourceSchemaPropertyContent
5050
$stringArray += '| Parameter | Attribute | DataType | Description | Allowed Values |'
5151
$stringArray += '| --- | --- | --- | --- | --- |'
5252

53-
foreach ($currentProperty in $Property)
53+
# Order the properties
54+
$orderedProperties = @()
55+
$sortOrder = @(
56+
'Key'
57+
'Required'
58+
'Write'
59+
'Read'
60+
)
61+
62+
foreach ($key in $sortOrder) {
63+
$orderedProperties += $Property.GetEnumerator() | Where-Object {$_.State -eq $key} | Sort-Object {$_.Name}
64+
}
65+
66+
foreach ($currentProperty in $orderedProperties)
5467
{
5568
if ($currentProperty.EmbeddedInstance -eq 'MSFT_Credential')
5669
{

source/Private/New-DscClassResourceWikiPage.ps1

+16-16
Original file line numberDiff line numberDiff line change
@@ -92,14 +92,18 @@ function New-DscClassResourceWikiPage
9292
# Looping through each module file (normally just one).
9393
foreach ($builtModuleScriptFile in $builtModuleScriptFiles)
9494
{
95-
$dscResourceAsts = Get-ClassResourceAst -ScriptFile $builtModuleScriptFile.FullName
95+
Import-Module $builtModuleScriptFile.FullName
9696

97-
Write-Verbose -Message ($script:localizedData.FoundClassBasedMessage -f $dscResourceAsts.Count, $builtModuleScriptFile.FullName)
97+
$classesInModule = (Get-Module $builtModuleScriptFile.BaseName).ImplementingAssembly.DefinedTypes | Where-Object { $_.IsClass -and $_.IsPublic }
98+
$dscClassesInModule = $classesInModule | Where-Object {'DscResourceAttribute' -in $_.CustomAttributes.AttributeType.Name}
99+
100+
Write-Verbose -Message ($script:localizedData.FoundClassBasedMessage -f $dscClassesInModule.Count, $builtModuleScriptFile.FullName)
98101

99102
# Looping through each class-based resource.
100-
foreach ($dscResourceAst in $dscResourceAsts)
103+
# TODO: Should this include non Dsc Classes?
104+
foreach ($dscClassInModule in $dscClassesInModule)
101105
{
102-
Write-Verbose -Message ($script:localizedData.GenerateWikiPageMessage -f $dscResourceAst.Name)
106+
Write-Verbose -Message ($script:localizedData.GenerateWikiPageMessage -f $dscClassInModule.Name)
103107

104108
$output = New-Object -TypeName 'System.Text.StringBuilder'
105109

@@ -118,24 +122,20 @@ function New-DscClassResourceWikiPage
118122
}
119123

120124
# Add the documentation for the resource.
121-
$null = $output.AppendLine("# $($dscResourceAst.Name)")
125+
$null = $output.AppendLine("# $($dscClassInModule.Name)")
122126
$null = $output.AppendLine()
123127
$null = $output.AppendLine('## Parameters')
124128
$null = $output.AppendLine()
125129

126-
$sourceFilePath = Join-Path -Path $SourcePath -ChildPath ('Classes/*{0}.ps1' -f $dscResourceAst.Name)
127-
128-
$className = @()
130+
$sourceFilePath = Join-Path -Path $SourcePath -ChildPath ('Classes/*{0}.ps1' -f $dscClassInModule.Name)
129131

130-
if ($dscResourceAst.BaseTypes.Count -gt 0)
131-
{
132-
$className += @($dscResourceAst.BaseTypes.TypeName.Name)
133-
}
132+
$dscProperties = $dscClassInModule.GetProperties() | Where-Object {'DscPropertyAttribute' -in $_.CustomAttributes.AttributeType.Name}
134133

135-
$className += $dscResourceAst.Name
134+
#$className = ($dscProperties | Select-Object -Unique DeclaringType).DeclaringType.Name
136135

137136
# Returns the properties for class and any existing parent class(es).
138-
$resourceProperty = Get-ClassResourceProperty -ClassName $className -SourcePath $SourcePath -BuiltModuleScriptFilePath $builtModuleScriptFile.FullName
137+
$resourceProperty = Get-ClassResourcePropertyNew -Properties $dscProperties -SourcePath $SourcePath
138+
#$resourceProperty = Get-ClassResourcePropertyNew -ClassName $className -SourcePath $SourcePath -BuiltModuleScriptFilePath $builtModuleScriptFile.FullName
139139

140140
$propertyContent = Get-DscResourceSchemaPropertyContent -Property $resourceProperty -UseMarkdown
141141

@@ -156,7 +156,7 @@ function New-DscClassResourceWikiPage
156156
$null = $output.AppendLine($description)
157157
$null = $output.AppendLine()
158158

159-
$examplesPath = Join-Path -Path $SourcePath -ChildPath ('Examples\Resources\{0}' -f $dscResourceAst.Name)
159+
$examplesPath = Join-Path -Path $SourcePath -ChildPath ('Examples\Resources\{0}' -f $dscClassInModule.Name)
160160

161161
$examplesOutput = Get-ResourceExampleAsMarkdown -Path $examplesPath
162162

@@ -165,7 +165,7 @@ function New-DscClassResourceWikiPage
165165
$null = $output.Append($examplesOutput)
166166
}
167167

168-
$outputFileName = '{0}.md' -f $dscResourceAst.Name
168+
$outputFileName = '{0}.md' -f $dscClassInModule.Name
169169

170170
$savePath = Join-Path -Path $OutputPath -ChildPath $outputFileName
171171

0 commit comments

Comments
 (0)