Update-EditorDiagnostic.ps1

# Copyright (c) Matthias Wolf, Mawosoft.

using namespace System
using namespace System.Collections.Generic
using namespace System.Management.Automation
using namespace System.IO

<#
.SYNOPSIS
    Updates the PSES diagnostics displayed for PowerShell script files in the editor.
.INPUTS
    You can pipe paths to this cmdlet.
.OUTPUTS
    None.
#>

function Update-EditorDiagnostic {
    [CmdletBinding(PositionalBinding = $false)]
    param(
        [Alias('LP', 'PSPath')]
        [Parameter(Mandatory, ParameterSetName = 'LiteralPath', ValueFromPipelineByPropertyName, Position = 0)]
        [ValidateNotNullOrEmpty()]
        # Specifies paths to PowerShell script files. Wildcards are not permitted.
        [string[]]$LiteralPath,

        [Parameter(Mandatory, ParameterSetName = 'Path', ValueFromPipeline, Position = 0)]
        [SupportsWildcards()]
        [ValidateNotNullOrEmpty()]
        # Specifies paths to PowerShell script files that may contain wildcards.
        [string[]]$Path,

        [Parameter(Mandatory, DontShow, ParameterSetName = 'ResolvedPath', Position = 0)]
        [ValidateNotNullOrEmpty()]
        # For internal use only.
        [System.Collections.Generic.List[string]]$ResolvedPath,

        [ValidateSet('All', 'Open', 'Marked')]
        # Specifies which of the provided files are updated. Accepted values are:
        # 'All' - Updates all files as provided.
        # 'Open' - Updates only files that are opened in the editor.
        # 'Marked' - Updates only files that already contain diagnostic markers.
        [string]$UpdateDiagnostic = 'Marked'
    )
    begin {
        if ($script:PSES.Error) {
            $PSCmdlet.ThrowTerminatingError([ErrorRecord]::new(
                    [InvalidOperationException]::new($script:PSES.Error),
                    $script:PSES.Error, [ErrorCategory]::InvalidOperation, $null))
            return
        }
        $pathIntrinsics = $ExecutionContext.SessionState.Path
        $currentDir = $pathIntrinsics.CurrentFileSystemLocation
        $seen = [HashSet[string]]::new($script:PathComparer)
        if ($ResolvedPath) {
            # It's fine to use the original list here because the path parameters
            # are mutually exclusive.
            $resolvedPaths = $ResolvedPath
        }
        else {
            $resolvedPaths = [List[string]]::new()
        }
    }
    process {
        if ($LiteralPath) {
            foreach ($p in $LiteralPath) {
                $p2 = [Path]::GetFullPath([Path]::Combine($currentDir, $p))
                if ($seen.Add($p2)) { $resolvedPaths.Add($p2) }
            }
        }
        if ($Path) {
            foreach ($p in $Path) {
                foreach ($p2 in $pathIntrinsics.GetResolvedPSPathFromPSPath($p)) {
                    if ($seen.Add($p2.Path)) { $resolvedPaths.Add($p2.Path) }
                }
            }
        }
    }
    end {
        $reflector = $script:Reflector
        $PSES = $script:PSES
        $scriptFiles = [List[Object]]::new()
        $workspace = $PSES.ServiceProvider.GetService($PSES.WorkspaceServiceType)
        foreach ($p in $resolvedPaths) {
            $scriptFile = $reflector.Expose($workspace.GetFileBuffer($p))
            if ($null -eq $scriptFile) { continue }
            if ($UpdateDiagnostic -eq 'Open') {
                if (-not $scriptFile.IsOpen) { continue }
            }
            elseif ($UpdateDiagnostic -eq 'Marked') {
                if (-not $scriptFile.DiagnosticMarkers) { continue }
            }
            $scriptFile.ParseFileContents()
            $scriptFiles.Add($scriptFile)
            Write-Verbose "Parsing/analyzing: $p"
        }
        if ($scriptFiles) {
            $analysis = $PSES.ServiceProvider.GetService($PSES.AnalysisServiceType)
            $analysis.StartScriptDiagnostics($scriptFiles)
        }
    }
}