Skip to content

Commit ce26dc2

Browse files
Merge pull request #107 from PowershellFrameworkCollective/Export-PSMDString
Adding Export-PSMDString
2 parents b1ab3d6 + 5c10269 commit ce26dc2

File tree

3 files changed

+150
-0
lines changed

3 files changed

+150
-0
lines changed

PSModuleDevelopment/PSModuleDevelopment.psd1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
# Functions to export from this module
6666
FunctionsToExport = @(
6767
'Expand-PSMDTypeName',
68+
'Export-PSMDString',
6869
'Find-PSMDFileContent',
6970
'Find-PSMDType',
7071
'Format-PSMDParameter',

PSModuleDevelopment/changelog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
# Changelog
2+
##
3+
- New: Export-PSMDString - Parses strings from modules using the PSFramework localization feature.
4+
25
## 2.2.6.72 (May 27th, 2019)
36
- New: Template AzureFunction - Creates a basic azure function scaffold
47
- New: Template AzureFunctionTimer - Creates a timer triggered Azure Function
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
function Export-PSMDString
2+
{
3+
<#
4+
.SYNOPSIS
5+
Parses a module that uses the PSFramework localization feature for strings and their value.
6+
7+
.DESCRIPTION
8+
Parses a module that uses the PSFramework localization feature for strings and their value.
9+
This command can be used to generate and update the language files used by the module.
10+
It is also used in automatic tests, ensuring no abandoned string has been left behind and no key is unused.
11+
12+
.PARAMETER ModuleRoot
13+
The root of the module to process.
14+
Must be the root folder where the psd1 file is stored in.
15+
16+
.EXAMPLE
17+
PS C:\> Export-PSMDString -ModuleRoot 'C:\Code\Github\MyModuleProject\MyModule'
18+
19+
Generates the strings data for the MyModule module.
20+
#>
21+
[CmdletBinding()]
22+
param (
23+
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
24+
[Alias('ModuleBase')]
25+
[string]
26+
$ModuleRoot
27+
)
28+
29+
process
30+
{
31+
#region Find Language Files : $languageFiles
32+
$languageFiles = @{ }
33+
$languageFolders = Get-ChildItem -Path $ModuleRoot -Directory | Where-Object Name -match '^\w\w-\w\w$'
34+
foreach ($languageFolder in $languageFolders)
35+
{
36+
$languageFiles[$languageFolder.Name] = @{ }
37+
foreach ($file in (Get-ChildItem -Path $languageFolder.FullName -Filter *.psd1))
38+
{
39+
$languageFiles[$languageFolder.Name] += Import-PSFPowerShellDataFile -Path $file.FullName
40+
}
41+
}
42+
#endregion Find Language Files : $languageFiles
43+
44+
#region Find Keys : $foundKeys
45+
$foundKeys = foreach ($file in (Get-ChildItem -Path $ModuleRoot -Recurse | Where-Object Extension -match '^\.ps1$|^\.psm1$'))
46+
{
47+
$ast = (Read-PSMDScript -Path $file.FullName).Ast
48+
$commandAsts = $ast.FindAll({
49+
if ($args[0] -isnot [System.Management.Automation.Language.CommandAst]) { return $false }
50+
if ($args[0].CommandElements[0].Value -notmatch '^Invoke-PSFProtectedCommand$|^Write-PSFMessage$|^Stop-PSFFunction$') { return $false }
51+
if (-not ($args[0].CommandElements.ParameterName -match '^String$|^ActionString$')) { return $false }
52+
$true
53+
}, $true)
54+
55+
foreach ($commandAst in $commandAsts)
56+
{
57+
$stringParam = $commandAst.CommandElements | Where-Object ParameterName -match '^String$|^ActionString$'
58+
$stringParamValue = $commandAst.CommandElements[($commandAst.CommandElements.IndexOf($stringParam) + 1)].Value
59+
60+
$stringValueParam = $commandAst.CommandElements | Where-Object ParameterName -match '^StringValues$|^ActionStringValues$'
61+
if ($stringValueParam)
62+
{
63+
$stringValueParamValue = $commandAst.CommandElements[($commandAst.CommandElements.IndexOf($stringValueParam) + 1)].Extent.Text
64+
}
65+
else { $stringValueParamValue = '' }
66+
[PSCustomObject]@{
67+
PSTypeName = 'PSModuleDevelopment.String.ParsedItem'
68+
File = $file.FullName
69+
Line = $commandAst.Extent.StartLineNumber
70+
CommandName = $commandAst.CommandElements[0].Value
71+
String = $stringParamValue
72+
StringValues = $stringValueParamValue
73+
}
74+
}
75+
76+
$validateAsts = $ast.FindAll({
77+
if ($args[0] -isnot [System.Management.Automation.Language.AttributeAst]) { return $false }
78+
if ($args[0].TypeName -notmatch '^PsfValidateScript$|^PsfValidatePattern$') { return $false }
79+
if (-not ($args[0].NamedArguments.ArgumentName -eq 'ErrorString')) { return $false }
80+
$true
81+
}, $true)
82+
83+
foreach ($validateAst in $validateAsts)
84+
{
85+
[PSCustomObject]@{
86+
PSTypeName = 'PSModuleDevelopment.String.ParsedItem'
87+
File = $file.FullName
88+
Line = $commandAst.Extent.StartLineNumber
89+
CommandName = '[{0}]' -f $validateAst.TypeName
90+
String = (($validateAst.NamedArguments | Where-Object ArgumentName -eq 'ErrorString').Argument.Value -split "\.", 2)[1] # The first element is the module element
91+
StringValues = '<user input>, <validation item>'
92+
}
93+
}
94+
}
95+
#endregion Find Keys : $foundKeys
96+
97+
#region Report Findings
98+
$totalResults = foreach ($languageFile in $languageFiles.Keys)
99+
{
100+
#region Phase 1: Matching parsed strings to language file
101+
$results = @{ }
102+
foreach ($foundKey in $foundKeys)
103+
{
104+
if ($results[$foundKey.String])
105+
{
106+
$results[$foundKey.String].Entries += $foundKey
107+
continue
108+
}
109+
110+
$results[$foundKey.String] = [PSCustomObject] @{
111+
PSTypeName = 'PSmoduleDevelopment.String.LanguageFinding'
112+
Language = $languageFile
113+
Surplus = $false
114+
String = $foundKey.String
115+
StringValues = $foundKey.StringValues
116+
Text = $languageFiles[$languageFile][$foundKey.String]
117+
Line = "'{0}' = '{1}' # {2}" -f $foundKey.String, $languageFiles[$languageFile][$foundKey.String], $foundKey.StringValues
118+
Entries = @($foundKey)
119+
}
120+
}
121+
$results.Values
122+
#endregion Phase 1: Matching parsed strings to language file
123+
124+
#region Phase 2: Finding unneeded strings
125+
foreach ($key in $languageFiles[$languageFile].Keys)
126+
{
127+
if ($key -notin $foundKeys.String)
128+
{
129+
[PSCustomObject] @{
130+
PSTypeName = 'PSmoduleDevelopment.String.LanguageFinding'
131+
Language = $languageFile
132+
Surplus = $true
133+
String = $key
134+
StringValues = ''
135+
Text = $languageFiles[$languageFile][$key]
136+
Line = ''
137+
Entries = @()
138+
}
139+
}
140+
}
141+
#endregion Phase 2: Finding unneeded strings
142+
}
143+
$totalResults | Sort-Object String
144+
#endregion Report Findings
145+
}
146+
}

0 commit comments

Comments
 (0)