Functions/Get-WhiskeyNPMPath.ps1


function Get-WhiskeyNPMPath
{

    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]
        $ApplicationRoot,

        [Parameter(Mandatory=$true)]
        [string]
        $NodePath
    )

    Set-StrictMode -Version 'Latest'
    Use-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState

    $npmGlobalPath = (Join-Path -Path ($NodePath | Split-Path) -ChildPath 'node_modules\npm\bin\npm-cli.js')

    $packageJsonPath = Resolve-Path -Path (Join-Path -Path $ApplicationRoot -ChildPath 'package.json') | Select-Object -ExpandProperty 'ProviderPath'
    $packageJson = Get-Content -Raw -Path $packageJsonPath | ConvertFrom-Json

    if ( ($packageJson | Get-Member -Name 'engines') -and ($packageJson.engines | Get-Member -Name 'npm') )
    {
        if( $packageJson.engines.npm -notmatch '(\d+\.\d+\.\d+)' )
        {
            Write-Error -Message ('NPM version ''{0}'' is invalid. The NPM version must be a valid semantic version. Package.json file ''{1}'', engines field:{2}{3}' -f $packageJson.engines.npm,$packageJsonPath,[Environment]::NewLine,($packageJson.engines | ConvertTo-Json -Depth 50))
            return
        }
        $version = $Matches[1]

        $localNpmPath = (Join-Path -Path $ApplicationRoot -ChildPath 'node_modules\npm\bin\npm-cli.js')
        $localNpmMetadata = Get-Content -Path (Join-Path -Path $ApplicationRoot -ChildPath 'node_modules\npm\package.json') -Raw -ErrorAction Ignore | ConvertFrom-Json

        if ((Test-Path -Path $localNpmPath -PathType Leaf) -and ($localNpmMetadata.Version -eq $version))
        {
            return $localNpmPath
        }

        Push-Location -Path $ApplicationRoot
        Try
        {
            $version = $Matches[1]
            $npmVersion = ('npm@{0}' -f $version)

            $activity = ('Installing local NPM version {0}' -f $version)
            Invoke-Command -ScriptBlock {
                & $NodePath $npmGlobalPath 'install' $npmVersion '--no-save' |
                    Where-Object { $_ } |
                    ForEach-Object { Write-Progress -Activity $activity -Status $_ ; }
            }
            Write-Progress -Activity $activity -Completed

            if ( $LASTEXITCODE )
            {
                Write-Error -Message ('NPM failed to install NPM version ''{0}'' specified in package.json. NPM returned with exit code ''{1}''.' -f $version,$LASTEXITCODE)
                return
            }
        }
        finally
        {
            Pop-Location
        }

        return $localNpmPath
    }
    else
    {
        return $npmGlobalPath
    }
}