Public/New-PstScript.ps1

function New-PstScript {
    <#
.SYNOPSIS
    Creates a new script file from a template with configurable complexity levels.
.DESCRIPTION
    This function takes a name parameter, copies a script template based on the specified
    complexity level, and saves it with the specified name.

    Complexity Levels:
    - Basic: Simple script with linear execution and minimal structure
    - Moderate: Script with parameter validation, basic error handling, and logging
    - Complex: Advanced script with begin/process/end blocks, pipeline support, and comprehensive features
.PARAMETER Name
    (Required) The name for the new script file.
.PARAMETER ComplexityLevel
    (Optional) The complexity level of the script template. Valid values: Basic, Moderate, Complex.
    Defaults to Moderate for typical script scenarios.
.PARAMETER Force
    (Optional) Forces creation even if file exists, useful in automation scenarios.
.PARAMETER IncludeProjectLayout
    (Optional) Creates a complete project structure including src/, tests/, docs/ directories and supporting files.
.EXAMPLE
    New-PstScript -Name MyScript
    Creates a new moderate complexity script file named MyScript.ps1.
.EXAMPLE
    New-PstScript -Name SimpleTask -ComplexityLevel Basic
    Creates a simple script with minimal structure for basic automation.
.EXAMPLE
    New-PstScript -Name AdvancedProcessor -ComplexityLevel Complex
    Creates an advanced script with full begin/process/end structure and pipeline support.
.EXAMPLE
    New-PstScript -Name ProcessData -IncludeProjectLayout
    Creates a complete project structure with ProcessData.ps1 in src/, test files, documentation, and .gitignore.
.NOTES
    Ensure that the appropriate template files exist in the Resources/Samples directory.
    Template files: Script-Basic.ps1, Script-Moderate.ps1, Script-Complex.ps1
.LINK
    For more information on PowerShell scripting, visit: https://docs.microsoft.com/en-us/powershell/scripting/overview
#>

    [CmdletBinding(SupportsShouldProcess)]
    param (
        [Parameter(Mandatory = $true, Position = 0,
            HelpMessage = "The name for the new script file.")]
        [ValidatePattern('^[A-Za-z][A-Za-z0-9\-_]*$')]
        [string]$Name,

        [Parameter(Mandatory = $false)]
        [ValidateSet("Basic", "Moderate", "Complex")]
        [string]$ComplexityLevel = "Moderate",

        [Parameter(Mandatory = $false)]
        [switch]$Force,

        [Parameter(Mandatory = $false)]
        [switch]$IncludeProjectLayout
    )
    begin {
        Write-Debug -Message "Begin '$($MyInvocation.MyCommand.Name)' at '$(Get-Date)'"

        # Select template based on complexity level
        $templateFileName = switch ($ComplexityLevel) {
            "Basic"     { "Script-Basic.ps1" }
            "Moderate"  { "Script-Moderate.ps1" }
            "Complex"   { "Script-Complex.ps1" }
            default     { "Script-Moderate.ps1" }  # Fallback to Moderate
        }


        $templatePath = $Samples[$templateFileName]

        # Determine file path based on project layout option
        if ($IncludeProjectLayout) {
            $projectRoot = $Name
            $newFilePath = Join-Path $projectRoot "src" "$Name.ps1"
        } else {
            $newFilePath = "$Name.ps1"
        }

        Write-Verbose "Using complexity level: $ComplexityLevel"
        Write-Verbose "Selected template: $templateFileName"

        if (-not $templatePath) {
            throw "Template '$templateFileName' not found in Samples hashtable. Available templates: $($Samples.Keys -join ', ')"
        }
        if (-not (Test-Path $templatePath)) {
            throw "Template file not found: $templatePath"
        } else {
            Write-Verbose "Template file found: $templatePath"
        }
    }
    process {
        try {
            # Check if we're in automation mode - inline check to avoid scope issues
            $isAutomationMode = $Force -or
            ($Global:PstAutomationMode -eq $true) -or
            ($env:CI -eq 'true') -or
            ($env:GITHUB_ACTIONS -eq 'true') -or
            ($Host.Name -eq 'ServerRemoteHost') -or
            (-not [Environment]::UserInteractive) -or
            ($global:ConfirmPreference -eq 'None')

            # Create project structure if IncludeProjectLayout is specified
            if ($IncludeProjectLayout) {
                $projectRoot = $Name

                # Create directory structure
                $directories = @(
                    $projectRoot,
                    (Join-Path $projectRoot "src"),
                    (Join-Path $projectRoot "tests"),
                    (Join-Path $projectRoot "tests" "Unit"),
                    (Join-Path $projectRoot "tests" "Integration"),
                    (Join-Path $projectRoot "docs")
                )

                foreach ($dir in $directories) {
                    if (-not (Test-Path $dir)) {
                        if ($isAutomationMode -or $PSCmdlet.ShouldProcess($dir, "Create directory")) {
                            New-Item -Path $dir -ItemType Directory -Force | Out-Null
                            Write-Verbose "Created directory: $dir"
                        }
                    }
                }

                # Create README.md in root
                $readmeContent = @"
# $Name

PowerShell script for [brief description].

## Installation

``````powershell
.\src\$Name.ps1
``````

## Usage

``````powershell
.\src\$Name.ps1 -Parameter Value
``````

## Testing

``````powershell
Invoke-Pester -Path .\tests\
``````

## License

[Specify license]
"@

                $readmePath = Join-Path $projectRoot "README.md"
                if ($isAutomationMode -or $PSCmdlet.ShouldProcess($readmePath, "Create README.md")) {
                    $readmeContent | Set-Content -Path $readmePath
                    Write-Verbose "Created: $readmePath"
                }

                # Create .gitignore
                $gitignoreContent = @"
# Build artifacts
build/
*.nupkg

# Test results
TestResults*.xml
coverage*.xml

# Temporary files
temp/
*.tmp
*.log
"@

                $gitignorePath = Join-Path $projectRoot ".gitignore"
                if ($isAutomationMode -or $PSCmdlet.ShouldProcess($gitignorePath, "Create .gitignore")) {
                    $gitignoreContent | Set-Content -Path $gitignorePath
                    Write-Verbose "Created: $gitignorePath"
                }

                # Create docs README.md
                $docsReadmeContent = @"
# $Name Documentation

## Overview

[Script overview and purpose]

## Parameters

[Parameter documentation]

## Examples

[Usage examples]

## Notes

[Additional notes]
"@

                $docsReadmePath = Join-Path $projectRoot "docs" "README.md"
                if ($isAutomationMode -or $PSCmdlet.ShouldProcess($docsReadmePath, "Create docs README.md")) {
                    $docsReadmeContent | Set-Content -Path $docsReadmePath
                    Write-Verbose "Created: $docsReadmePath"
                }

                # Create test file
                $testContent = @"
BeforeAll {
    `$scriptPath = "`$PSScriptRoot\..\..\src\$Name.ps1"
}

Describe "$Name" {
    Context "When executed with valid parameters" {
        It "Should execute without errors" {
            # Arrange

            # Act

            # Assert
            `$true | Should -Be `$true
        }
    }

    Context "When executed with invalid parameters" {
        It "Should handle errors gracefully" {
            # Arrange & Act & Assert
            `$true | Should -Be `$true
        }
    }
}
"@

                $testFilePath = Join-Path $projectRoot "tests" "Unit" "$Name.Tests.ps1"
                if ($isAutomationMode -or $PSCmdlet.ShouldProcess($testFilePath, "Create test file")) {
                    $testContent | Set-Content -Path $testFilePath
                    Write-Verbose "Created: $testFilePath"
                }
            }

            # Check if file already exists
            if ((Test-Path $newFilePath) -and -not $isAutomationMode) {
                if (-not $PSCmdlet.ShouldProcess($newFilePath, "Overwrite existing script file")) {
                    Write-Warning "Operation cancelled by user."
                    return
                }
            }
            elseif ((Test-Path $newFilePath) -and $isAutomationMode -and -not $Force) {
                Write-Warning "File '$newFilePath' already exists. Use -Force to overwrite in automation mode."
                return
            }
            # Proceed with file creation - skip ShouldProcess in automation mode
            if ($isAutomationMode -or $PSCmdlet.ShouldProcess($newFilePath, "Create new script file")) {
                # Create parent directory if it doesn't exist (for project layout)
                $parentDir = Split-Path -Path $newFilePath -Parent
                if ($parentDir -and -not (Test-Path $parentDir)) {
                    New-Item -Path $parentDir -ItemType Directory -Force | Out-Null
                }

                Write-Information -Message "Copy-Item -Path '$($templatePath)' -Destination '$(Join-Path (Get-Location) $newFilePath)'"
                Copy-Item -Path $templatePath -Destination $newFilePath

                if ($IncludeProjectLayout) {
                    Write-Output "New script project created: $projectRoot"
                    Write-Output " - Script file: $newFilePath"
                    Write-Output " - Test file: tests\Unit\$Name.Tests.ps1"
                    Write-Output " - Documentation: docs\README.md"
                } else {
                    Write-Output "New script file created: $newFilePath"
                }
            }
            else {
                Write-Verbose "Operation cancelled or skipped."
            }
        }
        catch {
            if ($_.Exception -and $_.Exception.Message) {
                Write-Error "An error occurred: $($_.Exception.Message)"
            } else {
                Write-Error "An error occurred, but no additional information is available."
            }
        }
    }
    end {
        if ($?) {
            Write-Debug -Message "End '$($MyInvocation.MyCommand.Name)' at '$(Get-Date)'"
        }
    }
}