Skip to content

Commit 2d50603

Browse files
Measure-PSMDLinesOfCode
1 parent f1e2935 commit 2d50603

File tree

13 files changed

+304
-1
lines changed

13 files changed

+304
-1
lines changed

PSModuleDevelopment/PSModuleDevelopment.psd1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
'Import-PSMDModuleDebug',
7676
'Invoke-PSMDTemplate',
7777
'Measure-PSMDCommandEx',
78+
'Measure-PSMDLinesOfCode',
7879
'New-PSMDDotNetProject',
7980
'New-PSMDHeader',
8081
'New-PSMDFormatTableDefinition',
0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.

PSModuleDevelopment/bin/PSModuleDevelopment.xml

Lines changed: 30 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

PSModuleDevelopment/changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Changelog
22
##
33
- New: Format-PSMDParameter - updates legacy parameter notation
4+
- New: Measure-PSMDLinesOfCode - Measures the lines of code in a scriptfile.
45
- New: Search-PSMDPropertyValue - search objects for values in properties
56
- Upd: Template PSFTest - adding WMI commands to list of forbidden commands
67
- Upd: Template PSFModule - adding changelog
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@{
2+
'MeasurePSMDLinesOfCode.Processing' = 'Processing Path: {0}'
3+
}
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
function Measure-PSMDLinesOfCode
2+
{
3+
<#
4+
.SYNOPSIS
5+
Measures the lines of code ina PowerShell scriptfile.
6+
7+
.DESCRIPTION
8+
Measures the lines of code ina PowerShell scriptfile.
9+
This scan uses the AST to figure out how many lines contain actual functional code.
10+
11+
.PARAMETER Path
12+
Path to the files to scan.
13+
Folders will be ignored.
14+
15+
.EXAMPLE
16+
PS C:\> Measure-PSMDLinesOfCode -Path .\script.ps1
17+
18+
Measures the lines of code in the specified file.
19+
20+
.EXAMPLE
21+
PS C:\> Get-ChildItem C:\Scripts\*.ps1 | Measure-PSMDLinesOfCode
22+
23+
Measures the lines of code for every single file in the folder c:\Scripts.
24+
#>
25+
[CmdletBinding()]
26+
param (
27+
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
28+
[Alias('FullName')]
29+
[string[]]
30+
$Path
31+
)
32+
33+
begin
34+
{
35+
#region Utility Functions
36+
function Invoke-AstWalk
37+
{
38+
[CmdletBinding()]
39+
param (
40+
$Ast,
41+
42+
[string[]]
43+
$Command,
44+
45+
[string[]]
46+
$Name,
47+
48+
[string]
49+
$NewName,
50+
51+
[bool]
52+
$IsCommand,
53+
54+
[bool]
55+
$NoAlias,
56+
57+
[switch]
58+
$First
59+
)
60+
61+
#Write-PSFMessage -Level Host -Message "Processing $($Ast.Extent.StartLineNumber) | $($Ast.Extent.File) | $($Ast.GetType().FullName)"
62+
$typeName = $Ast.GetType().FullName
63+
64+
switch ($typeName)
65+
{
66+
'System.Management.Automation.Language.StringConstantExpressionAst'
67+
{
68+
$Ast.Extent.StartLineNumber .. $Ast.Extent.EndLineNumber
69+
}
70+
'System.Management.Automation.Language.IfStatementAst'
71+
{
72+
$Ast.Extent.StartLineNumber
73+
$Ast.Extent.EndLineNumber
74+
75+
foreach ($clause in $Ast.Clauses)
76+
{
77+
Invoke-AstWalk -Ast $clause.Item1 -Command $Command -Name $Name -NewName $NewName -IsCommand $IsCommand
78+
Invoke-AstWalk -Ast $clause.Item2 -Command $Command -Name $Name -NewName $NewName -IsCommand $IsCommand
79+
}
80+
if ($null -ne $Ast.ElseClause)
81+
{
82+
Invoke-AstWalk -Ast $Ast.ElseClause -Command $Command -Name $Name -NewName $NewName -IsCommand $IsCommand
83+
}
84+
}
85+
default
86+
{
87+
if (-not $First)
88+
{
89+
$Ast.Extent.StartLineNumber
90+
$Ast.Extent.EndLineNumber
91+
}
92+
93+
foreach ($property in $Ast.PSObject.Properties)
94+
{
95+
if ($property.Name -eq "Parent") { continue }
96+
if ($null -eq $property.Value) { continue }
97+
98+
if (Get-Member -InputObject $property.Value -Name GetEnumerator -MemberType Method)
99+
{
100+
foreach ($item in $property.Value)
101+
{
102+
if ($item.PSObject.TypeNames -contains "System.Management.Automation.Language.Ast")
103+
{
104+
Invoke-AstWalk -Ast $item -Command $Command -Name $Name -NewName $NewName -IsCommand $IsCommand
105+
}
106+
}
107+
continue
108+
}
109+
110+
if ($property.Value.PSObject.TypeNames -contains "System.Management.Automation.Language.Ast")
111+
{
112+
Invoke-AstWalk -Ast $property.Value -Command $Command -Name $Name -NewName $NewName -IsCommand $IsCommand
113+
}
114+
}
115+
}
116+
}
117+
}
118+
#endregion Utility Functions
119+
}
120+
process
121+
{
122+
#region Process Files
123+
foreach ($fileItem in $Path)
124+
{
125+
Write-PSFMessage -Level VeryVerbose -String MeasurePSMDLinesOfCode.Processing -StringValues $fileItem
126+
foreach ($resolvedPath in (Resolve-PSFPath -Path $fileItem -Provider FileSystem))
127+
{
128+
if ((Get-Item $resolvedPath).PSIsContainer) { continue }
129+
130+
$parsedItem = Read-PSMDScript -Path $resolvedPath
131+
132+
$object = New-Object PSModuleDevelopment.Utility.LinesOfCode -Property @{
133+
Path = $resolvedPath
134+
}
135+
136+
if ($parsedItem.Ast)
137+
{
138+
$object.Ast = $parsedItem.Ast
139+
$object.Lines = Invoke-AstWalk -Ast $parsedItem.Ast -First | Sort-Object -Unique
140+
$object.Count = ($object.Lines | Measure-Object).Count
141+
$object.Success = $true
142+
}
143+
144+
$object
145+
}
146+
}
147+
#endregion Process Files
148+
}
149+
}

PSModuleDevelopment/internal/scripts/preload.ps1

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@ Usually configuration is imported after most of the module has been imported.
55
This module is an exception to this, since a significant amount of its tasks are performed on import.
66
#>
77

8-
foreach ($file in (Get-ChildItem -Path "$PSModuleRoot\internal\configurations"))
8+
foreach ($file in (Get-ChildItem -Path "$script:PSModuleRoot\internal\configurations"))
99
{
1010
. Import-PSMDFile -Path $file.FullName
1111
}
1212
#endregion Configuration
1313

14+
# Load strings
15+
. Import-PSMDFile -Path "$script:PSModuleRoot\internal\scripts\strings.ps1"
16+
1417
#region Ensure Config path exists
1518

1619
# If there is no global override for the config path, use module default path
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
foreach ($resolvedPath in (Resolve-PSFPath -Path "$($script:PSModuleRoot)\en-us\*.psd1"))
2+
{
3+
$data = Import-PowerShellDataFile -Path $resolvedPath
4+
5+
foreach ($key in $data.Keys)
6+
{
7+
[PSFramework.Localization.LocalizationHost]::Write('PSModuleDevelopment', $key, 'en-US', $data[$key])
8+
}
9+
}

PSModuleDevelopment/xml/PSModuleDevelopment.Format.ps1xml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,37 @@
138138
</TableControl>
139139
</View>
140140

141+
<!-- PSModuleDevelopment.Utility.LinesOfCode -->
142+
<View>
143+
<Name>PSModuleDevelopment.Utility.LinesOfCode</Name>
144+
<ViewSelectedBy>
145+
<TypeName>PSModuleDevelopment.Utility.LinesOfCode</TypeName>
146+
</ViewSelectedBy>
147+
<TableControl>
148+
<AutoSize/>
149+
<TableHeaders>
150+
<TableColumnHeader/>
151+
<TableColumnHeader/>
152+
<TableColumnHeader/>
153+
</TableHeaders>
154+
<TableRowEntries>
155+
<TableRowEntry>
156+
<TableColumnItems>
157+
<TableColumnItem>
158+
<PropertyName>Success</PropertyName>
159+
</TableColumnItem>
160+
<TableColumnItem>
161+
<PropertyName>Count</PropertyName>
162+
</TableColumnItem>
163+
<TableColumnItem>
164+
<PropertyName>Path</PropertyName>
165+
</TableColumnItem>
166+
</TableColumnItems>
167+
</TableRowEntry>
168+
</TableRowEntries>
169+
</TableControl>
170+
</View>
171+
141172
<!-- PSModuleDevelopment.Utility.PropertySearchResult -->
142173
<View>
143174
<Name>PSModuleDevelopment.Utility.PropertySearchResult</Name>

0 commit comments

Comments
 (0)