Public/dsl.ps1

function New-ServiceDefinition {
    [CmdletBinding()]
    [Alias('Service')]
    param (

        [Parameter(Mandatory, Position=0)]
        [scriptblock]
        $ServiceSpec,

        [Parameter()]
        [switch]
        $DryRun,

        [Parameter()]
        [switch]
        $OutYaml
    )


    $serviceParam = @{}
    $serviceFunctions = [System.Collections.Generic.Dictionary[string,System.Management.Automation.ScriptBlock]]::new()

    function Name {
        param (
            [string]$Value
        )
        $serviceParam.Add('Name', $Value)
    }

    function NameSpace {
        param (
            [string]$Value
        )
        $serviceParam.Add('Namespace', $Value)
    }

    function Spec {
        param (
            [Parameter(Mandatory, Position=0)]
            [scriptblock]
            $ServicePort)


        $specParam = @{
            Selector = @{}
            PortObject = @()
        }

        $specFunctions = [System.Collections.Generic.Dictionary[string,System.Management.Automation.ScriptBlock]]::new()

        function Selector {
            param (
                [string]$Key,
                [string]$Value
            )

            $specParam["Selector"].Add($Key, $Value)
        }

        function Port {
            param (
                [scriptblock]$Properties
            )

            $portParams = @{}
            $portFunctions = [System.Collections.Generic.Dictionary[string,System.Management.Automation.ScriptBlock]]::new()

            function Number {
                param (
                    [int]$Value
                )
                $portParams['Port'] = $Value

            }

            function TargetPort {
                param (
                    [int]$Value
                )
                $portParams['TargetPort'] = $Value
            }

            function Name {
                param (
                    [string]$Value
                )
                $portParams['Name'] = $Value
            }

            $portFunctions.Add('Number', (Get-Item function:\Number).ScriptBlock)
            $portFunctions.Add('TargetPort', (Get-Item function:\TargetPort).ScriptBlock)
            $portFunctions.Add('Name', (Get-Item function:\Name).ScriptBlock)

            $Properties.InvokeWithContext($portFunctions, $null, $null)

            $p = New-k8sServicePort @portParams
            $specParam["PortObject"] += $p
        }

        $specFunctions.Add('Selector', (Get-Item function:\Selector).ScriptBlock)
        $specFunctions.Add('Port', (Get-Item function:\Port).ScriptBlock)

        $ServicePort.InvokeWithContext($specFunctions, $null, $null)
        $spec = New-k8sServiceSpec @specParam

        $serviceParam["Spec"] = $spec

    }


    $serviceFunctions.Add('Name', (Get-Item function:\Name).ScriptBlock)
    $serviceFunctions.Add('Namespace', (Get-Item function:\Namespace).ScriptBlock)
    $serviceFunctions.Add('Spec', (Get-Item function:\Spec).ScriptBlock)

    $ServiceSpec.InvokeWithContext($serviceFunctions, $null, $null)

    #& $ServiceSpec

    if ($null -eq $serviceParam["Name"]) {
        throw "Name is empty. You must provide a Serivce Name."
    }

    if ($null -eq $serviceParam["Spec"]) {
        throw "Spec is empty. You must define a Serivce Spec."
    }

    if ($DryRun) {
        $serviceParam.Add('DryRun', 'All')
    }

    $service = New-k8sService @serviceParam -OutYaml:$OutYaml

    Write-Output $service

}
<#
## Example 1


$service = K8sService -DryRun {
    Name testservice2
    Namespace testnamespace
    Spec {
        Selector service testservice
        Port {
            Number 80
            TargetPort 8080
            Name http
        }
        Port {
            Number 443
            TargetPort 8443
        }
    }
}

## Example 2


K8sService {
    Name testservice
    Namespace testnamespace
    Spec {
        Selector service testservice
        foreach ($item in @(80,8080))
        {
            Port {
                Number $item
            }
        }
    }
}

#>