Includes/PwSh.Fw.Object.Bash.psm1

<#
.SYNOPSIS
Converts PowerShell objects to Linux shell-compatible variables
.DESCRIPTION
Converts any PowerShell object (hashtable, array, PSCustomObject, etc.) into Linux shell variables
that can be sourced as a .rc file. Handles different data types appropriately for bash interpretation.
.PARAMETER InputObject
The PowerShell object to convert to shell variables
.PARAMETER Prefix
Optional prefix to add to all variable names
.PARAMETER Export
If specified, adds an 'export' line after each 'declare' line to make variables available to child processes
.PARAMETER Flat
If specified, flattens nested objects instead of creating separate associative arrays
.PARAMETER DateTimeFormat
Format for DateTime values: 'String' (default), 'Timestamp', or 'ISO'
.PARAMETER Strict
If specified, shows warnings when variable names are sanitized
.EXAMPLE
ConvertTo-LinuxShellData -InputObject $data -Prefix "PROJECT"
Converts a hashtable to shell variables with PROJECT_ prefix
.EXAMPLE
ConvertTo-LinuxShellData -InputObject $data -Prefix "PROJECT" -Export
Converts and exports variables for child processes
.EXAMPLE
ConvertTo-LinuxShellData -InputObject $data -Flat
Flattens nested objects into single-level variables
.NOTES
Author: Your Name
Date: 2024
#>

function ConvertTo-LinuxShellData {
    [CmdletBinding()]
    [OutputType([String])]
    Param (
        [parameter(Mandatory, ValueFromPipeline = $True)]
        $InputObject,
        [string]$Prefix = "",
        [switch]$Export,
        [switch]$Flat,
        [ValidateSet('String', 'Timestamp', 'ISO')]
        [string]$DateTimeFormat = 'String',
        [switch]$Strict
    )
    Begin {
        # Write-EnterFunction
    }
    Process {
        $output = @()
        if ($InputObject -is [hashtable]) {
            $output += ConvertTo-BashHashtable -Hashtable $InputObject -Prefix $Prefix -Export:$Export -Flat:$Flat -DateTimeFormat $DateTimeFormat -Strict:$Strict
        } elseif ($InputObject -is [array] -or $InputObject -is [System.Collections.ArrayList]) {
            $varName = Sanitize-VariableName -Name (if ($Prefix) { "${Prefix}_ARRAY" } else { "ARRAY" }) -Strict:$Strict
            $output += ConvertTo-BashArray -Name $varName -Value $InputObject -Export:$Export
        } elseif ($InputObject -is [PSCustomObject]) {
            $output += ConvertTo-BashCustomObject -Object $InputObject -Prefix $Prefix -Export:$Export -Flat:$Flat -DateTimeFormat $DateTimeFormat -Strict:$Strict
        } else {
            $varName = Sanitize-VariableName -Name (if ($Prefix) { "${Prefix}_VALUE" } else { "VALUE" }) -Strict:$Strict
            $output += ConvertTo-BashVariable -Name $varName -Value $InputObject -Export:$Export -DateTimeFormat $DateTimeFormat
        }
        return $output -join "`n"
    }
    End {
        # Write-LeaveFunction
    }
}

<#
.SYNOPSIS
Sanitizes variable names for Linux shell compatibility
.DESCRIPTION
Converts variable names to be compatible with bash naming conventions (uppercase, underscores only, no leading numbers)
.PARAMETER Name
The variable name to sanitize
.PARAMETER Strict
If specified, shows warnings when variable names are modified
.EXAMPLE
Sanitize-VariableName -Name "Project-Name"
Returns: PROJECT_NAME
.NOTES
Author: Your Name
Date: 2024
#>

function Sanitize-VariableName {
    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "", Justification="Sanitize is an intuitive verb for this function.")]
    [CmdletBinding()]
    [OutputType([String])]
    Param (
        [string]$Name,
        [switch]$Strict
    )
    Begin {
        # Write-EnterFunction
    }
    Process {
        # Convert to uppercase and replace invalid characters with underscore
        $sanitized = $Name -replace '[^a-zA-Z0-9]', '_'
        $sanitized = $sanitized -replace '_+', '_'
        $sanitized = $sanitized -replace '^_+', ''
        $sanitized = $sanitized -replace '_+$', ''
        # If starts with number, prepend underscore
        if ($sanitized -match '^[0-9]') {
            $sanitized = "_${sanitized}"
        }
        if ($Strict -and $sanitized -ne $Name) {
            Write-Warning "Variable name '$Name' sanitized to '$sanitized'"
        }
        return $sanitized
    }
    End {
        # Write-LeaveFunction
    }
}

<#
.SYNOPSIS
Converts a single PowerShell value to a bash variable declaration
.DESCRIPTION
Converts a single value (string, int, bool, datetime, etc.) to a bash variable declaration
.PARAMETER Name
The variable name
.PARAMETER Value
The value to convert
.PARAMETER Export
If specified, adds an 'export' line after the declaration
.PARAMETER DateTimeFormat
Format for DateTime values: 'String' (default), 'Timestamp', or 'ISO'
.EXAMPLE
ConvertTo-BashVariable -Name "NAME" -Value "MyProject"
Returns: declare NAME='MyProject'
.NOTES
Author: Your Name
Date: 2024
#>

function ConvertTo-BashVariable {
    [CmdletBinding()]
    [OutputType([String])]
    Param (
        [string]$Name,
        $Value,
        [switch]$Export,
        [ValidateSet('String', 'Timestamp', 'ISO')]
        [string]$DateTimeFormat = 'String'
    )
    Begin {
        # Write-EnterFunction
    }
    Process {
        $name = Sanitize-VariableName -Name $Name
        if ($null -eq $Value) {
            $output = @()
            $output += "declare ${name}="""
            if ($Export) { $output += "export ${name}" }
            return $output -join "`n"
        }
        elseif ($Value -is [bool]) {
            $bashValue = if ($Value) { "true" } else { "false" }
            $output = @()
            $output += "declare ${name}=${bashValue}"
            if ($Export) { $output += "export ${name}" }
            return $output -join "`n"
        }
        elseif ($Value -is [int] -or $Value -is [double] -or $Value -is [decimal]) {
            $output = @()
            $output += "declare ${name}=${Value}"
            if ($Export) { $output += "export ${name}" }
            return $output -join "`n"
        }
        elseif ($Value -is [datetime]) {
            $output = @()
            switch ($DateTimeFormat) {
                'Timestamp' { $output += "declare ${name}=\$(date -d '${Value}' +%s)" }
                'ISO' { $output += "declare ${name}='${Value.ToString("o")}'" }
                default { $output += "declare ${name}='${Value.ToString("yyyy-MM-dd HH:mm:ss")}'" }
            }
            if ($Export) { $output += "export ${name}" }
            return $output -join "`n"
        }
        elseif ($Value -is [string]) {
            $output = @()
            $escaped = Escape-BashString -Value $Value
            $output += "declare ${name}='${escaped}'"
            if ($Export) { $output += "export ${name}" }
            return $output -join "`n"
        }
        elseif ($Value -is [array] -or $Value -is [System.Collections.ArrayList]) {
            return ConvertTo-BashArray -Name $name -Value $Value -Export:$Export
        }
        elseif ($Value -is [hashtable]) {
            return ConvertTo-BashAssociativeArray -Name $name -Value $Value -Export:$Export
        }
        else {
            $strValue = [string]$Value
            $output = @()
            $escaped = Escape-BashString -Value $strValue
            $output += "declare ${name}='${escaped}'"
            if ($Export) { $output += "export ${name}" }
            return $output -join "`n"
        }
    }
    End {
        # Write-LeaveFunction
    }
}

<#
.SYNOPSIS
Converts a PowerShell array to a bash indexed array
.DESCRIPTION
Converts a PowerShell array to a bash indexed array declaration with proper escaping
.PARAMETER Name
The array variable name
.PARAMETER Value
The array to convert
.PARAMETER Export
If specified, adds an 'export' line after the declaration
.EXAMPLE
ConvertTo-BashArray -Name "ITEMS" -Value @("a", "b", "c")
Returns: declare -a ITEMS=([0]='a' [1]='b' [2]='c')
.NOTES
Author: Your Name
Date: 2024
#>

function ConvertTo-BashArray {
    [CmdletBinding()]
    [OutputType([String])]
    Param (
        [string]$Name,
        [array]$Value,
        [switch]$Export
    )
    Begin {
        # Write-EnterFunction
    }
    Process {
        $name = Sanitize-VariableName -Name $Name
        # Write-Devel "name = $name"
        if ($Value.Count -eq 0) {
            $output = @()
            $output += "declare -a ${name}=()"
            if ($Export) { $output += "export ${name}" }
            return $output -join "`n"
        }
        $elements = @()
        $i=0
        foreach ($item in $Value) {
            # Write-Devel "item = $item"
            $element = "[$(($i++))]="
            if ($null -eq $item) {
                $element += '""'
            }
            elseif ($item -is [int]) {
                $element += "${item}"
            }
            elseif ($item -is [string]) {
                $escaped = Escape-BashString -Value $item
                $element += "'${escaped}'"
            }
            else {
                $strItem = [string]$item
                $escaped = Escape-BashString -Value $strItem
                $element += "'${escaped}'"
            }
            $elements += $element
            # Write-Devel "escaped = $escaped"
        }
        $output = @()
        $output += "declare -a ${name}=($($elements -join ' '))"
        if ($Export) { $output += "export ${name}" }
        return $output -join "`n"
    }
    End {
        # Write-LeaveFunction
    }
}

<#
.SYNOPSIS
Converts a PowerShell hashtable to a bash associative array
.DESCRIPTION
Converts a PowerShell hashtable to a bash associative array declaration with proper escaping
.PARAMETER Name
The associative array variable name
.PARAMETER Value
The hashtable to convert
.PARAMETER Export
If specified, adds an 'export' line after the declaration
.EXAMPLE
ConvertTo-BashAssociativeArray -Name "CONFIG" -Value @{Port=8080; Host="localhost"}
Returns: declare -A CONFIG=('Port'=8080 'Host'='localhost')
.NOTES
Author: Your Name
Date: 2024
#>

function ConvertTo-BashAssociativeArray {
    [CmdletBinding()]
    [OutputType([String])]
    Param (
        [string]$Name,
        [hashtable]$Value,
        [switch]$Export
    )
    Begin {
        # Write-EnterFunction
    }
    Process {
        $name = Sanitize-VariableName -Name $Name
        # Write-Devel "name = $name"
        if ($Value.Count -eq 0) {
            $output = @()
            $output += "declare -A ${name}=()"
            if ($Export) { $output += "export ${name}" }
            return $output -join "`n"
        }
        $pairs = @()
        foreach ($key in $Value.Keys) {
            # Write-Devel "key = $key"
            $keyEscaped = Escape-BashString -Value $key
            $val = $Value[$key]
            if ($null -eq $val) {
                $valEscaped = '""'
            }
            elseif ($val -is [int]) {
                $valEscaped = [string]${val}
            }
            elseif ($val -is [string]) {
                $valEscaped = "'$(Escape-BashString -Value $val)'"
            }
            else {
                $valEscaped = "'$(Escape-BashString -Value ([string]$val))'"
            }
            # Write-Devel "valEscaped = $valEscaped"
            $pairs += "'${keyEscaped}'=${valEscaped}"
        }
        $output = @()
        $output += "declare -A ${name}=($($pairs -join ' '))"
        if ($Export) { $output += "export ${name}" }
        return $output -join "`n"
    }
    End {
        # Write-LeaveFunction
    }
}

<#
.SYNOPSIS
Converts a PowerShell hashtable to bash variables
.DESCRIPTION
Converts a hashtable to multiple bash variable declarations, handling nested objects recursively
.PARAMETER Hashtable
The hashtable to convert
.PARAMETER Prefix
Optional prefix to add to all variable names
.PARAMETER Export
If specified, adds 'export' lines after declarations
.PARAMETER Flat
If specified, flattens nested objects instead of creating separate associative arrays
.PARAMETER DateTimeFormat
Format for DateTime values: 'String' (default), 'Timestamp', or 'ISO'
.PARAMETER Strict
If specified, shows warnings when variable names are sanitized
.EXAMPLE
ConvertTo-BashHashtable -Hashtable $data -Prefix "PROJECT"
.NOTES
Author: Your Name
Date: 2024
#>

function ConvertTo-BashHashtable {
    [CmdletBinding()]
    [OutputType([String])]
    Param (
        [hashtable]$Hashtable,
        [string]$Prefix,
        [switch]$Export,
        [switch]$Flat,
        [ValidateSet('String', 'Timestamp', 'ISO')]
        [string]$DateTimeFormat = 'String',
        [switch]$Strict
    )
    Begin {
        # Write-EnterFunction
    }
    Process {
        $output = @()
        foreach ($key in $Hashtable.Keys) {
            $varName = Sanitize-VariableName -Name $(if ($Prefix) { "${Prefix}_${key}" } else { $key }) -Strict:$Strict
            $value = $Hashtable[$key]
            if ($value -is [hashtable] -or $value -is [PSCustomObject]) {
                if ($Flat) {
                    # Flatten nested objects
                    $output += ConvertTo-BashHashtable -Hashtable $value -Prefix $varName -Export:$Export -Flat:$Flat -DateTimeFormat $DateTimeFormat -Strict:$Strict
                } else {
                    # Create separate associative array
                    if ($value -is [hashtable]) {
                        $output += ConvertTo-BashAssociativeArray -Name $varName -Value $value -Export:$Export
                    } else {
                        $output += ConvertTo-BashCustomObject -Object $value -Prefix $varName -Export:$Export -Flat:$Flat -DateTimeFormat $DateTimeFormat -Strict:$Strict
                    }
                }
            } else {
                $output += ConvertTo-BashVariable -Name $varName -Value $value -Export:$Export -DateTimeFormat $DateTimeFormat
            }
        }
        return $output
    }
    End {
        # Write-LeaveFunction
    }
}

<#
.SYNOPSIS
Converts a PSCustomObject to bash variables
.DESCRIPTION
Converts a PSCustomObject to multiple bash variable declarations, handling nested objects recursively
.PARAMETER Object
The PSCustomObject to convert
.PARAMETER Prefix
Optional prefix to add to all variable names
.PARAMETER Export
If specified, adds 'export' lines after declarations
.PARAMETER Flat
If specified, flattens nested objects instead of creating separate associative arrays
.PARAMETER DateTimeFormat
Format for DateTime values: 'String' (default), 'Timestamp', or 'ISO'
.PARAMETER Strict
If specified, shows warnings when variable names are sanitized
.EXAMPLE
ConvertTo-BashCustomObject -Object $project -Prefix "APP"
.NOTES
Author: Your Name
Date: 2024
#>

function ConvertTo-BashCustomObject {
    [CmdletBinding()]
    [OutputType([String])]
    Param (
        [PSCustomObject]$Object,
        [string]$Prefix,
        [switch]$Export,
        [switch]$Flat,
        [ValidateSet('String', 'Timestamp', 'ISO')]
        [string]$DateTimeFormat = 'String',
        [switch]$Strict
    )
    Begin {
        # Write-EnterFunction
    }
    Process {
        $output = @()
        foreach ($prop in $Object.PSObject.Properties) {
            $varName = Sanitize-VariableName -Name (if ($Prefix) { "${Prefix}_${prop.Name}" } else { $prop.Name }) -Strict:$Strict
            $value = $prop.Value
            if ($value -is [hashtable] -or $value -is [PSCustomObject]) {
                if ($Flat) {
                    if ($value -is [hashtable]) {
                        $output += ConvertTo-BashHashtable -Hashtable $value -Prefix $varName -Export:$Export -Flat:$Flat -DateTimeFormat $DateTimeFormat -Strict:$Strict
                    } else {
                        $output += ConvertTo-BashCustomObject -Object $value -Prefix $varName -Export:$Export -Flat:$Flat -DateTimeFormat $DateTimeFormat -Strict:$Strict
                    }
                } else {
                    if ($value -is [hashtable]) {
                        $output += ConvertTo-BashAssociativeArray -Name $varName -Value $value -Export:$Export
                    } else {
                        $output += ConvertTo-BashCustomObject -Object $value -Prefix $varName -Export:$Export -Flat:$Flat -DateTimeFormat $DateTimeFormat -Strict:$Strict
                    }
                }
            } else {
                $output += ConvertTo-BashVariable -Name $varName -Value $value -Export:$Export -DateTimeFormat $DateTimeFormat
            }
        }
        return $output
    }
    End {
        # Write-LeaveFunction
    }
}

<#
.SYNOPSIS
Escapes a string for safe use in bash single-quoted strings
.DESCRIPTION
Escapes special characters in a string to make it safe for use in bash single-quoted strings
.PARAMETER Value
The string to escape
.EXAMPLE
Escape-BashString -Value "It's a test"
Returns: It'\''s a test
.NOTES
Author: Your Name
Date: 2024
#>

function Escape-BashString {
    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "", Justification="Escape is an intuitive verb for this function.")]
    [CmdletBinding()]
    [OutputType([String])]
    Param (
        [string]$Value
    )
    Begin {
        # Write-EnterFunction
    }
    Process {
        if ($null -eq $Value) { return "" }
        # Escape single quotes for single-quoted strings
        $escaped = $Value -replace "'", "'"
        # Escape special characters
        $escaped = $escaped -replace "`n", '\n'
        $escaped = $escaped -replace "`r", '\r'
        $escaped = $escaped -replace "`t", '\t'
        $escaped = $escaped -replace "```$", '\$'
        # $escaped = $escaped -replace "\\", '\\\\'
        return $escaped
    }
    End {
        # Write-LeaveFunction
    }
}