PowerShell.PowerLibrary.DataBinder.psm1
#region Variables [psobject]$Constants = @{ DefaultModelName = "Model"; }; #endregion #region DELEGATES [System.Text.RegularExpressions.MatchEvaluator]$SqlParameterMatchEvaluator = { #region Parameters param ( [Parameter(ValueFromPipeline=$true)] [Alias('M')] [ValidateNotNullOrEmpty()] [System.Text.RegularExpressions.Match] ${Match} ) #endregion $Pattern = '@@'; $Replacement = '@'; Write-Debug $Match; RETURN [System.Text.RegularExpressions.Regex]::Replace($Match.Value, $Pattern, $Replacement, [System.Text.RegularExpressions.RegexOptions]::CultureInvariant); }; #endregion #region FUNCTIONS FUNCTION Get-JsonFromDynamicModel { #region Parameters [CmdletBinding()] param ( [Parameter(ValueFromPipeline=$true)] [Alias('M')] [ValidateNotNullOrEmpty()] [string] $Model ) #endregion IF ([System.IO.File]::Exists($Model)) { $Data = [System.IO.File]::ReadAllText($Model); } ELSE { $Data = $Model; } $DataModel = ConvertFrom-Json -InputObject $JSON; RETURN $DataModel; } FUNCTION Get-DataModel { #region Parameters [CmdletBinding()] param ( [Parameter(ValueFromPipeline=$true)] [Alias('M')] [ValidateNotNullOrEmpty()] [string] $Model, [Parameter(ValueFromPipeline = $true)] [Alias('S')] [ValidateNotNullOrEmpty()] [switch] $Silent = $false ) #endregion IF(!$Silent) { Write-Host "Getting Data Model from " -NoNewline -ForegroundColor Cyan; Write-Host $Model -ForegroundColor White; Write-Host "`n"; } IF ([System.IO.File]::Exists($Model)) { $JSON = [System.IO.File]::ReadAllText($Model); } ELSE { $JSON = $Model; } $DataModel = ConvertFrom-Json -InputObject $JSON; RETURN $DataModel; } FUNCTION Get-DataModelHashTable { #region Parameters [CmdletBinding()] param ( [Parameter(ValueFromPipeline=$true)] [Alias('M')] [ValidateNotNullOrEmpty()] [string] $Model, [Parameter(ValueFromPipeline = $true)] [Alias('S')] [ValidateNotNullOrEmpty()] [switch] $Silent = $false ) #endregion $DataModel = Get-DataModel -Model $Model -Silent:$Silent; IF($DataModel -eq $null) { RETURN $null; } IF(!$Silent) { Write-Host "Convert Data Model (" -NoNewline -ForegroundColor Cyan; Write-Host $Model -NoNewline -ForegroundColor White; Write-Host ") into Hash Table" -ForegroundColor Cyan; Write-Host "`n"; } $Value = @{}; $DataModel.psobject.Properties | %{ $Value[$_.Name] = $_.Value; } RETURN $Value; } FUNCTION Get-TemplateFileInfo { #region Parameters [CmdletBinding()] param ( [Parameter(ValueFromPipeline=$true)] [Alias('I')] [ValidateNotNullOrEmpty()] [System.IO.FileInfo] $FileInfo ) #endregion RETURN @{ FoamFileFullName = $FileInfo.FullName; FileFullName = (Join-Path -Path $FileInfo.DirectoryName -ChildPath $FileInfo.BaseName); }; } FUNCTION Get-TemplateFiles { #region Parameters [CmdletBinding()] param ( [Parameter(ValueFromPipeline=$true, Mandatory = $true)] [Alias('P')] [ValidateNotNullOrEmpty()] [string[]] $Path, [Parameter(ValueFromPipeline = $true, Mandatory = $false)] [Alias('extensions')] [string[]] $IncludedExtensions = @('*.foam','*.template'), [Parameter(ValueFromPipeline = $true)] [Alias('S')] [switch] $Silent = $false ) #endregion IF(!$Silent) { Write-Host "Enumerating all template files under the following directory: " -ForegroundColor Cyan; } $Path | %{ IF(!$Silent){ Write-Host "***" $_ -ForegroundColor White; } } IF(!$Silent) { Write-Host "`n"; } RETURN Get-ChildItem -Path $Path -Include $IncludedExtensions -Recurse; } FUNCTION Get-ModelKey { #region Parameters [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true)] [Alias('V')] [ValidateNotNullOrEmpty()] [string] $Value, [Parameter(ValueFromPipeline = $true, Mandatory = $false)] [string] $ModelName = $Constants.DefaultModelName ) #endregion IF([string]::IsNullOrWhiteSpace($ModelName)) { $ModelName = $Constants.DefaultModelName; } $KeyPattern = "@$ModelName."; $Split = [System.Text.RegularExpressions.Regex]::Split($Value, $KeyPattern, [System.Text.RegularExpressions.RegexOptions]::CultureInvariant); IF($Split -ne $null -and $Split.Length -eq 2) { RETURN $Split[1]; } RETURN $Value; } FUNCTION Repair-SqlTemplates { #region Parameters [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true)] [Alias('T')] [ValidateNotNullOrEmpty()] [string] $Template, [Parameter(ValueFromPipeline = $true, Mandatory = $false)] [string] $ModelName = $Constants.DefaultModelName ) #endregion IF([string]::IsNullOrWhiteSpace($ModelName)) { $ModelName = $Constants.DefaultModelName; } $SqlParameterPattern = '@+\w+'; $Template = [System.Text.RegularExpressions.Regex]::Replace($Template, $SqlParameterPattern, $SqlParameterMatchEvaluator, [System.Text.RegularExpressions.RegexOptions]::CultureInvariant); RETURN $Template; } FUNCTION Get-Matches { #region Parameters [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true)] [Alias('T')] [ValidateNotNullOrEmpty()] [string] $Template, [Parameter(ValueFromPipeline = $true, Mandatory = $false)] [string] $ModelName = $Constants.DefaultModelName ) #endregion IF([string]::IsNullOrWhiteSpace($ModelName)) { $ModelName = $Constants.DefaultModelName; } $Template = Repair-SqlTemplates -Template $Template -ModelName $ModelName; $ModelPattern = "@$ModelName.\w+"; $Matches = [System.Text.RegularExpressions.Regex]::Matches($Template, $ModelPattern, [System.Text.RegularExpressions.RegexOptions]::CultureInvariant); RETURN $Matches; } FUNCTION Parse-Template { #region Parameters [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true)] [Alias('T')] [ValidateNotNullOrEmpty()] [string] $Template, [Parameter(ValueFromPipeline = $true)] [Alias('D')] [ValidateNotNullOrEmpty()] [Hashtable] $Data, [Parameter(ValueFromPipeline = $true, Mandatory = $false)] [string] $ModelName = $Constants.DefaultModelName ) #endregion IF([string]::IsNullOrWhiteSpace($ModelName)) { $ModelName = $Constants.DefaultModelName; } $Matches = Get-Matches -ModelName $ModelName -Template $Template; $IsValid = $true; $MissingKeys = @(); $Patterns = [System.Collections.Generic.SortedSet[string]]::new(); FOREACH($Match in $Matches) { IF(!$Patterns.Contains($Match.Value)) { $__ = $Patterns.Add($Match.Value); } } FOREACH($Pattern in $Patterns.Reverse()) { $Key = Get-ModelKey -Value $Pattern -ModelName $ModelName; IF(!$Data.ContainsKey($Key)) { $IsValid = $false; $MissingKeys += $Key; } IF($IsValid) { $Value = $Data[$Key]; IF($Value -eq $null) { $Value = ''; } $Template = [System.Text.RegularExpressions.Regex]::Replace($Template, $Pattern, $Value); } } IF(!$IsValid) { Write-Warning "Data Model DOES NOT match the Template.`r`nModel Properties defined in the Template file must match the properties in the data model."; $MissingKeys | %{ Write-Warning "Data Model Missing Key: $_"; }; RETURN $null; } RETURN $Template; } FUNCTION Get-DataModelKeys { #region Parameters [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true)] [Alias('T')] [ValidateNotNullOrEmpty()] [string] $Template, [Parameter(ValueFromPipeline = $true)] [Alias('D')] [ValidateNotNullOrEmpty()] [Hashtable] $Data, [Parameter(ValueFromPipeline = $true, Mandatory = $false)] [string] $ModelName = $Constants.DefaultModelName ) #endregion IF([string]::IsNullOrWhiteSpace($ModelName)) { $ModelName = $Constants.DefaultModelName; } $Matches = Get-Matches -ModelName $ModelName -Template $Template; $IsValid = $true; $ModelKeys = New-Object 'System.Collections.Generic.HashSet[string]'; FOREACH($Match in $Matches) { $Key = Get-ModelKey -Value $Match.Value -ModelName $ModelName; IF(![string]::IsNullOrEmpty($Key)) { $__ = $ModelKeys.Add($Key); } } RETURN $ModelKeys; } FUNCTION Get-FormattedTemplate { <# .Synopsis Databind all templates as per a certain Data Model. .DESCRIPTION This Function goes through all paths and match against ModelName to data bind all templates from a certain Data Model. .PARAMETER Model The Model of Which templates will be bound against. .PARAMETER ModelName This is Model Name being Used. .PARAMETER Path This is the URL Paths to loop through. .PARAMETER OutputPath This is the Path where to save the Formatted Template. .PARAMETER IncludedExtensions Array of all file extensions need to be looked up. .OUTPUTS System.String. Get-FormattedTemplate returns a the formatted template string. .NOTES This Method Pipes the Formated Template and Saves it in the Output Path if Provided. #> #region Parameters [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true)] [Alias('M')] [ValidateNotNullOrEmpty()] [string] $Model, [Parameter(ValueFromPipeline = $true, Mandatory = $false)] [string] $ModelName, [Parameter(ValueFromPipeline = $true)] [Alias('P')] [ValidateNotNullOrEmpty()] [string] $Path, [Parameter(ValueFromPipeline = $true)] [Alias('Out')] [string] $OutputPath, [Parameter(ValueFromPipeline = $true)] [Alias('S')] [ValidateNotNullOrEmpty()] [switch] $Silent = $false ) #endregion $DataModel = Get-DataModelHashTable -Model $Model -Silent:$Silent; IF($DataModel -eq $null) { Write-Error "Data Model Cannot be NULL." -RecommendedAction "Model must be a VALID JSON"; RETURN; } IF(![System.IO.File]::Exists($Path)) { Write-Error "Could NOT find '$Path' Template file!!!"; RETURN; } IF(!$Silent) { Write-Host "Formatting..." -ForegroundColor Gray; Write-Host "*** From: " -NoNewline -ForegroundColor Yellow; Write-Host $Path -ForegroundColor White; Write-Host "*** To: " -NoNewline -ForegroundColor Yellow; Write-Host $OutputPath -ForegroundColor White; } $Template = [System.IO.File]::ReadAllText($Path); $Template = Parse-Template -Template $Template -Data $DataModel -ModelName $ModelName; IF(!$Silent) { Write-Host "Formatting Result: " -NoNewline -ForegroundColor Gray; } IF(![string]::IsNullOrWhiteSpace($Template) -and ![string]::IsNullOrWhiteSpace($OutputPath)) { IF([System.IO.File]::Exists($OutputPath)) { Set-ItemProperty -Path $OutputPath -Name IsReadOnly -Value $false; } IF(!$Silent) { Write-Host "Template is being saved" -ForegroundColor Green; } $FileInfo = [System.IO.FileInfo]::new($OutputPath); IF(!$FileInfo.Directory.Exists) { $FileInfo.Directory.Create(); } [System.IO.File]::WriteAllText($OutputPath, $Template); } ELSE { IF(!$Silent) { Write-Host "Template is Skipped" -ForegroundColor Red; } } IF(!$Silent) { Write-Host; } RETURN $Template; } FUNCTION Set-DataBinding { <# .Synopsis Databind all templates as per a certain Data Model. .DESCRIPTION This Function goes through all paths and match against ModelName to data bind all templates from a certain Data Model. .PARAMETER Model The Model of Which templates will be bound against. .PARAMETER ModelName This is Model Name being Used. .PARAMETER Path This is the URL Paths to loop through. .PARAMETER IncludedExtensions Array of all file extensions need to be looked up. #> #region Parameters [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true)] [Alias('M')] [ValidateNotNullOrEmpty()] [string] $Model, [Parameter(ValueFromPipeline = $true, Mandatory = $false)] [string] $ModelName, [Parameter(ValueFromPipeline = $true)] [Alias('P')] [ValidateNotNullOrEmpty()] [string[]] $Path, [Parameter(ValueFromPipeline = $true, Mandatory = $false)] [Alias('extensions')] [string[]] $IncludedExtensions = @('*.foam','*.template'), [Parameter(ValueFromPipeline = $true)] [Alias('S')] [ValidateNotNullOrEmpty()] [switch] $Silent = $false ) #endregion $DataModel = Get-DataModelHashTable -Model $Model -Silent:$Silent; IF($DataModel -eq $null) { Write-Error "Data Model Cannot be NULL." -RecommendedAction "Model must be a VALID JSON"; RETURN; } $Templates = Get-TemplateFiles -Path $Path -IncludedExtensions $IncludedExtensions -Silent:$Silent; IF($Templates -eq $null) { Write-Error "Could NOT find any '$([string]::Join(', ', $IncludedExtensions))' file!!!"; RETURN; } IF(!$Silent) { Write-Host "Formatting " -NoNewline -ForegroundColor Cyan; Write-Host $($Templates.Count) -NoNewline -ForegroundColor White; Write-Host " foamed file(s)." -ForegroundColor Cyan; } FOREACH($FI in $Templates) { $Reference = Get-TemplateFileInfo -FileInfo $FI; IF(!$Silent) { Write-Host "Formatting..." -ForegroundColor Gray; Write-Host "*** From: " -NoNewline -ForegroundColor Yellow; Write-Host $($Reference.FoamFileFullName) -ForegroundColor White; Write-Host "*** To: " -NoNewline -ForegroundColor Yellow; Write-Host $($Reference.FileFullName) -ForegroundColor White; } IF([System.IO.File]::Exists($Reference.FileFullName)) { Set-ItemProperty -Path $Reference.FileFullName -Name IsReadOnly -Value $false; } $Template = [System.IO.File]::ReadAllText($Reference.FoamFileFullName); $Template = Parse-Template -Template $Template -Data $DataModel -ModelName $ModelName; IF(!$Silent) { Write-Host "Formatting Result: " -NoNewline -ForegroundColor Gray; } IF(![string]::IsNullOrWhiteSpace($Template)) { IF(!$Silent) { Write-Host "Template is being saved" -ForegroundColor Green; } $FileInfo = [System.IO.FileInfo]::new($Reference.FileFullName); IF(!$FileInfo.Directory.Exists) { $FileInfo.Directory.Create(); } [System.IO.File]::WriteAllText($Reference.FileFullName, $Template); } ELSE { IF(!$Silent) { Write-Host "Template is Skipped" -ForegroundColor Red; } } IF(!$Silent) { Write-Host; } } } FUNCTION Get-DataModelTemplate { <# .Synopsis Generates Data Template Model. .DESCRIPTION This Function goes through all paths and match against ModelName to build up JSON model as a template to be saved in the output Path. .PARAMETER ModelName This is Model Name being Used. .PARAMETER Path This is the URL Paths to loop through. .PARAMETER OutputPath This is the Path where to save the output JSON model. .PARAMETER IncludedExtensions Array of all file extensions need to be looked up. #> #region Parameters [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true, Mandatory = $false)] [string] $ModelName, [Parameter(ValueFromPipeline = $true)] [Alias('P')] [ValidateNotNullOrEmpty()] [string[]] $Path, [Parameter(ValueFromPipeline = $true)] [Alias('Out')] [string] $OutputPath, [Parameter(ValueFromPipeline = $true, Mandatory = $false)] [Alias('extensions')] [string[]] $IncludedExtensions = @('*.foam','*.template'), [Parameter(ValueFromPipeline = $true)] [Alias('S')] [ValidateNotNullOrEmpty()] [switch] $Silent = $false ) #endregion $DataModel = @{}; $Templates = Get-TemplateFiles -Path $Path -IncludedExtensions $IncludedExtensions -Silent:$Silent; IF($Templates -eq $null) { Write-Error "Could NOT find any '$([string]::Join(', ', $IncludedExtensions))' file!!!"; RETURN; } IF(!$Silent) { Write-Host "Getting Data Model Keys from " -NoNewline -ForegroundColor Cyan; Write-Host $($Templates.Count) -NoNewline -ForegroundColor White; Write-Host " foamed file(s)." -ForegroundColor Cyan; } FOREACH($FI in $Templates) { $Reference = Get-TemplateFileInfo -FileInfo $FI; IF(!$Silent) { Write-Host "Getting Data Model Keys..." -ForegroundColor Gray; Write-Host "*** From: " -NoNewline -ForegroundColor Yellow; Write-Host $($Reference.FoamFileFullName) -ForegroundColor White; } $Template = [System.IO.File]::ReadAllText($Reference.FoamFileFullName); Get-DataModelKeys -ModelName $ModelName -Template $Template | %{ $DataModel[$_] = ''; } IF(!$Silent) { Write-Host; } } $JSON = ConvertTo-Json -InputObject $DataModel; IF(![string]::IsNullOrEmpty($OutputPath) -and ![string]::IsNullOrEmpty($JSON)) { IF(![System.IO.Path]::HasExtension($OutputPath)) { $OutputPath = [string]::Concat($OutputPath, '.json'); } $FileInfo = [System.IO.FileInfo]::new($OutputPath); IF(!$FileInfo.Directory.Exists) { $FileInfo.Directory.Create(); } [System.IO.File]::WriteAllText($OutputPath, $JSON); } RETURN $JSON; } #endregion |