Public/New-PstModule.ps1

function New-PstModule {
    <#
.SYNOPSIS
    Creates a new PowerShell module from a template or using intelligent code generation.
.DESCRIPTION
    This function creates a new PowerShell module with proper structure. It supports two modes:

    1. Template Mode (default): Unpacks a zip template and renames files
    2. Generator Mode (-UseGenerator): Uses the intelligent code generation system to create
       the module root file (.psm1) with proper structure based on complexity level

    Complexity Levels (for Generator Mode):
    - Basic: Simple module with minimal structure
    - Standard: Module with proper loading, error handling, and exports
    - Advanced: Full module features including version checking, dependency management

    Module templates always include proper folder structure and manifest files.
.PARAMETER Path
    (Optional) The destination path where the new module will be created. Defaults to current directory.
.PARAMETER Complexity
    (Optional) The complexity level for code generation. Valid values: Basic, Standard, Advanced.
    Defaults to Standard. Only used with -UseGenerator switch.
.PARAMETER UseGenerator
    (Optional) Switch to use the intelligent code generation system for the .psm1 file.
.PARAMETER IncludeProjectLayout
    (Optional) Creates a complete project structure with src/, tests/, docs/ directories.
.EXAMPLE
    New-PstModule -Path "C:\Modules\MyNewModule"
    Creates a new module using the template (legacy mode).
.EXAMPLE
    New-PstModule -Path "C:\Modules\MyModule" -UseGenerator -Complexity Standard
    Creates a module with a generated .psm1 file using Standard complexity.
.EXAMPLE
    New-PstModule -Path "C:\Modules\MyAwesomeModule" -IncludeProjectLayout
    Creates a complete project structure with the module in src/.
.NOTES
    Template mode uses Module.zip from Resources/Samples.
    Generator mode creates the .psm1 content dynamically.
.LINK
    https://docs.microsoft.com/en-us/powershell/scripting/developer/module/writing-a-windows-powershell-module
#>

    [CmdletBinding(SupportsShouldProcess)]
    param (
        [Parameter(Mandatory = $false, Position = 0,
            HelpMessage = "The destination path where the new module will be created.")]
        [string]$Path = (Get-Location),

        [Parameter(Mandatory = $false,
            HelpMessage = "Complexity level for code generation (Basic, Standard, Advanced).")]
        [ValidateSet("Basic", "Standard", "Advanced")]
        [string]$Complexity = "Standard",

        [Parameter(Mandatory = $false,
            HelpMessage = "Use the intelligent code generation system for the .psm1 file.")]
        [switch]$UseGenerator,

        [Parameter(Mandatory = $false)]
        [switch]$IncludeProjectLayout
    )
    begin {
        Write-Debug -Message "Begin '$($MyInvocation.MyCommand.Name)' at '$(Get-Date)'"
        Write-Verbose -Message "Path: '$($Path)'"
        # Check if Path is empty
        if (-not $Path) {
            throw "Path cannot be empty."
        }

        # Determine actual module destination based on project layout option
        if ($IncludeProjectLayout) {
            $ModuleName = Split-Path -Path $Path -Leaf
            $ModuleDestination = Join-Path $Path "src" $ModuleName
        } else {
            $ModuleDestination = $Path
            $ModuleName = Split-Path -Path $Path -Leaf
        }

        # Check if the module destination is not empty (contains any files or folders)
        if (Test-Path -Path $ModuleDestination) {
            $existingItems = @(Get-ChildItem -Path $ModuleDestination -Force)
            if ($existingItems.Count -gt 0) {
                throw "The path '$ModuleDestination' is not empty. Please choose an empty directory."
            }
        }

        Write-Verbose -Message "ModuleName: '$($ModuleName)'"
        Write-Verbose -Message "ModuleDestination: '$($ModuleDestination)'"

        # Use the predefined file path from the $Samples hashtable
        if (-not $Samples.ContainsKey("Module.zip")) {
            throw "The file 'Module.zip' was not found in the Samples hashtable."
        }
        $ZipFilePath = $Samples["Module.zip"]
        Write-Verbose -Message "ZipFilePath: '$($ZipFilePath)'"
        $result = @{}
    }
    process {
        try {
            # Create project structure if IncludeProjectLayout is specified
            if ($IncludeProjectLayout) {
                # Create directory structure
                $directories = @(
                    $Path,
                    (Join-Path $Path "src"),
                    (Join-Path $Path "tests"),
                    (Join-Path $Path "tests" "Unit"),
                    (Join-Path $Path "tests" "Integration"),
                    (Join-Path $Path "docs")
                )

                foreach ($dir in $directories) {
                    if (-not (Test-Path $dir)) {
                        if ($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 = @"
# $ModuleName

PowerShell module for [brief description].

## Installation

``````powershell
Import-Module .\src\$ModuleName
``````

## Usage

``````powershell
Import-Module .\src\$ModuleName
Get-Command -Module $ModuleName
``````

## Testing

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

## License

[Specify license]
"@

                $readmePath = Join-Path $Path "README.md"
                if ($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 $Path ".gitignore"
                if ($PSCmdlet.ShouldProcess($gitignorePath, "Create .gitignore")) {
                    $gitignoreContent | Set-Content -Path $gitignorePath
                    Write-Verbose "Created: $gitignorePath"
                }

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

## Overview

[Module overview and purpose]

## Cmdlets

[List of exported cmdlets and their usage]

## Examples

[Usage examples]

## Notes

[Additional notes]
"@

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

            Write-Information -Message "Unpacking zip file to '$($ModuleDestination)'"
            # Ensure the destination path exists
            if (-not (Test-Path -Path $ModuleDestination)) {
                if ($PSCmdlet.ShouldProcess($ModuleDestination, "Create module directory")) {
                    New-Item -Path $ModuleDestination -ItemType Directory -Force | Out-Null
                }
            }
            # Extract the contents of the zip file to the destination path
            if ($PSCmdlet.ShouldProcess($ModuleDestination, "Extract module template")) {
                Expand-Archive -Path $ZipFilePath -DestinationPath $ModuleDestination -Force

                # Get the .psm1 file from the extracted contents
                $Psm1File = Get-ChildItem -Path $ModuleDestination -Filter "*.psm1" | Select-Object -First 1
                if ($Psm1File) {
                    # Rename the .psm1 file to match the module name
                    $NewPsm1Name = Join-Path -Path $ModuleDestination -ChildPath "$ModuleName.psm1"
                    if ($PSCmdlet.ShouldProcess($NewPsm1Name, "Rename .psm1 file")) {
                        Rename-Item -Path $Psm1File.FullName -NewName $NewPsm1Name -Force
                        Write-Information -Message "Renamed .psm1 file to '$NewPsm1Name'"
                    }

                    # If using generator, replace the .psm1 content with generated content
                    if ($UseGenerator) {
                        $generatedPsm1Content = New-PstModuleRootContent -ModuleName $ModuleName -Complexity $Complexity
                        if ($PSCmdlet.ShouldProcess($NewPsm1Name, "Generate .psm1 content ($Complexity complexity)")) {
                            Set-Content -Path $NewPsm1Name -Value $generatedPsm1Content -Force
                            Write-Information -Message "Generated .psm1 content with $Complexity complexity"
                        }
                    }
                } else {
                    throw "No .psm1 file found in the extracted template."
                }
                # Get the .psd1 file from the extracted contents
                $Psd1File = Get-ChildItem -Path $ModuleDestination -Filter "*.psd1" | Select-Object -First 1
                if ($Psd1File) {
                    # Rename the .psd1 file to match the module name
                    $NewPsd1Name = Join-Path -Path $ModuleDestination -ChildPath "$ModuleName.psd1"
                    if ($PSCmdlet.ShouldProcess($NewPsd1Name, "Rename .psd1 file")) {
                        Rename-Item -Path $Psd1File.FullName -NewName $NewPsd1Name -Force
                        Write-Information -Message "Renamed .psd1 file to '$NewPsd1Name'"
                    }
                } else {
                    Write-Warning -Message "No .psd1 file found in the extracted template."
                }
            }

            if ($IncludeProjectLayout) {
                Write-Output "New module project created: $Path"
                Write-Output " - Module: $ModuleDestination"
                if ($UseGenerator) {
                    Write-Output " - .psm1: Generated ($Complexity complexity)"
                }
                Write-Output " - Tests: $(Join-Path $Path 'tests')"
                Write-Output " - Documentation: $(Join-Path $Path 'docs' 'README.md')"
            } else {
                if ($UseGenerator) {
                    Write-Output "Module '$ModuleName' created at '$ModuleDestination' (Generated: $Complexity complexity)"
                } else {
                    Write-Output $result
                }
            }
        }
        catch {
            Write-Error -Message "An error occurred: $($_.Exception.Message)"
        }
    }
    end {
        if ($?) {
            Write-Debug -Message "End '$($MyInvocation.MyCommand.Name)' at '$(Get-Date)'"
            if ($IncludeProjectLayout) {
                Write-Information -Message "Module project '$ModuleName' created successfully at '$Path'."
            } else {
                Write-Information -Message "Module '$ModuleName' created successfully at '$Path'."
            }
        }
    }
}