diff --git a/.editorconfig b/.editorconfig
index b1bfe93a1..0786fbe27 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -54,11 +54,11 @@ dotnet_diagnostic.CA1068.severity = error
# CA1501: Avoid excessive inheritance
dotnet_diagnostic.CA1501.severity = error
# CA1502: Avoid excessive complexity
-dotnet_diagnostic.CA1502.severity = warning
+dotnet_diagnostic.CA1502.severity = silent
# CA1505: Avoid unmaintainable code
dotnet_diagnostic.CA1505.severity = error
# CA1506: Avoid excessive class coupling
-dotnet_diagnostic.CA1506.severity = warning
+dotnet_diagnostic.CA1506.severity = silent
# CA1507: Use nameof in place of string
dotnet_diagnostic.CA1507.severity = error
# CA1508: Avoid dead conditional code
@@ -95,22 +95,22 @@ dotnet_diagnostic.RCS1210.severity = error
# RCS1036: Remove unnecessary blank line
dotnet_diagnostic.RCS1036.severity = error
# RCS1075: Avoid empty catch clause that catches System.Exception
-dotnet_diagnostic.RCS1075.severity = suggestion
+dotnet_diagnostic.RCS1075.severity = error
# RCS1170: Use read-only auto-implemented property
dotnet_diagnostic.RCS1170.severity = error
# VSTHRD002: Avoid problematic synchronous waits
-dotnet_diagnostic.VSTHRD002.severity = suggestion
+dotnet_diagnostic.VSTHRD002.severity = error
# VSTHRD003: Avoid awaiting foreign Tasks
-dotnet_diagnostic.VSTHRD003.severity = suggestion
+dotnet_diagnostic.VSTHRD003.severity = error
# VSTHRD105: Avoid method overloads that assume TaskScheduler.Current
-dotnet_diagnostic.VSTHRD105.severity = suggestion
+dotnet_diagnostic.VSTHRD105.severity = error
# VSTHRD100: Avoid async void methods
-dotnet_diagnostic.VSTHRD100.severity = suggestion
+dotnet_diagnostic.VSTHRD100.severity = error
# VSTHRD103: Call async methods when in an async method
-dotnet_diagnostic.VSTHRD103.severity = suggestion
+dotnet_diagnostic.VSTHRD103.severity = error
# VSTHRD110: Observe result of async calls
-dotnet_diagnostic.VSTHRD110.severity = suggestion
+dotnet_diagnostic.VSTHRD110.severity = error
# VSTHRD114: Avoid returning a null Task
dotnet_diagnostic.VSTHRD114.severity = error
# VSTHRD200: Use "Async" suffix for awaitable methods
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644
index 000000000..e0c1cb705
--- /dev/null
+++ b/.git-blame-ignore-revs
@@ -0,0 +1,9 @@
+# Enable this file in your git config: git config blame.ignoreRevsFile .git-blame-ignore-revs
+# Enabled on GitHub automatically
+
+# Close Over APIs, was mostly reformatting
+945d61634784db2e51f894c9606e785a099fd23d
+# Dotnet Format Style
+44387b36695607248cebb9467ad48061c19354cb
+# Formatting Fixup
+7233182585b63760992545c7407b17fb2965bc5c
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
deleted file mode 100644
index e3a2fb57f..000000000
--- a/.github/dependabot.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-version: 2
-updates:
-- package-ecosystem: nuget
- directory: "/"
- labels: [ ]
- schedule:
- interval: weekly
- open-pull-requests-limit: 10
- groups:
- OmniSharp:
- patterns:
- - "OmniSharp.Extensions.*"
- xUnit:
- patterns:
- - "xunit"
- - "xunit.*"
-- package-ecosystem: github-actions
- directory: "/"
- labels: [ ]
- schedule:
- interval: weekly
diff --git a/.github/release.yml b/.github/release.yml
index bb7a942a4..cc5a1aa80 100644
--- a/.github/release.yml
+++ b/.github/release.yml
@@ -3,7 +3,7 @@ changelog:
labels:
- Ignore
authors:
- - dependabot[bot]
+ - dependabot
categories:
- title: Enhancements & Features ✨
labels:
diff --git a/.github/workflows/ci-test.yml b/.github/workflows/ci-test.yml
index fd93eb384..d4393920e 100644
--- a/.github/workflows/ci-test.yml
+++ b/.github/workflows/ci-test.yml
@@ -4,73 +4,70 @@ on:
push:
branches: [ main ]
pull_request:
- # The branches below must be a subset of the branches above
branches: [ main ]
- paths-ignore: [ '**/*.md' ]
- merge_group:
- types: [ checks_requested ]
- schedule:
- # 6am UTC which should be after a new daily build posts
- - cron: "0 6 * * *"
jobs:
ci:
name: dotnet
strategy:
+ fail-fast: false
matrix:
os: [ windows-latest, macos-latest, ubuntu-latest ]
runs-on: ${{ matrix.os }}
env:
DOTNET_NOLOGO: true
- DOTNET_CLI_TELEMETRY_OPTOUT: true
DOTNET_GENERATE_ASPNET_CERTIFICATE: false
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
- name: Install dotnet
- uses: actions/setup-dotnet@v4
+ uses: actions/setup-dotnet@v5
with:
cache: true
- cache-dependency-path: '**/packages.lock.json'
- dotnet-version: |
- 6.0.x
- 7.0.x
- 8.0.x
- source-url: https://pkgs.dev.azure.com/mscodehub/PowerShellCore/_packaging/PowerShellCore_PublicPackages/nuget/v3/index.json
- env:
- NUGET_AUTH_TOKEN: ${{ secrets.AZURE_NUGET_TOKEN }}
+ cache-dependency-path: '**/*.csproj'
+ global-json-file: ./global.json
- name: Install PSResources
shell: pwsh
run: ./tools/installPSResources.ps1
- - name: Download daily install script
- uses: actions/checkout@v4
+ - name: Download PowerShell install script
+ uses: actions/checkout@v6
with:
repository: PowerShell/PowerShell
path: pwsh
sparse-checkout: tools/install-powershell.ps1
sparse-checkout-cone-mode: false
- - name: Build and test
+ - name: Install preview
shell: pwsh
- run: Invoke-Build -Configuration Release ${{ github.event_name == 'merge_group' && 'TestFull' || 'Test' }}
+ run: ./pwsh/tools/install-powershell.ps1 -Preview -Destination ./preview
- - name: Test with daily
- if: ${{ github.event_name == 'schedule' }}
+ - name: Build and test
shell: pwsh
- run: ./pwsh/tools/install-powershell.ps1 -Daily && Invoke-Build -Configuration Release TestE2EDaily
+ run: Invoke-Build -Configuration Release TestFull
+
+ # - name: Start VS Code Tunnel if failed or in debug mode
+ # if: ${{ failure() || runner.debug == '1' }}
+ # #v0.0.2 - Pinned for security
+ # uses: justingrote/vscode-action@5d495ef6156c20f1f9bb21031c15776d476c10c3
+ # with:
+ # #All these settings are optional
+ # tunnel-name: 'pses-action-tunnel'
+ # connection-timeout: 2
+ # session-timeout: 30
+ # no-cache-cli-auth: true
- name: Upload build artifacts
if: always()
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v5
with:
name: PowerShellEditorServices-module-${{ matrix.os }}
path: module
- name: Upload test results
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v5
if: always()
with:
name: PowerShellEditorServices-test-results-${{ matrix.os }}
diff --git a/.github/workflows/close-stale-issues.yml b/.github/workflows/close-stale-issues.yml
index 8ababb3c9..7349ee838 100644
--- a/.github/workflows/close-stale-issues.yml
+++ b/.github/workflows/close-stale-issues.yml
@@ -11,7 +11,7 @@ jobs:
stale-resolved-issues:
runs-on: ubuntu-latest
steps:
- - uses: actions/stale@v9
+ - uses: actions/stale@v10
name: Label resolved issues as needing fix verification
with:
any-of-labels: "Resolution-Answered,Resolution-Duplicate,Resolution-External,Resolution-Fixed,Resolution-Inactive"
@@ -23,7 +23,7 @@ jobs:
stale-fixed-issues:
runs-on: ubuntu-latest
steps:
- - uses: actions/stale@v9
+ - uses: actions/stale@v10
name: Close issues needing fix verification after 1 week of inactivity
with:
stale-issue-label: "Needs: Fix Verification"
@@ -34,7 +34,7 @@ jobs:
stale-feedback-issues:
runs-on: ubuntu-latest
steps:
- - uses: actions/stale@v9
+ - uses: actions/stale@v10
name: Close issues needing author feedback after 1 week of inactivity
with:
stale-issue-label: "Needs: Author Feedback"
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
deleted file mode 100644
index 018eaaa77..000000000
--- a/.github/workflows/codeql-analysis.yml
+++ /dev/null
@@ -1,56 +0,0 @@
-name: CodeQL Analysis
-
-on:
- push:
- branches: [ main ]
- pull_request:
- # The branches below must be a subset of the branches above
- branches: [ main ]
- paths-ignore: [ '**/*.md' ]
-
-jobs:
- analyze:
- name: analyze
- strategy:
- fail-fast: false
- matrix:
- language: [ csharp ]
- runs-on: ubuntu-latest
- permissions:
- actions: read
- contents: read
- security-events: write
- env:
- DOTNET_NOLOGO: true
- DOTNET_CLI_TELEMETRY_OPTOUT: true
- DOTNET_GENERATE_ASPNET_CERTIFICATE: false
- steps:
- - name: Checkout repository
- uses: actions/checkout@v4
-
- - name: Install dotnet
- uses: actions/setup-dotnet@v4
- with:
- cache: true
- cache-dependency-path: '**/packages.lock.json'
- source-url: https://pkgs.dev.azure.com/mscodehub/PowerShellCore/_packaging/PowerShellCore_PublicPackages/nuget/v3/index.json
- env:
- NUGET_AUTH_TOKEN: ${{ secrets.AZURE_NUGET_TOKEN }}
-
- - name: Initialize CodeQL
- uses: github/codeql-action/init@v3
- with:
- languages: ${{ matrix.language }}
-
- - name: Install PSResources
- shell: pwsh
- run: tools/installPSResources.ps1
-
- - name: Build
- shell: pwsh
- run: Invoke-Build Build
-
- - name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v3
- with:
- category: '/language:${{matrix.language}}'
diff --git a/.github/workflows/emacs-test.yml b/.github/workflows/emacs-test.yml
index 31f840581..32fb728a2 100644
--- a/.github/workflows/emacs-test.yml
+++ b/.github/workflows/emacs-test.yml
@@ -6,7 +6,6 @@ on:
pull_request:
# The branches below must be a subset of the branches above
branches: [ main ]
- paths-ignore: [ '**/*.md' ]
merge_group:
types: [ checks_requested ]
@@ -16,20 +15,16 @@ jobs:
runs-on: ubuntu-latest
env:
DOTNET_NOLOGO: true
- DOTNET_CLI_TELEMETRY_OPTOUT: true
DOTNET_GENERATE_ASPNET_CERTIFICATE: false
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
- name: Install dotnet
- uses: actions/setup-dotnet@v4
+ uses: actions/setup-dotnet@v5
with:
cache: true
- cache-dependency-path: '**/packages.lock.json'
- source-url: https://pkgs.dev.azure.com/mscodehub/PowerShellCore/_packaging/PowerShellCore_PublicPackages/nuget/v3/index.json
- env:
- NUGET_AUTH_TOKEN: ${{ secrets.AZURE_NUGET_TOKEN }}
+ cache-dependency-path: '**/*.csproj'
- name: Install PSResources
shell: pwsh
@@ -40,7 +35,7 @@ jobs:
run: Invoke-Build Build
- name: Install Emacs
- uses: purcell/setup-emacs@master
+ uses: purcell/setup-emacs@v8.0
with:
version: '28.2'
diff --git a/.github/workflows/vim-test.yml b/.github/workflows/vim-test.yml
index b434fcb45..b04d5272a 100644
--- a/.github/workflows/vim-test.yml
+++ b/.github/workflows/vim-test.yml
@@ -6,7 +6,6 @@ on:
pull_request:
# The branches below must be a subset of the branches above
branches: [ main ]
- paths-ignore: [ '**/*.md' ]
merge_group:
types: [ checks_requested ]
@@ -16,20 +15,16 @@ jobs:
runs-on: ubuntu-latest
env:
DOTNET_NOLOGO: true
- DOTNET_CLI_TELEMETRY_OPTOUT: true
DOTNET_GENERATE_ASPNET_CERTIFICATE: false
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
- name: Install dotnet
- uses: actions/setup-dotnet@v4
+ uses: actions/setup-dotnet@v5
with:
cache: true
- cache-dependency-path: '**/packages.lock.json'
- source-url: https://pkgs.dev.azure.com/mscodehub/PowerShellCore/_packaging/PowerShellCore_PublicPackages/nuget/v3/index.json
- env:
- NUGET_AUTH_TOKEN: ${{ secrets.AZURE_NUGET_TOKEN }}
+ cache-dependency-path: '**/*.csproj'
- name: Install PSResources
shell: pwsh
@@ -40,16 +35,19 @@ jobs:
run: Invoke-Build Build
- name: Install Vim
+ id: vim
uses: rhysd/action-setup-vim@v1
+ with:
+ version: nightly
- name: Checkout vim-ps1
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
with:
repository: PProvost/vim-ps1
path: vim-ps1
- name: Checkout LanguageClient-neovim
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
with:
repository: autozimu/LanguageClient-neovim
path: LanguageClient-neovim
@@ -59,7 +57,7 @@ jobs:
working-directory: LanguageClient-neovim
- name: Checkout Themis
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
with:
repository: thinca/vim-themis
path: vim-themis
@@ -73,3 +71,14 @@ jobs:
env:
THEMIS_VIM: ${{ steps.vim.outputs.executable }}
run: ./vim-themis/bin/themis ./test/vim-simple-test.vim
+
+ # - name: Start VS Code Tunnel if failed or in debug mode
+ # if: ${{ failure() || runner.debug == '1' }}
+ # #v0.0.2 - Pinned for security
+ # uses: justingrote/vscode-action@5d495ef6156c20f1f9bb21031c15776d476c10c3
+ # with:
+ # #All these settings are optional
+ # tunnel-name: 'pses-action-tunnel'
+ # connection-timeout: 2
+ # session-timeout: 30
+ # no-cache-cli-auth: true
diff --git a/.gitignore b/.gitignore
index f73bd5823..d8c2d5b16 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,79 +1,4 @@
-_ReSharper*
-[Bb]in
-bin-nano
-obj
-objd
-out/
-tmp/
-.tmp
-App_Data
-*.user
-*.sln.cache
-*.suo
-TestResults
-test/emacs-session.json
-[Tt]humbs.db
-buildd.*
-release/
-*.log
-*.bak
-packages
-OACRTemp/
-build_logs/
-lock
-/public/inc/bldver.*
-/public/inc/sources.ver
-/data
-/target
-.corext/gen
-registered_data.ini
-.vs/
-.dotnet/
-module/Plaster
-module/PSScriptAnalyzer
-module/PSReadLine
-docs/_site/
-docs/_repo/
-docs/metadata/
-*.zip
-
-# Generated build info file
-src/PowerShellEditorServices.Hosting/BuildInfo.cs
-
-# quickbuild.exe
-/VersionGeneratingLogs/
-QLogs
-QLocal
-QTestLogs
-
-# bad tlb/chm generators in nmake tree
-*.tlb
-*.chm
-
-# dumb silverlight
-ClientBin/
-
-# dump azure
-*.build.csdef
-csx/
-
-# Don't include ScriptAnalyzer binaries
-PowerShellEditorServices/**
-PowerShellEditorServices.NoNano/**
-
-PowerShellEditorServices.sln.ide/edb.chk
-PowerShellEditorServices.sln.ide/edbres00001.jrs
-PowerShellEditorServices.sln.ide/storage.ide
-*.jrs
-
-# Don't include PlatyPS generated MAML
-module/PowerShellEditorServices/Commands/en-US/*-help.xml
-
-# Don't include Third Party Notices in module folder
-module/PowerShellEditorServices/Third\ Party\ Notices.txt
-
-# Visual Studio for Mac generated file
-*.userprefs
-
-# JetBrains generated file (Rider, intelliJ)
-.idea/
+bin/
+obj/
+module/
+TestResults/
diff --git a/.pipelines/PowerShellEditorServices-Official.yml b/.pipelines/PowerShellEditorServices-Official.yml
deleted file mode 100644
index f1d47c08c..000000000
--- a/.pipelines/PowerShellEditorServices-Official.yml
+++ /dev/null
@@ -1,182 +0,0 @@
-#################################################################################
-# OneBranch Pipelines #
-# This pipeline was created by EasyStart from a sample located at: #
-# https://aka.ms/obpipelines/easystart/samples #
-# Documentation: https://aka.ms/obpipelines #
-# Yaml Schema: https://aka.ms/obpipelines/yaml/schema #
-# Retail Tasks: https://aka.ms/obpipelines/tasks #
-# Support: https://aka.ms/onebranchsup #
-#################################################################################
-
-trigger: none
-
-parameters:
-- name: debug
- displayName: Enable debug output
- type: boolean
- default: false
-
-variables:
- system.debug: ${{ parameters.debug }}
- BuildConfiguration: Release
- WindowsContainerImage: onebranch.azurecr.io/windows/ltsc2019/vse2022:latest
- DOTNET_NOLOGO: true
- DOTNET_CLI_TELEMETRY_OPTOUT: true
- DOTNET_GENERATE_ASPNET_CERTIFICATE: false
-
-resources:
- repositories:
- - repository: templates
- type: git
- name: OneBranch.Pipelines/GovernedTemplates
- ref: refs/heads/main
-
-extends:
- # https://aka.ms/obpipelines/templates
- template: v2/OneBranch.Official.CrossPlat.yml@templates
- parameters:
- globalSdl: # https://aka.ms/obpipelines/sdl
- asyncSdl:
- enabled: true
- forStages: [build]
- stages:
- - stage: build
- jobs:
- - job: main
- displayName: Build package
- pool:
- type: windows
- variables:
- ob_outputDirectory: $(Build.SourcesDirectory)/module
- steps:
- - pwsh: |
- [xml]$xml = Get-Content PowerShellEditorServices.Common.props
- $version = $xml.Project.PropertyGroup.VersionPrefix
- Write-Output "##vso[task.setvariable variable=version;isOutput=true]$version"
- name: package
- displayName: Get version from project properties
- - task: onebranch.pipeline.version@1
- displayName: Set OneBranch version
- inputs:
- system: Custom
- customVersion: $(package.version)
- - task: UseDotNet@2
- displayName: Install .NET 8.x SDK
- inputs:
- packageType: sdk
- version: 8.x
- - task: UseDotNet@2
- displayName: Install .NET 7.x runtime
- inputs:
- packageType: runtime
- version: 7.x
- - task: UseDotNet@2
- displayName: Install .NET 6.x runtime
- inputs:
- packageType: runtime
- version: 6.x
- - task: PowerShell@2
- displayName: Install PSResources
- inputs:
- pwsh: true
- filePath: tools/installPSResources.ps1
- - task: PowerShell@2
- displayName: Build and test
- inputs:
- targetType: inline
- pwsh: true
- script: Invoke-Build TestFull -Configuration $(BuildConfiguration)
- - task: PublishTestResults@2
- displayName: Publish test results
- inputs:
- testRunner: VSTest
- testResultsFiles: '**/*.trx'
- failTaskOnFailedTests: true
- - task: PowerShell@2
- displayName: Assert release configuration
- inputs:
- targetType: inline
- pwsh: true
- script: |
- $assembly = [Reflection.Assembly]::LoadFile("$(Build.SourcesDirectory)/module/PowerShellEditorServices/bin/Core/Microsoft.PowerShell.EditorServices.Hosting.dll")
- if ($assembly.GetCustomAttributes([System.Diagnostics.DebuggableAttribute], $true).IsJITOptimizerDisabled) {
- Write-Host "##vso[task.LogIssue type=error;]Was not built in release configuration!"
- exit 1
- }
- - task: onebranch.pipeline.signing@1
- displayName: Sign 1st-party files
- inputs:
- command: sign
- signing_environment: external_distribution
- search_root: $(Build.SourcesDirectory)/module
- files_to_sign: |
- **/*.ps1;
- **/*.psd1;
- **/*.psm1;
- **/*.ps1xml;
- **/Microsoft.PowerShell.EditorServices*.dll;
- !Plaster/*;
- - task: onebranch.pipeline.signing@1
- displayName: Sign 3rd-party files
- inputs:
- command: sign
- signing_environment: 135020002
- search_root: $(Build.SourcesDirectory)/module
- files_to_sign: |
- **/MediatR.dll;
- **/Nerdbank.Streams.dll;
- **/Newtonsoft.Json.dll;
- **/OmniSharp.Extensions*.dll;
- **/Serilog*.dll;
- **/System.Reactive.dll;
- Plaster/**/*.ps1;
- Plaster/**/*.psd1;
- Plaster/**/*.psm1;
- - stage: release
- dependsOn: build
- variables:
- version: $[ stageDependencies.build.main.outputs['package.version'] ]
- drop: $(Pipeline.Workspace)/drop_build_main
- jobs:
- - job: validation
- displayName: Manual validation
- pool:
- type: agentless
- timeoutInMinutes: 1440
- steps:
- - task: ManualValidation@0
- displayName: Wait 24 hours for validation
- inputs:
- notifyUsers: $(Build.RequestedForEmail)
- instructions: Please validate the release
- timeoutInMinutes: 1440
- - job: github
- dependsOn: validation
- displayName: Publish draft to GitHub
- pool:
- type: windows
- variables:
- ob_outputDirectory: $(Build.SourcesDirectory)/out
- steps:
- - download: current
- displayName: Download artifacts
- - task: ArchiveFiles@2
- displayName: Zip signed artifacts
- inputs:
- rootFolderOrFile: $(drop)
- includeRootFolder: false
- archiveType: zip
- archiveFile: out/PowerShellEditorServices.zip
- - task: GitHubRelease@1
- displayName: Create GitHub release
- inputs:
- gitHubConnection: GitHub
- repositoryName: PowerShell/PowerShellEditorServices
- assets: out/PowerShellEditorServices.zip
- tagSource: userSpecifiedTag
- tag: v$(version)
- isDraft: true
- addChangeLog: false
- releaseNotesSource: inline
- releaseNotesInline: |
- # TODO: Generate release notes on GitHub!
diff --git a/.pipelines/PowerShellEditorServices-OneBranch.yml b/.pipelines/PowerShellEditorServices-OneBranch.yml
new file mode 100644
index 000000000..980603f14
--- /dev/null
+++ b/.pipelines/PowerShellEditorServices-OneBranch.yml
@@ -0,0 +1,174 @@
+#################################################################################
+# OneBranch Pipelines #
+# This pipeline was created by EasyStart from a sample located at: #
+# https://aka.ms/obpipelines/easystart/samples #
+# Documentation: https://aka.ms/obpipelines #
+# Yaml Schema: https://aka.ms/obpipelines/yaml/schema #
+# Retail Tasks: https://aka.ms/obpipelines/tasks #
+# Support: https://aka.ms/onebranchsup #
+#################################################################################
+
+trigger:
+ - main
+
+schedules:
+ - cron: "35 13 * * 4"
+ displayName: Weekly CodeQL
+ branches:
+ include:
+ - main
+ always: true
+
+resources:
+ repositories:
+ - repository: templates
+ type: git
+ name: OneBranch.Pipelines/GovernedTemplates
+ ref: refs/heads/main
+
+parameters:
+ - name: debug
+ displayName: Enable debug output
+ type: boolean
+ default: false
+ - name: OfficialBuild
+ displayName: Use Official OneBranch template
+ type: boolean
+ default: true
+ - name: Release
+ displayName: Generate a release
+ type: boolean
+ default: false
+
+variables:
+ system.debug: ${{ parameters.debug }}
+ BuildConfiguration: Release
+ WindowsContainerImage: onebranch.azurecr.io/windows/ltsc2022/vse2022:latest
+ DOTNET_NOLOGO: true
+ DOTNET_GENERATE_ASPNET_CERTIFICATE: false
+ OneBranchTemplate: ${{ iif(parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@templates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@templates') }}
+
+extends:
+ # https://aka.ms/obpipelines/templates
+ template: ${{ variables.OneBranchTemplate }}
+ parameters:
+ globalSdl: # https://aka.ms/obpipelines/sdl
+ asyncSdl:
+ enabled: true
+ forStages: [build]
+ featureFlags:
+ EnableCDPxPAT: false
+ WindowsHostVersion:
+ Version: 2022
+ Network: KS3
+ release:
+ category: NonAzure
+ stages:
+ - stage: build
+ jobs:
+ - job: main
+ displayName: Build package
+ pool:
+ type: windows
+ variables:
+ ob_outputDirectory: $(Build.SourcesDirectory)/out
+ steps:
+ - pwsh: |
+ [xml]$xml = Get-Content PowerShellEditorServices.Common.props
+ $version = $xml.Project.PropertyGroup.VersionPrefix
+ $prerelease = $xml.Project.PropertyGroup.VersionSuffix
+ if ($prerelease) { $version += "-$prerelease" }
+ Write-Output "##vso[task.setvariable variable=version;isOutput=true]$version"
+ Write-Output "##vso[task.setvariable variable=prerelease;isOutput=true]$(-not [string]::IsNullOrEmpty($prerelease))"
+ name: package
+ displayName: Get version from project properties
+ - task: onebranch.pipeline.version@1
+ displayName: Set OneBranch version
+ inputs:
+ system: Custom
+ customVersion: $(package.version)
+ - task: UseDotNet@2
+ displayName: Use .NET 8.x SDK
+ inputs:
+ packageType: sdk
+ useGlobalJson: true
+ - pwsh: ./tools/installPSResources.ps1 -PSRepository CFS
+ displayName: Install PSResources
+ - pwsh: Invoke-Build TestFull -Configuration $(BuildConfiguration) -PSRepository CFS
+ displayName: Build and test
+ - task: PublishTestResults@2
+ displayName: Publish test results
+ inputs:
+ testRunner: VSTest
+ testResultsFiles: "**/*.trx"
+ failTaskOnFailedTests: true
+ - pwsh: |
+ $assembly = [Reflection.Assembly]::LoadFile("$(Build.SourcesDirectory)/module/PowerShellEditorServices/bin/Core/Microsoft.PowerShell.EditorServices.Hosting.dll")
+ if ($assembly.GetCustomAttributes([System.Diagnostics.DebuggableAttribute], $true).IsJITOptimizerDisabled) {
+ Write-Host "##vso[task.LogIssue type=error;]Was not built in release configuration!"
+ exit 1
+ }
+ displayName: Assert release configuration
+ continueOnError: true
+ - task: onebranch.pipeline.signing@1
+ displayName: Sign 1st-party files
+ inputs:
+ command: sign
+ signing_profile: external_distribution
+ search_root: $(Build.SourcesDirectory)/module
+ files_to_sign: |
+ **/*.ps1;
+ **/*.psd1;
+ **/*.psm1;
+ **/*.ps1xml;
+ **/Microsoft.PowerShell.EditorServices*.dll;
+ - task: onebranch.pipeline.signing@1
+ displayName: Sign 3rd-party files
+ inputs:
+ command: sign
+ signing_profile: 135020002
+ search_root: $(Build.SourcesDirectory)/module
+ files_to_sign: |
+ **/MediatR.dll;
+ **/Nerdbank.Streams.dll;
+ **/Newtonsoft.Json.dll;
+ **/OmniSharp.Extensions*.dll;
+ **/System.Reactive.dll;
+ - task: ArchiveFiles@2
+ displayName: Zip signed artifacts
+ inputs:
+ rootFolderOrFile: $(Build.SourcesDirectory)/module
+ includeRootFolder: false
+ archiveType: zip
+ archiveFile: out/PowerShellEditorServices.zip
+ - stage: release
+ dependsOn: build
+ condition: and(succeeded(), ${{ eq(parameters.Release, true) }})
+ variables:
+ ob_release_environment: ${{ iif(parameters.OfficialBuild, 'Production', 'Test') }}
+ version: $[ stageDependencies.build.main.outputs['package.version'] ]
+ prerelease: $[ stageDependencies.build.main.outputs['package.prerelease'] ]
+ jobs:
+ - job: github
+ displayName: Publish draft to GitHub
+ pool:
+ type: release
+ templateContext:
+ inputs:
+ - input: pipelineArtifact
+ artifactName: drop_build_main
+ steps:
+ - task: GitHubRelease@1
+ displayName: Create GitHub release
+ inputs:
+ gitHubConnection: github.com_andyleejordan
+ repositoryName: PowerShell/PowerShellEditorServices
+ target: main
+ assets: $(Pipeline.Workspace)/PowerShellEditorServices.zip
+ tagSource: userSpecifiedTag
+ tag: v$(version)
+ isDraft: true
+ isPreRelease: $(prerelease)
+ addChangeLog: false
+ releaseNotesSource: inline
+ releaseNotesInline: ""
diff --git a/ADOPTERS.md b/ADOPTERS.md
deleted file mode 100644
index ff80c2205..000000000
--- a/ADOPTERS.md
+++ /dev/null
@@ -1,17 +0,0 @@
-# Adopters
-
-
-
-This is a list of adopters of using PowerShell Editor Services in production or in their products (in alphabetical order):
-
-* [vscode-powershell](https://github.com/PowerShell/vscode-powershell) - Provides rich PowerShell language support for Visual Studio Code. You can write and debug PowerShell scripts using the excellent IDE-like interface that Visual Studio Code provides.
-
-* [coc-powershell](https://github.com/coc-extensions/coc-powershell) - A Vim and NeoVim plugin powered by PowerShellEditorServices and [coc.nvim](https://github.com/neoclide/coc.nvim) to provide a rich PowerShell editing experience.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 10c90056d..548812339 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,103 @@
# PowerShell Editor Services Release History
+## v4.6.0
+### Friday, May 15, 2026
+
+See more details at the GitHub Release for [v4.6.0](https://github.com/PowerShell/PowerShellEditorServices/releases/tag/v4.6.0).
+
+New rename provider and workspace document API!
+
+## v4.5.0
+### Wednesday, April 08, 2026
+
+See more details at the GitHub Release for [v4.5.0](https://github.com/PowerShell/PowerShellEditorServices/releases/tag/v4.5.0).
+
+New PSSA version and lots of fixes!
+
+## v4.4.0
+### Thursday, September 04, 2025
+
+See more details at the GitHub Release for [v4.4.0](https://github.com/PowerShell/PowerShellEditorServices/releases/tag/v4.4.0).
+
+Supports screen readers!
+
+## Unreleased
+
+- ✨ 📟 [PowerShellEditorServices #2239](https://github.com/PowerShell/PowerShellEditorServices/pull/2239) - Update PSReadLine to v2.4.2-beta2.
+
+## v4.3.0
+### Tuesday, March 18, 2025
+
+See more details at the GitHub Release for [v4.3.0](https://github.com/PowerShell/PowerShellEditorServices/releases/tag/v4.3.0).
+
+New packages!
+
+## v4.2.0
+### Thursday, January 16, 2025
+
+See more details at the GitHub Release for [v4.2.0](https://github.com/PowerShell/PowerShellEditorServices/releases/tag/v4.2.0).
+
+Support PSScriptAnalyzer config in multi-root workspaces
+
+## v4.1.0
+### Wednesday, December 04, 2024
+
+See more details at the GitHub Release for [v4.1.0](https://github.com/PowerShell/PowerShellEditorServices/releases/tag/v4.1.0).
+
+Debugger optimizations and incremental build support!
+
+## v4.0.0
+### Monday, November 18, 2024
+
+See more details at the GitHub Release for [v4.0.0](https://github.com/PowerShell/PowerShellEditorServices/releases/tag/v4.0.0).
+
+Drop support for PowerShell <7.4 and logging overhaul
+
+PowerShell 7.2 LTS and 7.3 are now past end-of-support and are now unsupported.
+This is an incompatible API change so we're bumping the major version.
+Please update to PowerShell 7.4 LTS going forward.
+
+This release contains a logging overhaul which purposely removes our
+dependency on Serilog and should lead to improved stability with
+PowerShell 5.1 (by avoiding a major GAC assembly conflict).
+
+## v3.30.0 (mistakenly released as v3.3.0)
+### Friday, November 15, 2024
+
+See more details at the GitHub Release for [v3.3.0](https://github.com/PowerShell/PowerShellEditorServices/releases/tag/v3.3.0).
+
+Logging updates and dropped EOL PowerShell
+
+## v3.21.0
+### Wednesday, October 30, 2024
+
+See more details at the GitHub Release for [v3.21.0](https://github.com/PowerShell/PowerShellEditorServices/releases/tag/v3.21.0).
+
+Updates to PSScriptAnalyzer and Call-operator support
+
+## v3.20.1
+### Friday, May 03, 2024
+
+See more details at the GitHub Release for [v3.20.1](https://github.com/PowerShell/PowerShellEditorServices/releases/tag/v3.20.1).
+
+Update third-party notices.
+
+## v3.20.0
+### Tuesday, April 16, 2024
+
+See more details at the GitHub Release for [v3.20.0](https://github.com/PowerShell/PowerShellEditorServices/releases/tag/v3.20.0).
+
+Hotfix for incorrect signing certificate, sorry about that!
+
+Also removed Plaster integration as we were unable to correctly sign it since we no longer own it.
+
+## v3.19.0
+### Wednesday, April 03, 2024
+
+See more details at the GitHub Release for [v3.19.0](https://github.com/PowerShell/PowerShellEditorServices/releases/tag/v3.19.0).
+
+Overhauled Terminal Shell Integration!
+
## v3.18.1
### Tuesday, March 19, 2024
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
index dddfa22df..686e5e7a0 100644
--- a/CODE_OF_CONDUCT.md
+++ b/CODE_OF_CONDUCT.md
@@ -1,8 +1,10 @@
-# Code of Conduct
+# Microsoft Open Source Code of Conduct
-This project has adopted the [Microsoft Open Source Code of Conduct][conduct-code].
-For more information see the [Code of Conduct FAQ][conduct-FAQ] or contact [opencode@microsoft.com][conduct-email] with any additional questions or comments.
+This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
-[conduct-code]: http://opensource.microsoft.com/codeofconduct/
-[conduct-FAQ]: http://opensource.microsoft.com/codeofconduct/faq/
-[conduct-email]: mailto:opencode@microsoft.com
+Resources:
+
+- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
+- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
+- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
+- Employees can reach out at [aka.ms/opensource/moderation-support](https://aka.ms/opensource/moderation-support)
diff --git a/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 000000000..193280892
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,5 @@
+
+
+ true
+
+
diff --git a/Directory.Packages.props b/Directory.Packages.props
new file mode 100644
index 000000000..c76c2a7e3
--- /dev/null
+++ b/Directory.Packages.props
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
+
+
+
diff --git a/NOTICE.txt b/NOTICE.txt
new file mode 100644
index 000000000..aabad504f
--- /dev/null
+++ b/NOTICE.txt
@@ -0,0 +1,3496 @@
+NOTICES AND INFORMATION
+Do Not Translate or Localize
+
+This software incorporates material from third parties.
+Microsoft makes certain open source code available at https://3rdpartysource.microsoft.com,
+or you may send a check or money order for US $5.00, including the product name,
+the open source component name, platform, and version number, to:
+
+Source Code Compliance Team
+Microsoft Corporation
+One Microsoft Way
+Redmond, WA 98052
+USA
+
+Notwithstanding any other terms, you may reverse engineer this software to the extent
+required to debug changes to any libraries licensed under the GNU Lesser General Public License.
+
+---------------------------------------------------------
+
+MediatR 8.1.0 - Apache-2.0
+
+
+Copyright Jimmy Bogard
+
+Apache License
+
+Version 2.0, January 2004
+
+http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+
+
+ "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+
+
+
+ "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+
+
+
+ "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+
+
+ "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
+
+
+
+ "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
+
+
+
+ "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
+
+
+
+ "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
+
+
+
+ "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+
+
+
+ "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
+
+
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
+
+ (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+
+you may not use this file except in compliance with the License.
+
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+
+distributed under the License is distributed on an "AS IS" BASIS,
+
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+
+See the License for the specific language governing permissions and
+
+limitations under the License.
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Microsoft.Bcl.AsyncInterfaces 7.0.0 - MIT
+
+
+(c) Microsoft Corporation
+Copyright (c) Andrew Arnott
+Copyright 2019 LLVM Project
+Copyright 2018 Daniel Lemire
+Copyright (c) .NET Foundation
+Copyright (c) 2011, Google Inc.
+Copyright (c) 2020 Dan Shechter
+(c) 1997-2005 Sean Eron Anderson
+Copyright (c) 1998 Microsoft. To
+Copyright (c) 2017 Yoshifumi Kawai
+Copyright (c) 2005-2020 Rich Felker
+Copyright (c) Microsoft Corporation
+Copyright (c) 2007 James Newton-King
+Copyright (c) 2012-2014, Yann Collet
+Copyright (c) 1991-2022 Unicode, Inc.
+Copyright (c) 2013-2017, Alfred Klomp
+Copyright 2012 the V8 project authors
+Copyright (c) 1999 Lucent Technologies
+Copyright (c) 2008-2016, Wojciech Mula
+Copyright (c) 2011-2020 Microsoft Corp
+Copyright (c) 2015-2017, Wojciech Mula
+Copyright (c) 2021 csFastFloat authors
+Copyright (c) 2005-2007, Nick Galbreath
+Copyright (c) 2015 The Chromium Authors
+Copyright (c) 2018 Alexander Chermyanin
+Copyright (c) The Internet Society 1997
+Portions (c) International Organization
+Copyright (c) 2004-2006 Intel Corporation
+Copyright (c) 2013-2017, Milosz Krajewski
+Copyright (c) 2016-2017, Matthieu Darbois
+Copyright (c) The Internet Society (2003)
+Copyright (c) .NET Foundation Contributors
+Copyright (c) 2020 Mara Bos
+Copyright (c) .NET Foundation and Contributors
+Copyright (c) 2008-2020 Advanced Micro Devices, Inc.
+Copyright (c) 2019 Microsoft Corporation, Daan Leijen
+Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler
+Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com)
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors
+Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com
+Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers
+Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip
+Copyright (c) 1980, 1986, 1993 The Regents of the University of California
+Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To
+
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Microsoft.Bcl.AsyncInterfaces 8.0.0 - MIT
+
+
+Copyright (c) Six Labors
+(c) Microsoft Corporation
+Copyright (c) Andrew Arnott
+Copyright 2019 LLVM Project
+Copyright 2018 Daniel Lemire
+Copyright (c) .NET Foundation
+Copyright (c) 2011, Google Inc.
+Copyright (c) 2020 Dan Shechter
+(c) 1997-2005 Sean Eron Anderson
+Copyright (c) 1998 Microsoft. To
+Copyright (c) 2022, Wojciech Mula
+Copyright (c) 2017 Yoshifumi Kawai
+Copyright (c) 2022, Geoff Langdale
+Copyright (c) 2005-2020 Rich Felker
+Copyright (c) 2012-2021 Yann Collet
+Copyright (c) Microsoft Corporation
+Copyright (c) 2007 James Newton-King
+Copyright (c) 1991-2022 Unicode, Inc.
+Copyright (c) 2013-2017, Alfred Klomp
+Copyright 2012 the V8 project authors
+Copyright (c) 1999 Lucent Technologies
+Copyright (c) 2008-2016, Wojciech Mula
+Copyright (c) 2011-2020 Microsoft Corp
+Copyright (c) 2015-2017, Wojciech Mula
+Copyright (c) 2021 csFastFloat authors
+Copyright (c) 2005-2007, Nick Galbreath
+Copyright (c) 2015 The Chromium Authors
+Copyright (c) 2018 Alexander Chermyanin
+Copyright (c) The Internet Society 1997
+Portions (c) International Organization
+Copyright (c) 2004-2006 Intel Corporation
+Copyright (c) 2011-2015 Intel Corporation
+Copyright (c) 2013-2017, Milosz Krajewski
+Copyright (c) 2016-2017, Matthieu Darbois
+Copyright (c) The Internet Society (2003)
+Copyright (c) .NET Foundation Contributors
+Copyright (c) 2020 Mara Bos
+Copyright (c) .NET Foundation and Contributors
+Copyright (c) 2012 - present, Victor Zverovich
+Copyright (c) 2006 Jb Evain (jbevain@gmail.com)
+Copyright (c) 2008-2020 Advanced Micro Devices, Inc.
+Copyright (c) 2019 Microsoft Corporation, Daan Leijen
+Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler
+Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com)
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors
+Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com
+Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers
+Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip
+Copyright (c) 1980, 1986, 1993 The Regents of the University of California
+Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass
+
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Microsoft.Extensions.Configuration 6.0.1 - MIT
+
+
+(c) Microsoft Corporation
+Copyright (c) Andrew Arnott
+Copyright 2018 Daniel Lemire
+Copyright (c) .NET Foundation
+Copyright (c) 2011, Google Inc.
+Copyright (c) 2020 Dan Shechter
+(c) 1997-2005 Sean Eron Anderson
+Copyright (c) 1998 Microsoft. To
+Copyright (c) 2017 Yoshifumi Kawai
+Copyright (c) 2005-2020 Rich Felker
+Copyright (c) Microsoft Corporation
+Copyright (c) 2007 James Newton-King
+Copyright (c) 2012-2014, Yann Collet
+Copyright (c) 1991-2020 Unicode, Inc.
+Copyright (c) 2013-2017, Alfred Klomp
+Copyright 2012 the V8 project authors
+Copyright (c) 2011-2020 Microsoft Corp
+Copyright (c) 2015-2017, Wojciech Mula
+Copyright (c) 2005-2007, Nick Galbreath
+Copyright (c) 2015 The Chromium Authors
+Copyright (c) 2018 Alexander Chermyanin
+Copyright (c) The Internet Society 1997
+Portions (c) International Organization
+Copyright (c) 2004-2006 Intel Corporation
+Copyright (c) 2013-2017, Milosz Krajewski
+Copyright (c) 2016-2017, Matthieu Darbois
+Copyright (c) The Internet Society (2003)
+Copyright (c) .NET Foundation Contributors
+Copyright (c) .NET Foundation and Contributors
+Copyright (c) 2019 Microsoft Corporation, Daan Leijen
+Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler
+Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com)
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors
+Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com
+Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers
+Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip
+Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To
+
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Microsoft.Extensions.Configuration.Abstractions 6.0.0 - MIT
+
+
+(c) Microsoft Corporation
+Copyright (c) Andrew Arnott
+Copyright 2018 Daniel Lemire
+Copyright (c) .NET Foundation
+Copyright (c) 2011, Google Inc.
+Copyright (c) 2020 Dan Shechter
+(c) 1997-2005 Sean Eron Anderson
+Copyright (c) 1998 Microsoft. To
+Copyright (c) 2017 Yoshifumi Kawai
+Copyright (c) 2005-2020 Rich Felker
+Copyright (c) Microsoft Corporation
+Copyright (c) 2007 James Newton-King
+Copyright (c) 2012-2014, Yann Collet
+Copyright (c) 1991-2020 Unicode, Inc.
+Copyright (c) 2013-2017, Alfred Klomp
+Copyright 2012 the V8 project authors
+Copyright (c) 2011-2020 Microsoft Corp
+Copyright (c) 2015-2017, Wojciech Mula
+Copyright (c) 2005-2007, Nick Galbreath
+Copyright (c) 2015 The Chromium Authors
+Copyright (c) 2018 Alexander Chermyanin
+Copyright (c) The Internet Society 1997
+Portions (c) International Organization
+Copyright (c) 2004-2006 Intel Corporation
+Copyright (c) 2013-2017, Milosz Krajewski
+Copyright (c) 2016-2017, Matthieu Darbois
+Copyright (c) The Internet Society (2003)
+Copyright (c) .NET Foundation Contributors
+Copyright (c) .NET Foundation and Contributors
+Copyright (c) 2019 Microsoft Corporation, Daan Leijen
+Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler
+Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com)
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors
+Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com
+Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers
+Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip
+Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To
+
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Microsoft.Extensions.Configuration.Binder 6.0.0 - MIT
+
+
+(c) Microsoft Corporation
+Copyright (c) Andrew Arnott
+Copyright 2018 Daniel Lemire
+Copyright (c) .NET Foundation
+Copyright (c) 2011, Google Inc.
+Copyright (c) 2020 Dan Shechter
+(c) 1997-2005 Sean Eron Anderson
+Copyright (c) 1998 Microsoft. To
+Copyright (c) 2017 Yoshifumi Kawai
+Copyright (c) 2005-2020 Rich Felker
+Copyright (c) Microsoft Corporation
+Copyright (c) 2007 James Newton-King
+Copyright (c) 2012-2014, Yann Collet
+Copyright (c) 1991-2020 Unicode, Inc.
+Copyright (c) 2013-2017, Alfred Klomp
+Copyright 2012 the V8 project authors
+Copyright (c) 2011-2020 Microsoft Corp
+Copyright (c) 2015-2017, Wojciech Mula
+Copyright (c) 2005-2007, Nick Galbreath
+Copyright (c) 2015 The Chromium Authors
+Copyright (c) 2018 Alexander Chermyanin
+Copyright (c) The Internet Society 1997
+Portions (c) International Organization
+Copyright (c) 2004-2006 Intel Corporation
+Copyright (c) 2013-2017, Milosz Krajewski
+Copyright (c) 2016-2017, Matthieu Darbois
+Copyright (c) The Internet Society (2003)
+Copyright (c) .NET Foundation Contributors
+Copyright (c) .NET Foundation and Contributors
+Copyright (c) 2019 Microsoft Corporation, Daan Leijen
+Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler
+Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com)
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors
+Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com
+Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers
+Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip
+Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To
+
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Microsoft.Extensions.DependencyInjection 8.0.0 - MIT
+
+
+Copyright (c) Six Labors
+(c) Microsoft Corporation
+Copyright (c) Andrew Arnott
+Copyright 2019 LLVM Project
+Copyright 2018 Daniel Lemire
+Copyright (c) .NET Foundation
+Copyright (c) 2011, Google Inc.
+Copyright (c) 2020 Dan Shechter
+(c) 1997-2005 Sean Eron Anderson
+Copyright (c) 1998 Microsoft. To
+Copyright (c) 2022, Wojciech Mula
+Copyright (c) 2017 Yoshifumi Kawai
+Copyright (c) 2022, Geoff Langdale
+Copyright (c) 2005-2020 Rich Felker
+Copyright (c) 2012-2021 Yann Collet
+Copyright (c) Microsoft Corporation
+Copyright (c) 2007 James Newton-King
+Copyright (c) 1991-2022 Unicode, Inc.
+Copyright (c) 2013-2017, Alfred Klomp
+Copyright 2012 the V8 project authors
+Copyright (c) 1999 Lucent Technologies
+Copyright (c) 2008-2016, Wojciech Mula
+Copyright (c) 2011-2020 Microsoft Corp
+Copyright (c) 2015-2017, Wojciech Mula
+Copyright (c) 2021 csFastFloat authors
+Copyright (c) 2005-2007, Nick Galbreath
+Copyright (c) 2015 The Chromium Authors
+Copyright (c) 2018 Alexander Chermyanin
+Copyright (c) The Internet Society 1997
+Portions (c) International Organization
+Copyright (c) 2004-2006 Intel Corporation
+Copyright (c) 2011-2015 Intel Corporation
+Copyright (c) 2013-2017, Milosz Krajewski
+Copyright (c) 2016-2017, Matthieu Darbois
+Copyright (c) The Internet Society (2003)
+Copyright (c) .NET Foundation Contributors
+Copyright (c) 2020 Mara Bos
+Copyright (c) .NET Foundation and Contributors
+Copyright (c) 2012 - present, Victor Zverovich
+Copyright (c) 2006 Jb Evain (jbevain@gmail.com)
+Copyright (c) 2008-2020 Advanced Micro Devices, Inc.
+Copyright (c) 2019 Microsoft Corporation, Daan Leijen
+Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler
+Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com)
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors
+Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com
+Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers
+Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip
+Copyright (c) 1980, 1986, 1993 The Regents of the University of California
+Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass
+
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Microsoft.Extensions.DependencyInjection.Abstractions 8.0.0 - MIT
+
+
+Copyright (c) Six Labors
+(c) Microsoft Corporation
+Copyright (c) Andrew Arnott
+Copyright 2019 LLVM Project
+Copyright 2018 Daniel Lemire
+Copyright (c) .NET Foundation
+Copyright (c) 2011, Google Inc.
+Copyright (c) 2020 Dan Shechter
+(c) 1997-2005 Sean Eron Anderson
+Copyright (c) 1998 Microsoft. To
+Copyright (c) 2022, Wojciech Mula
+Copyright (c) 2017 Yoshifumi Kawai
+Copyright (c) 2022, Geoff Langdale
+Copyright (c) 2005-2020 Rich Felker
+Copyright (c) 2012-2021 Yann Collet
+Copyright (c) Microsoft Corporation
+Copyright (c) 2007 James Newton-King
+Copyright (c) 1991-2022 Unicode, Inc.
+Copyright (c) 2013-2017, Alfred Klomp
+Copyright 2012 the V8 project authors
+Copyright (c) 1999 Lucent Technologies
+Copyright (c) 2008-2016, Wojciech Mula
+Copyright (c) 2011-2020 Microsoft Corp
+Copyright (c) 2015-2017, Wojciech Mula
+Copyright (c) 2021 csFastFloat authors
+Copyright (c) 2005-2007, Nick Galbreath
+Copyright (c) 2015 The Chromium Authors
+Copyright (c) 2018 Alexander Chermyanin
+Copyright (c) The Internet Society 1997
+Portions (c) International Organization
+Copyright (c) 2004-2006 Intel Corporation
+Copyright (c) 2011-2015 Intel Corporation
+Copyright (c) 2013-2017, Milosz Krajewski
+Copyright (c) 2016-2017, Matthieu Darbois
+Copyright (c) The Internet Society (2003)
+Copyright (c) .NET Foundation Contributors
+Copyright (c) 2020 Mara Bos
+Copyright (c) .NET Foundation and Contributors
+Copyright (c) 2012 - present, Victor Zverovich
+Copyright (c) 2006 Jb Evain (jbevain@gmail.com)
+Copyright (c) 2008-2020 Advanced Micro Devices, Inc.
+Copyright (c) 2019 Microsoft Corporation, Daan Leijen
+Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler
+Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com)
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors
+Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com
+Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers
+Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip
+Copyright (c) 1980, 1986, 1993 The Regents of the University of California
+Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass
+
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Microsoft.Extensions.FileSystemGlobbing 8.0.0 - MIT
+
+
+Copyright (c) Six Labors
+(c) Microsoft Corporation
+Copyright (c) Andrew Arnott
+Copyright 2019 LLVM Project
+Copyright 2018 Daniel Lemire
+Copyright (c) .NET Foundation
+Copyright (c) 2011, Google Inc.
+Copyright (c) 2020 Dan Shechter
+(c) 1997-2005 Sean Eron Anderson
+Copyright (c) 1998 Microsoft. To
+Copyright (c) 2022, Wojciech Mula
+Copyright (c) 2017 Yoshifumi Kawai
+Copyright (c) 2022, Geoff Langdale
+Copyright (c) 2005-2020 Rich Felker
+Copyright (c) 2012-2021 Yann Collet
+Copyright (c) Microsoft Corporation
+Copyright (c) 2007 James Newton-King
+Copyright (c) 1991-2022 Unicode, Inc.
+Copyright (c) 2013-2017, Alfred Klomp
+Copyright 2012 the V8 project authors
+Copyright (c) 1999 Lucent Technologies
+Copyright (c) 2008-2016, Wojciech Mula
+Copyright (c) 2011-2020 Microsoft Corp
+Copyright (c) 2015-2017, Wojciech Mula
+Copyright (c) 2021 csFastFloat authors
+Copyright (c) 2005-2007, Nick Galbreath
+Copyright (c) 2015 The Chromium Authors
+Copyright (c) 2018 Alexander Chermyanin
+Copyright (c) The Internet Society 1997
+Portions (c) International Organization
+Copyright (c) 2004-2006 Intel Corporation
+Copyright (c) 2011-2015 Intel Corporation
+Copyright (c) 2013-2017, Milosz Krajewski
+Copyright (c) 2016-2017, Matthieu Darbois
+Copyright (c) The Internet Society (2003)
+Copyright (c) .NET Foundation Contributors
+Copyright (c) 2020 Mara Bos
+Copyright (c) .NET Foundation and Contributors
+Copyright (c) 2012 - present, Victor Zverovich
+Copyright (c) 2006 Jb Evain (jbevain@gmail.com)
+Copyright (c) 2008-2020 Advanced Micro Devices, Inc.
+Copyright (c) 2019 Microsoft Corporation, Daan Leijen
+Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler
+Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com)
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors
+Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com
+Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers
+Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip
+Copyright (c) 1980, 1986, 1993 The Regents of the University of California
+Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass
+
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Microsoft.Extensions.Logging 8.0.0 - MIT
+
+
+Copyright (c) Six Labors
+(c) Microsoft Corporation
+Copyright (c) Andrew Arnott
+Copyright 2019 LLVM Project
+Copyright 2018 Daniel Lemire
+Copyright (c) .NET Foundation
+Copyright (c) 2011, Google Inc.
+Copyright (c) 2020 Dan Shechter
+(c) 1997-2005 Sean Eron Anderson
+Copyright (c) 1998 Microsoft. To
+Copyright (c) 2022, Wojciech Mula
+Copyright (c) 2017 Yoshifumi Kawai
+Copyright (c) 2022, Geoff Langdale
+Copyright (c) 2005-2020 Rich Felker
+Copyright (c) 2012-2021 Yann Collet
+Copyright (c) Microsoft Corporation
+Copyright (c) 2007 James Newton-King
+Copyright (c) 1991-2022 Unicode, Inc.
+Copyright (c) 2013-2017, Alfred Klomp
+Copyright 2012 the V8 project authors
+Copyright (c) 1999 Lucent Technologies
+Copyright (c) 2008-2016, Wojciech Mula
+Copyright (c) 2011-2020 Microsoft Corp
+Copyright (c) 2015-2017, Wojciech Mula
+Copyright (c) 2021 csFastFloat authors
+Copyright (c) 2005-2007, Nick Galbreath
+Copyright (c) 2015 The Chromium Authors
+Copyright (c) 2018 Alexander Chermyanin
+Copyright (c) The Internet Society 1997
+Portions (c) International Organization
+Copyright (c) 2004-2006 Intel Corporation
+Copyright (c) 2011-2015 Intel Corporation
+Copyright (c) 2013-2017, Milosz Krajewski
+Copyright (c) 2016-2017, Matthieu Darbois
+Copyright (c) The Internet Society (2003)
+Copyright (c) .NET Foundation Contributors
+Copyright (c) 2020 Mara Bos
+Copyright (c) .NET Foundation and Contributors
+Copyright (c) 2012 - present, Victor Zverovich
+Copyright (c) 2006 Jb Evain (jbevain@gmail.com)
+Copyright (c) 2008-2020 Advanced Micro Devices, Inc.
+Copyright (c) 2019 Microsoft Corporation, Daan Leijen
+Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler
+Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com)
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors
+Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com
+Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers
+Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip
+Copyright (c) 1980, 1986, 1993 The Regents of the University of California
+Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass
+
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Microsoft.Extensions.Logging.Abstractions 8.0.0 - MIT
+
+
+Copyright (c) Six Labors
+(c) Microsoft Corporation
+Copyright (c) Andrew Arnott
+Copyright 2019 LLVM Project
+Copyright 2018 Daniel Lemire
+Copyright (c) .NET Foundation
+Copyright (c) 2011, Google Inc.
+Copyright (c) 2020 Dan Shechter
+(c) 1997-2005 Sean Eron Anderson
+Copyright (c) 1998 Microsoft. To
+Copyright (c) 2022, Wojciech Mula
+Copyright (c) 2017 Yoshifumi Kawai
+Copyright (c) 2022, Geoff Langdale
+Copyright (c) 2005-2020 Rich Felker
+Copyright (c) 2012-2021 Yann Collet
+Copyright (c) Microsoft Corporation
+Copyright (c) 2007 James Newton-King
+Copyright (c) 1991-2022 Unicode, Inc.
+Copyright (c) 2013-2017, Alfred Klomp
+Copyright 2012 the V8 project authors
+Copyright (c) 1999 Lucent Technologies
+Copyright (c) 2008-2016, Wojciech Mula
+Copyright (c) 2011-2020 Microsoft Corp
+Copyright (c) 2015-2017, Wojciech Mula
+Copyright (c) 2021 csFastFloat authors
+Copyright (c) 2005-2007, Nick Galbreath
+Copyright (c) 2015 The Chromium Authors
+Copyright (c) 2018 Alexander Chermyanin
+Copyright (c) The Internet Society 1997
+Portions (c) International Organization
+Copyright (c) 2004-2006 Intel Corporation
+Copyright (c) 2011-2015 Intel Corporation
+Copyright (c) 2013-2017, Milosz Krajewski
+Copyright (c) 2016-2017, Matthieu Darbois
+Copyright (c) The Internet Society (2003)
+Copyright (c) .NET Foundation Contributors
+Copyright (c) 2020 Mara Bos
+Copyright (c) .NET Foundation and Contributors
+Copyright (c) 2012 - present, Victor Zverovich
+Copyright (c) 2006 Jb Evain (jbevain@gmail.com)
+Copyright (c) 2008-2020 Advanced Micro Devices, Inc.
+Copyright (c) 2019 Microsoft Corporation, Daan Leijen
+Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler
+Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com)
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors
+Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com
+Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers
+Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip
+Copyright (c) 1980, 1986, 1993 The Regents of the University of California
+Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass
+
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Microsoft.Extensions.Options 8.0.0 - MIT
+
+
+Copyright (c) Six Labors
+(c) Microsoft Corporation
+Copyright (c) Andrew Arnott
+Copyright 2019 LLVM Project
+Copyright 2018 Daniel Lemire
+Copyright (c) .NET Foundation
+Copyright (c) 2011, Google Inc.
+Copyright (c) 2020 Dan Shechter
+(c) 1997-2005 Sean Eron Anderson
+Copyright (c) 1998 Microsoft. To
+Copyright (c) 2022, Wojciech Mula
+Copyright (c) 2017 Yoshifumi Kawai
+Copyright (c) 2022, Geoff Langdale
+Copyright (c) 2005-2020 Rich Felker
+Copyright (c) 2012-2021 Yann Collet
+Copyright (c) Microsoft Corporation
+Copyright (c) 2007 James Newton-King
+Copyright (c) 1991-2022 Unicode, Inc.
+Copyright (c) 2013-2017, Alfred Klomp
+Copyright 2012 the V8 project authors
+Copyright (c) 1999 Lucent Technologies
+Copyright (c) 2008-2016, Wojciech Mula
+Copyright (c) 2011-2020 Microsoft Corp
+Copyright (c) 2015-2017, Wojciech Mula
+Copyright (c) 2021 csFastFloat authors
+Copyright (c) 2005-2007, Nick Galbreath
+Copyright (c) 2015 The Chromium Authors
+Copyright (c) 2018 Alexander Chermyanin
+Copyright (c) The Internet Society 1997
+Portions (c) International Organization
+Copyright (c) 2004-2006 Intel Corporation
+Copyright (c) 2011-2015 Intel Corporation
+Copyright (c) 2013-2017, Milosz Krajewski
+Copyright (c) 2016-2017, Matthieu Darbois
+Copyright (c) The Internet Society (2003)
+Copyright (c) .NET Foundation Contributors
+Copyright (c) 2020 Mara Bos
+Copyright (c) .NET Foundation and Contributors
+Copyright (c) 2012 - present, Victor Zverovich
+Copyright (c) 2006 Jb Evain (jbevain@gmail.com)
+Copyright (c) 2008-2020 Advanced Micro Devices, Inc.
+Copyright (c) 2019 Microsoft Corporation, Daan Leijen
+Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler
+Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com)
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors
+Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com
+Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers
+Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip
+Copyright (c) 1980, 1986, 1993 The Regents of the University of California
+Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass
+
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Microsoft.Extensions.Options.ConfigurationExtensions 6.0.0 - MIT
+
+
+(c) Microsoft Corporation
+Copyright (c) Andrew Arnott
+Copyright 2018 Daniel Lemire
+Copyright (c) .NET Foundation
+Copyright (c) 2011, Google Inc.
+Copyright (c) 2020 Dan Shechter
+(c) 1997-2005 Sean Eron Anderson
+Copyright (c) 1998 Microsoft. To
+Copyright (c) 2017 Yoshifumi Kawai
+Copyright (c) 2005-2020 Rich Felker
+Copyright (c) Microsoft Corporation
+Copyright (c) 2007 James Newton-King
+Copyright (c) 2012-2014, Yann Collet
+Copyright (c) 1991-2020 Unicode, Inc.
+Copyright (c) 2013-2017, Alfred Klomp
+Copyright 2012 the V8 project authors
+Copyright (c) 2011-2020 Microsoft Corp
+Copyright (c) 2015-2017, Wojciech Mula
+Copyright (c) 2005-2007, Nick Galbreath
+Copyright (c) 2015 The Chromium Authors
+Copyright (c) 2018 Alexander Chermyanin
+Copyright (c) The Internet Society 1997
+Portions (c) International Organization
+Copyright (c) 2004-2006 Intel Corporation
+Copyright (c) 2013-2017, Milosz Krajewski
+Copyright (c) 2016-2017, Matthieu Darbois
+Copyright (c) The Internet Society (2003)
+Copyright (c) .NET Foundation Contributors
+Copyright (c) .NET Foundation and Contributors
+Copyright (c) 2019 Microsoft Corporation, Daan Leijen
+Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler
+Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com)
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors
+Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com
+Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers
+Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip
+Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To
+
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Microsoft.Extensions.Primitives 8.0.0 - MIT
+
+
+Copyright (c) Six Labors
+(c) Microsoft Corporation
+Copyright (c) Andrew Arnott
+Copyright 2019 LLVM Project
+Copyright 2018 Daniel Lemire
+Copyright (c) .NET Foundation
+Copyright (c) 2011, Google Inc.
+Copyright (c) 2020 Dan Shechter
+(c) 1997-2005 Sean Eron Anderson
+Copyright (c) 1998 Microsoft. To
+Copyright (c) 2022, Wojciech Mula
+Copyright (c) 2017 Yoshifumi Kawai
+Copyright (c) 2022, Geoff Langdale
+Copyright (c) 2005-2020 Rich Felker
+Copyright (c) 2012-2021 Yann Collet
+Copyright (c) Microsoft Corporation
+Copyright (c) 2007 James Newton-King
+Copyright (c) 1991-2022 Unicode, Inc.
+Copyright (c) 2013-2017, Alfred Klomp
+Copyright 2012 the V8 project authors
+Copyright (c) 1999 Lucent Technologies
+Copyright (c) 2008-2016, Wojciech Mula
+Copyright (c) 2011-2020 Microsoft Corp
+Copyright (c) 2015-2017, Wojciech Mula
+Copyright (c) 2021 csFastFloat authors
+Copyright (c) 2005-2007, Nick Galbreath
+Copyright (c) 2015 The Chromium Authors
+Copyright (c) 2018 Alexander Chermyanin
+Copyright (c) The Internet Society 1997
+Portions (c) International Organization
+Copyright (c) 2004-2006 Intel Corporation
+Copyright (c) 2011-2015 Intel Corporation
+Copyright (c) 2013-2017, Milosz Krajewski
+Copyright (c) 2016-2017, Matthieu Darbois
+Copyright (c) The Internet Society (2003)
+Copyright (c) .NET Foundation Contributors
+Copyright (c) 2020 Mara Bos
+Copyright (c) .NET Foundation and Contributors
+Copyright (c) 2012 - present, Victor Zverovich
+Copyright (c) 2006 Jb Evain (jbevain@gmail.com)
+Copyright (c) 2008-2020 Advanced Micro Devices, Inc.
+Copyright (c) 2019 Microsoft Corporation, Daan Leijen
+Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler
+Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com)
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors
+Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com
+Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers
+Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip
+Copyright (c) 1980, 1986, 1993 The Regents of the University of California
+Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass
+
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Microsoft.VisualStudio.Threading 17.6.40 - MIT
+
+
+(c) Andrew Arnott
+(c) 2019 GitHub, Inc.
+(c) Microsoft Corporation
+Copyright (c) Manuel Romer
+Copyright (c) Andrew Arnott
+Copyright 2019 LLVM Project
+Copyright 2018 Daniel Lemire
+Copyright (c) .NET Foundation
+Copyright 2012 the V8 project
+Copyright 1995-2017 Mark Adler
+Copyright (c) 2011, Google Inc.
+Copyright (c) 2020 Dan Shechter
+(c) 1997-2005 Sean Eron Anderson
+Copyright (c) 1998 Microsoft. To
+Copyright (c) Rackspace, US Inc.
+Copyright James Newton-King 2008
+Copyright (c) 2013 Scott Kirkland
+Copyright (c) 2014, Karlis Gangis
+Copyright (c) 2015 Dennis Fischer
+Copyright 2012-2017 Mehdi Khalili
+Copyright (c) 2015 .NET Foundation
+Copyright (c) 2015 Christian Klutz
+Copyright (c) 2017 Yoshifumi Kawai
+Copyright (c) 2005-2020 Rich Felker
+Copyright (c) Microsoft Corporation
+Copyright (c) Outercurve Foundation
+Copyright LibGit2Sharp contributors
+(c) Yoshifumi Kawai and contributors
+Copyright (c) 2007 James Newton-King
+Copyright (c) 2012-2014, Yann Collet
+Copyright (c) James Newton-King 2008
+Copyright (c) 1991-2017 Unicode, Inc.
+Copyright (c) 1991-2020 Unicode, Inc.
+Copyright (c) 1991-2022 Unicode, Inc.
+Copyright (c) 2012-2014 Mehdi Khalili
+Copyright (c) 2013-2014 Omar Khudeira
+Copyright (c) 2013-2017, Alfred Klomp
+Copyright (c) 1999 Lucent Technologies
+Copyright (c) 2008-2016, Wojciech Mula
+Copyright (c) 2011-2020 Microsoft Corp
+Copyright (c) 2015-2017, Wojciech Mula
+Copyright (c) 2021 csFastFloat authors
+Copyright (c) .NET Foundation xUnit.net
+Copyright (c) 2005-2007, Nick Galbreath
+Copyright (c) 2015 The Chromium Authors
+Copyright (c) 2018 Alexander Chermyanin
+Copyright (c) The Internet Society 1997
+Portions (c) International Organization
+Copyright (c) .NET Foundation 0xUnit.net
+Copyright (c) 2004-2006 Intel Corporation
+Copyright (c) 2013-2017, Milosz Krajewski
+Copyright (c) 2016-2017, Matthieu Darbois
+Copyright (c) The Internet Society (2003)
+Copyright James Newton-King 2008 Json.NET
+Copyright (c) .NET Foundation Contributors
+Copyright .NET Foundation and Contributors
+Copyright 1995-2017 Mark Adler +3 CScs DEFG
+Copyright 2012-2016 (c) 2008 VeriSign, Inc.
+Copyright (c) 2020 Mara Bos
+(c) Antoine Aubry and contributors 2008 - 2019
+Copyright (c) .NET Foundation and Contributors
+Copyright (c) Tunnel Vision Laboratories, LLC.
+Copyright AssemblyCompany AssemblyConfiguration
+Copyright (c) 2017 Yoshifumi Kawai and contributors
+Copyright 1995-2017 Jean-loup Gailly and Mark Adler
+Copyright (c) 2008-2020 Advanced Micro Devices, Inc.
+Copyright (c) 2019 Microsoft Corporation, Daan Leijen
+Copyright 2012-2016 Copyright 2012-2017 Mehdi Khalili
+Copyright (c) .NET Foundation xUnit.net Runner Utility
+Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+Copyright (c) .NET Foundation ,xUnit.net Runner Utility
+Copyright (c) .NET Foundation 1xUnit.net Runner Utility
+Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler
+Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler
+Copyright (c) .NET Foundation xUnit.net Runner Reporters
+Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com)
+Copyright (c) Antoine Aubry and contributors 2008 - 2019
+Copyright (c) .NET Foundation .xUnit.net Runner Reporters
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors
+Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com
+Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+Copyright (c) Outercurve Foundation WrapNonExceptionThrows RSDS
+Copyright (c) .NET Foundation and Contributors. Visual Studio 2019
+Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers
+Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip
+Copyright (c) 1980, 1986, 1993 The Regents of the University of California
+Copyright (c) .NET Foundation xunit.analyzers, analyzers, roslyn, xunit, xunit.net
+Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Antoine Aubry and contributors
+Copyright Tunnel Vision Laboratories, LLC 2018 1Copyright Tunnel Vision Laboratories, LLC 2018 NAn
+Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California
+Copyright 2018 Tunnel Vision Laboratories, LLC Documentation DotNetAnalyzers Roslyn Diagnostic Analyzer
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To
+
+MIT License
+
+Copyright (c)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Microsoft.VisualStudio.Threading.Analyzers 17.6.40 - MIT
+
+
+(c) Andrew Arnott
+(c) 2019 GitHub, Inc.
+(c) Microsoft Corporation
+Copyright (c) Manuel Romer
+Copyright (c) Andrew Arnott
+Copyright 2019 LLVM Project
+Copyright 2018 Daniel Lemire
+Copyright (c) .NET Foundation
+Copyright 2012 the V8 project
+Copyright 1995-2017 Mark Adler
+Copyright (c) 2011, Google Inc.
+Copyright (c) 2020 Dan Shechter
+(c) 1997-2005 Sean Eron Anderson
+Copyright (c) 1998 Microsoft. To
+Copyright (c) Rackspace, US Inc.
+Copyright James Newton-King 2008
+Copyright (c) 2013 Scott Kirkland
+Copyright (c) 2014, Karlis Gangis
+Copyright (c) 2015 Dennis Fischer
+Copyright 2012-2017 Mehdi Khalili
+Copyright (c) 2015 .NET Foundation
+Copyright (c) 2015 Christian Klutz
+Copyright (c) 2017 Yoshifumi Kawai
+Copyright (c) 2005-2020 Rich Felker
+Copyright (c) Microsoft Corporation
+Copyright (c) Outercurve Foundation
+Copyright LibGit2Sharp contributors
+(c) Yoshifumi Kawai and contributors
+Copyright (c) 2007 James Newton-King
+Copyright (c) 2012-2014, Yann Collet
+Copyright (c) James Newton-King 2008
+Copyright (c) 1991-2017 Unicode, Inc.
+Copyright (c) 1991-2020 Unicode, Inc.
+Copyright (c) 1991-2022 Unicode, Inc.
+Copyright (c) 2012-2014 Mehdi Khalili
+Copyright (c) 2013-2014 Omar Khudeira
+Copyright (c) 2013-2017, Alfred Klomp
+Copyright (c) 1999 Lucent Technologies
+Copyright (c) 2008-2016, Wojciech Mula
+Copyright (c) 2011-2020 Microsoft Corp
+Copyright (c) 2015-2017, Wojciech Mula
+Copyright (c) 2021 csFastFloat authors
+Copyright (c) .NET Foundation xUnit.net
+Copyright (c) 2005-2007, Nick Galbreath
+Copyright (c) 2015 The Chromium Authors
+Copyright (c) 2018 Alexander Chermyanin
+Copyright (c) The Internet Society 1997
+Portions (c) International Organization
+Copyright (c) .NET Foundation 0xUnit.net
+Copyright (c) 2004-2006 Intel Corporation
+Copyright (c) 2013-2017, Milosz Krajewski
+Copyright (c) 2016-2017, Matthieu Darbois
+Copyright (c) The Internet Society (2003)
+Copyright James Newton-King 2008 Json.NET
+Copyright (c) .NET Foundation Contributors
+Copyright .NET Foundation and Contributors
+Copyright 1995-2017 Mark Adler +3 CScs DEFG
+Copyright 2012-2016 (c) 2008 VeriSign, Inc.
+Copyright (c) 2020 Mara Bos
+(c) Antoine Aubry and contributors 2008 - 2019
+Copyright (c) .NET Foundation and Contributors
+Copyright (c) Tunnel Vision Laboratories, LLC.
+Copyright AssemblyCompany AssemblyConfiguration
+Copyright (c) 2017 Yoshifumi Kawai and contributors
+Copyright 1995-2017 Jean-loup Gailly and Mark Adler
+Copyright (c) 2008-2020 Advanced Micro Devices, Inc.
+Copyright (c) 2019 Microsoft Corporation, Daan Leijen
+Copyright 2012-2016 Copyright 2012-2017 Mehdi Khalili
+Copyright (c) .NET Foundation xUnit.net Runner Utility
+Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+Copyright (c) .NET Foundation ,xUnit.net Runner Utility
+Copyright (c) .NET Foundation 1xUnit.net Runner Utility
+Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler
+Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler
+Copyright (c) .NET Foundation xUnit.net Runner Reporters
+Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com)
+Copyright (c) Antoine Aubry and contributors 2008 - 2019
+Copyright (c) .NET Foundation .xUnit.net Runner Reporters
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors
+Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com
+Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+Copyright (c) Outercurve Foundation WrapNonExceptionThrows RSDS
+Copyright (c) .NET Foundation and Contributors. Visual Studio 2019
+Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers
+Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip
+Copyright (c) 1980, 1986, 1993 The Regents of the University of California
+Copyright (c) .NET Foundation xunit.analyzers, analyzers, roslyn, xunit, xunit.net
+Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Antoine Aubry and contributors
+Copyright Tunnel Vision Laboratories, LLC 2018 1Copyright Tunnel Vision Laboratories, LLC 2018 NAn
+Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California
+Copyright 2018 Tunnel Vision Laboratories, LLC Documentation DotNetAnalyzers Roslyn Diagnostic Analyzer
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To
+
+MIT License
+
+Copyright (c)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Microsoft.VisualStudio.Validation 17.6.11 - MIT
+
+
+(c) Microsoft Corporation
+Copyright (c) .NET Foundation
+Copyright 1995-2017 Mark Adler
+Copyright (c) Rackspace, US Inc.
+Copyright James Newton-King 2008
+Copyright (c) 2014, Karlis Gangis
+Copyright (c) 2015 Dennis Fischer
+Copyright (c) 2015 .NET Foundation
+Copyright (c) Outercurve Foundation
+Copyright LibGit2Sharp contributors
+Copyright (c) 2007 James Newton-King
+Copyright (c) James Newton-King 2008
+Copyright (c) .NET Foundation xUnit.net
+Copyright (c) .NET Foundation 0xUnit.net
+Copyright James Newton-King 2008 Json.NET
+Copyright 1995-2017 Mark Adler +3 CScs DEFG
+Copyright (c) .NET Foundation and Contributors
+Copyright (c) Tunnel Vision Laboratories, LLC.
+Copyright AssemblyCompany AssemblyConfiguration
+Copyright 1995-2017 Jean-loup Gailly and Mark Adler
+Copyright (c) .NET Foundation xUnit.net Runner Utility
+Copyright (c) .NET Foundation ,xUnit.net Runner Utility
+Copyright (c) .NET Foundation 1xUnit.net Runner Utility
+Copyright (c) .NET Foundation xUnit.net Runner Reporters
+Copyright (c) .NET Foundation .xUnit.net Runner Reporters
+(c) 2004-2022 Castle Project - http://www.castleproject.org
+Copyright (c) Outercurve Foundation WrapNonExceptionThrows RSDS
+Copyright 2004-2021 Castle Project - http://www.castleproject.org
+Copyright (c) .NET Foundation and Contributors. Visual Studio 2019
+Copyright (c) 2004-2022 Castle Project - http://www.castleproject.org
+Copyright (c) .NET Foundation xunit.analyzers, analyzers, roslyn, xunit, xunit.net
+Copyright (c) 2007, Clarius Consulting, Manas Technology Solutions, InSTEDD, and Contributors
+Copyright Tunnel Vision Laboratories, LLC 2018 1Copyright Tunnel Vision Laboratories, LLC 2018 NAn
+Copyright 2018 Tunnel Vision Laboratories, LLC Documentation DotNetAnalyzers Roslyn Diagnostic Analyzer
+
+NOTICES AND INFORMATION
+Do Not Translate or Localize
+
+This software incorporates material from third parties.
+Microsoft makes certain open source code available at https://3rdpartysource.microsoft.com,
+or you may send a check or money order for US $5.00, including the product name,
+the open source component name, platform, and version number, to:
+
+Source Code Compliance Team
+Microsoft Corporation
+One Microsoft Way
+Redmond, WA 98052
+USA
+
+Notwithstanding any other terms, you may reverse engineer this software to the extent
+required to debug changes to any libraries licensed under the GNU Lesser General Public License.
+
+---------------------------------------------------------
+
+Castle.Core 5.1.1 - Apache-2.0
+
+
+(c) 2004-2022 Castle Project - http://www.castleproject.org
+Copyright 2004-2021 Castle Project - http://www.castleproject.org
+Copyright (c) 2004-2022 Castle Project - http://www.castleproject.org
+
+Copyright 2004-2021 Castle Project - http://www.castleproject.org/
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+xunit 2.4.2 - Apache-2.0
+
+
+Copyright (c) .NET Foundation
+
+Apache License
+
+Version 2.0, January 2004
+
+http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+
+
+ "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+
+
+
+ "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+
+
+
+ "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+
+
+ "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
+
+
+
+ "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
+
+
+
+ "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
+
+
+
+ "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
+
+
+
+ "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+
+
+
+ "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
+
+
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
+
+ (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+
+you may not use this file except in compliance with the License.
+
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+
+distributed under the License is distributed on an "AS IS" BASIS,
+
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+
+See the License for the specific language governing permissions and
+
+limitations under the License.
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+xunit.abstractions 2.0.3 - Apache-2.0
+
+
+Copyright (c) Outercurve Foundation
+Copyright (c) Outercurve Foundation WrapNonExceptionThrows RSDS
+
+Apache License
+
+Version 2.0, January 2004
+
+http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+
+
+ "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+
+
+
+ "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+
+
+
+ "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+
+
+ "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
+
+
+
+ "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
+
+
+
+ "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
+
+
+
+ "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
+
+
+
+ "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+
+
+
+ "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
+
+
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
+
+ (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+
+you may not use this file except in compliance with the License.
+
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+
+distributed under the License is distributed on an "AS IS" BASIS,
+
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+
+See the License for the specific language governing permissions and
+
+limitations under the License.
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+xunit.analyzers 1.0.0 - Apache-2.0
+
+
+Copyright (c) .NET Foundation
+Copyright (c) .NET Foundation xUnit.net
+Copyright (c) .NET Foundation xunit.analyzers, analyzers, roslyn, xunit, xunit.net
+
+Apache License
+
+Version 2.0, January 2004
+
+http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+
+
+ "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+
+
+
+ "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+
+
+
+ "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+
+
+ "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
+
+
+
+ "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
+
+
+
+ "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
+
+
+
+ "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
+
+
+
+ "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+
+
+
+ "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
+
+
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
+
+ (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+
+you may not use this file except in compliance with the License.
+
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+
+distributed under the License is distributed on an "AS IS" BASIS,
+
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+
+See the License for the specific language governing permissions and
+
+limitations under the License.
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+xunit.assert 2.4.2 - Apache-2.0
+
+
+Copyright (c) .NET Foundation
+Copyright (c) .NET Foundation xUnit.net
+
+Apache License
+
+Version 2.0, January 2004
+
+http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+
+
+ "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+
+
+
+ "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+
+
+
+ "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+
+
+ "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
+
+
+
+ "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
+
+
+
+ "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
+
+
+
+ "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
+
+
+
+ "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+
+
+
+ "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
+
+
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
+
+ (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+
+you may not use this file except in compliance with the License.
+
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+
+distributed under the License is distributed on an "AS IS" BASIS,
+
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+
+See the License for the specific language governing permissions and
+
+limitations under the License.
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+xunit.core 2.4.2 - Apache-2.0
+
+
+Copyright (c) .NET Foundation
+
+Apache License
+
+Version 2.0, January 2004
+
+http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+
+
+ "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+
+
+
+ "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+
+
+
+ "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+
+
+ "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
+
+
+
+ "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
+
+
+
+ "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
+
+
+
+ "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
+
+
+
+ "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+
+
+
+ "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
+
+
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
+
+ (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+
+you may not use this file except in compliance with the License.
+
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+
+distributed under the License is distributed on an "AS IS" BASIS,
+
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+
+See the License for the specific language governing permissions and
+
+limitations under the License.
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+xunit.extensibility.core 2.4.2 - Apache-2.0
+
+
+Copyright (c) .NET Foundation
+Copyright (c) .NET Foundation xUnit.net
+Copyright (c) .NET Foundation 0xUnit.net
+Copyright (c) .NET Foundation xUnit.net Runner Utility
+
+Apache License
+
+Version 2.0, January 2004
+
+http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+
+
+ "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+
+
+
+ "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+
+
+
+ "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+
+
+ "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
+
+
+
+ "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
+
+
+
+ "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
+
+
+
+ "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
+
+
+
+ "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+
+
+
+ "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
+
+
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
+
+ (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+
+you may not use this file except in compliance with the License.
+
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+
+distributed under the License is distributed on an "AS IS" BASIS,
+
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+
+See the License for the specific language governing permissions and
+
+limitations under the License.
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+xunit.extensibility.execution 2.4.2 - Apache-2.0
+
+
+Copyright (c) .NET Foundation
+Copyright (c) .NET Foundation xUnit.net
+
+Apache License
+
+Version 2.0, January 2004
+
+http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+
+
+ "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+
+
+
+ "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+
+
+
+ "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+
+
+ "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
+
+
+
+ "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
+
+
+
+ "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
+
+
+
+ "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
+
+
+
+ "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+
+
+
+ "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
+
+
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
+
+ (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+
+you may not use this file except in compliance with the License.
+
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+
+distributed under the License is distributed on an "AS IS" BASIS,
+
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+
+See the License for the specific language governing permissions and
+
+limitations under the License.
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Moq 4.18.4 - BSD-3-Clause
+
+
+Copyright (c) 2007, Clarius Consulting, Manas Technology Solutions, InSTEDD, and Contributors
+
+Copyright (c) . All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+CSharpIsNullAnalyzer 0.1.329 - MIT
+
+
+Copyright (c) Andrew Arnott
+
+MIT License
+
+Copyright (c)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+DotNetAnalyzers.DocumentationAnalyzers 1.0.0-beta.59 - MIT
+
+
+Copyright (c) Rackspace, US Inc.
+Copyright (c) 2014, Karlis Gangis
+Copyright (c) 2015 Dennis Fischer
+Copyright (c) Tunnel Vision Laboratories, LLC.
+Copyright 2018 Tunnel Vision Laboratories, LLC Documentation DotNetAnalyzers Roslyn Diagnostic Analyzer
+
+The MIT License (MIT)
+
+Copyright (c) Tunnel Vision Laboratories, LLC
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+DotNetAnalyzers.DocumentationAnalyzers.Unstable 1.0.0.59 - MIT
+
+
+Copyright (c) Rackspace, US Inc.
+Copyright (c) 2014, Karlis Gangis
+Copyright (c) 2015 Dennis Fischer
+Copyright (c) Tunnel Vision Laboratories, LLC.
+Copyright Tunnel Vision Laboratories, LLC 2018
+1Copyright Tunnel Vision Laboratories, LLC 2018 NAn
+Copyright 2018 Tunnel Vision Laboratories, LLC Documentation DotNetAnalyzers Roslyn Diagnostic Analyzer
+
+The MIT License (MIT)
+
+Copyright (c) Tunnel Vision Laboratories, LLC
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Microsoft.Build.Tasks.Git 1.1.1 - MIT
+
+
+(c) Microsoft Corporation.
+
+MIT License
+
+Copyright (c)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Microsoft.SourceLink.Common 1.1.1 - MIT
+
+
+(c) Microsoft Corporation.
+
+MIT License
+
+Copyright (c)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Microsoft.SourceLink.GitHub 1.1.1 - MIT
+
+
+(c) Microsoft Corporation.
+
+MIT License
+
+Copyright (c)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Nerdbank.GitVersioning 3.5.119 - MIT
+
+
+Copyright 1995-2017 Mark Adler
+Copyright James Newton-King 2008
+Copyright LibGit2Sharp contributors
+Copyright James Newton-King 2008 Json.NET
+Copyright 1995-2017 Mark Adler +3 CScs DEFG
+Copyright (c) .NET Foundation and Contributors
+Copyright AssemblyCompany AssemblyConfiguration
+Copyright 1995-2017 Jean-loup Gailly and Mark Adler
+
+MIT License
+
+Copyright (c)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Newtonsoft.Json 13.0.1 - MIT
+
+
+Copyright James Newton-King 2008
+Copyright (c) 2007 James Newton-King
+Copyright (c) James Newton-King 2008
+Copyright James Newton-King 2008 Json.NET
+
+The MIT License (MIT)
+
+Copyright (c) 2007 James Newton-King
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Nullable 1.3.1 - MIT
+
+
+Copyright (c) Manuel Römer
+
+MIT License
+
+Copyright (c)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+StyleCop.Analyzers.Unstable 1.2.0.435 - MIT
+
+
+
+MIT License
+
+Copyright (c) Tunnel Vision Laboratories, LLC
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+xunit.runner.visualstudio 2.4.5 - MIT
+
+
+Copyright (c) .NET Foundation
+Copyright (c) 2015 .NET Foundation
+Copyright (c) Outercurve Foundation
+Copyright (c) .NET Foundation and Contributors
+Copyright (c) .NET Foundation xUnit.net Runner Utility
+Copyright (c) .NET Foundation ,xUnit.net Runner Utility
+Copyright (c) .NET Foundation 1xUnit.net Runner Utility
+Copyright (c) .NET Foundation xUnit.net Runner Reporters
+Copyright (c) .NET Foundation .xUnit.net Runner Reporters
+Copyright (c) Outercurve Foundation WrapNonExceptionThrows RSDS
+Copyright (c) .NET Foundation and Contributors. Visual Studio 2019
+
+Unless otherwise noted, the source code here is covered by the following license:
+
+ Copyright (c) .NET Foundation and Contributors
+ All Rights Reserved
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-----------------------
+
+The code in src/xunit.runner.visualstudio/Utility/AssemblyResolution/Microsoft.DotNet.PlatformAbstractions was imported from:
+ https://github.com/dotnet/core-setup/tree/v2.0.1/src/managed/Microsoft.DotNet.PlatformAbstractions
+
+The code in src/xunit.runner.visualstudio/Utility/AssemblyResolution/Microsoft.DotNet.PlatformAbstractions was imported from:
+ https://github.com/dotnet/core-setup/tree/v2.0.1/src/managed/Microsoft.Extensions.DependencyModel
+
+Both sets of code are covered by the following license:
+
+ The MIT License (MIT)
+
+ Copyright (c) 2015 .NET Foundation
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Procdump 0.0.1
+
+
+
+---------------------------------------------------------
+
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Nerdbank.Streams 2.10.69 - MIT
+
+
+(c) Andrew Arnott
+Copyright (c) .NET Foundation and Contributors
+
+MIT License
+
+Copyright (c)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+Newtonsoft.Json 13.0.3 - MIT
+
+
+Copyright James Newton-King 2008
+Copyright (c) 2007 James Newton-King
+Copyright (c) James Newton-King 2008
+Copyright James Newton-King 2008 Json.NET
+
+The MIT License (MIT)
+
+Copyright (c) 2007 James Newton-King
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+OmniSharp.Extensions.DebugAdapter 0.19.9 - MIT
+
+
+(c) Microsoft 2023
+Copyright OmniSharp and contributors
+Copyright OmniSharp and contributors (c) 2018
+Copyright (c) .NET Foundation and Contributors
+
+MIT License
+
+Copyright (c) .NET Foundation and Contributors
+All Rights Reserved
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+OmniSharp.Extensions.DebugAdapter.Client 0.19.9 - MIT
+
+
+(c) Microsoft 2023
+Copyright OmniSharp and contributors
+Copyright OmniSharp and contributors (c) 2018
+Copyright (c) .NET Foundation and Contributors
+
+MIT License
+
+Copyright (c) .NET Foundation and Contributors
+All Rights Reserved
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+OmniSharp.Extensions.DebugAdapter.Server 0.19.9 - MIT
+
+
+
+MIT License
+
+Copyright (c) .NET Foundation and Contributors
+All Rights Reserved
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+OmniSharp.Extensions.DebugAdapter.Shared 0.19.9 - MIT
+
+
+(c) Microsoft 2023
+Copyright OmniSharp and contributors
+Copyright OmniSharp and contributors (c) 2018
+Copyright (c) .NET Foundation and Contributors
+
+MIT License
+
+Copyright (c) .NET Foundation and Contributors
+All Rights Reserved
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+OmniSharp.Extensions.JsonRpc 0.19.9 - MIT
+
+
+(c) Microsoft 2023
+Copyright OmniSharp and contributors
+Copyright OmniSharp and contributors (c) 2018
+Copyright (c) .NET Foundation and Contributors
+
+MIT License
+
+Copyright (c) .NET Foundation and Contributors
+All Rights Reserved
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+OmniSharp.Extensions.JsonRpc.Generators 0.19.9 - MIT
+
+
+(c) Microsoft 2023
+Copyright OmniSharp and contributors
+Copyright OmniSharp and contributors (c) 2018
+Copyright (c) .NET Foundation and Contributors
+
+MIT License
+
+Copyright (c) .NET Foundation and Contributors
+All Rights Reserved
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+OmniSharp.Extensions.LanguageClient 0.19.9 - MIT
+
+
+(c) Microsoft 2023
+Copyright OmniSharp and contributors
+Copyright OmniSharp and contributors (c) 2018
+Copyright (c) .NET Foundation and Contributors
+
+MIT License
+
+Copyright (c) .NET Foundation and Contributors
+All Rights Reserved
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+OmniSharp.Extensions.LanguageProtocol 0.19.9 - MIT
+
+
+(c) Microsoft 2023
+Copyright OmniSharp and contributors
+Copyright OmniSharp and contributors (c) 2018
+Copyright (c) .NET Foundation and Contributors
+
+MIT License
+
+Copyright (c) .NET Foundation and Contributors
+All Rights Reserved
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+OmniSharp.Extensions.LanguageServer 0.19.9 - MIT
+
+
+(c) Microsoft 2023
+Copyright OmniSharp and contributors
+Copyright OmniSharp and contributors (c) 2018
+Copyright (c) .NET Foundation and Contributors
+
+MIT License
+
+Copyright (c) .NET Foundation and Contributors
+All Rights Reserved
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+OmniSharp.Extensions.LanguageServer.Shared 0.19.9 - MIT
+
+
+(c) Microsoft 2023
+Copyright OmniSharp and contributors
+Copyright OmniSharp and contributors (c) 2018
+Copyright (c) .NET Foundation and Contributors
+
+MIT License
+
+Copyright (c) .NET Foundation and Contributors
+All Rights Reserved
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+System.IO.Pipelines 7.0.0 - MIT
+
+
+(c) Microsoft Corporation
+Copyright (c) Andrew Arnott
+Copyright 2019 LLVM Project
+Copyright 2018 Daniel Lemire
+Copyright (c) .NET Foundation
+Copyright (c) 2011, Google Inc.
+Copyright (c) 2020 Dan Shechter
+(c) 1997-2005 Sean Eron Anderson
+Copyright (c) 1998 Microsoft. To
+Copyright (c) 2017 Yoshifumi Kawai
+Copyright (c) 2005-2020 Rich Felker
+Copyright (c) Microsoft Corporation
+Copyright (c) 2007 James Newton-King
+Copyright (c) 2012-2014, Yann Collet
+Copyright (c) 1991-2022 Unicode, Inc.
+Copyright (c) 2013-2017, Alfred Klomp
+Copyright 2012 the V8 project authors
+Copyright (c) 1999 Lucent Technologies
+Copyright (c) 2008-2016, Wojciech Mula
+Copyright (c) 2011-2020 Microsoft Corp
+Copyright (c) 2015-2017, Wojciech Mula
+Copyright (c) 2021 csFastFloat authors
+Copyright (c) 2005-2007, Nick Galbreath
+Copyright (c) 2015 The Chromium Authors
+Copyright (c) 2018 Alexander Chermyanin
+Copyright (c) The Internet Society 1997
+Portions (c) International Organization
+Copyright (c) 2004-2006 Intel Corporation
+Copyright (c) 2013-2017, Milosz Krajewski
+Copyright (c) 2016-2017, Matthieu Darbois
+Copyright (c) The Internet Society (2003)
+Copyright (c) .NET Foundation Contributors
+Copyright (c) 2020 Mara Bos
+Copyright (c) .NET Foundation and Contributors
+Copyright (c) 2008-2020 Advanced Micro Devices, Inc.
+Copyright (c) 2019 Microsoft Corporation, Daan Leijen
+Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+Copyright (c) 1995-2022 Jean-loup Gailly and Mark Adler
+Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com)
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors
+Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com
+Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers
+Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip
+Copyright (c) 1980, 1986, 1993 The Regents of the University of California
+Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To
+
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+System.IO.Pipes.AccessControl 5.0.0 - MIT
+
+
+(c) Microsoft Corporation.
+Copyright (c) Andrew Arnott
+Copyright 2018 Daniel Lemire
+Copyright 2012 the V8 project
+Copyright (c) .NET Foundation.
+Copyright (c) 2011, Google Inc.
+Copyright (c) 1998 Microsoft. To
+(c) 1997-2005 Sean Eron Anderson.
+Copyright (c) 2017 Yoshifumi Kawai
+Copyright (c) Microsoft Corporation
+Copyright (c) 2007 James Newton-King
+Copyright (c) 2012-2014, Yann Collet
+Copyright (c) 2013-2017, Alfred Klomp
+Copyright (c) 2015-2017, Wojciech Mula
+Copyright (c) 2005-2007, Nick Galbreath
+Copyright (c) 2018 Alexander Chermyanin
+Portions (c) International Organization
+Copyright (c) 2015 The Chromium Authors.
+Copyright (c) The Internet Society 1997.
+Copyright (c) 2004-2006 Intel Corporation
+Copyright (c) 2013-2017, Milosz Krajewski
+Copyright (c) 2016-2017, Matthieu Darbois
+Copyright (c) .NET Foundation Contributors
+Copyright (c) The Internet Society (2003).
+Copyright (c) .NET Foundation and Contributors
+Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler
+Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com)
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors.
+Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com
+Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
+Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS
+Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California.
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass.
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To
+
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+System.Memory 4.5.5 - MIT
+
+
+(c) 2022 GitHub, Inc.
+(c) Microsoft Corporation
+Copyright (c) 2011, Google Inc.
+(c) 1997-2005 Sean Eron Anderson
+Copyright (c) 1991-2017 Unicode, Inc.
+Copyright (c) 2015 The Chromium Authors
+Portions (c) International Organization
+Copyright (c) 2004-2006 Intel Corporation
+Copyright (c) .NET Foundation Contributors
+Copyright (c) .NET Foundation and Contributors
+Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler
+Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com)
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors
+Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers
+
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+System.Reactive 6.0.0 - MIT
+
+
+Copyright (c) .NET Foundation and Contributors
+Copyright (c) .NET Foundation and Contributors. Rx Reactive Extensions Observable LINQ Events
+
+MIT License
+
+Copyright (c)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+System.Runtime.CompilerServices.Unsafe 6.0.0 - MIT
+
+
+(c) Microsoft Corporation.
+Copyright (c) Andrew Arnott
+Copyright 2018 Daniel Lemire
+Copyright 2012 the V8 project
+Copyright (c) .NET Foundation.
+Copyright (c) 2011, Google Inc.
+Copyright (c) 1998 Microsoft. To
+(c) 1997-2005 Sean Eron Anderson.
+Copyright (c) 2017 Yoshifumi Kawai
+Copyright (c) Microsoft Corporation
+Copyright (c) 2007 James Newton-King
+Copyright (c) 2012-2014, Yann Collet
+Copyright (c) 2013-2017, Alfred Klomp
+Copyright (c) 2015-2017, Wojciech Mula
+Copyright (c) 2005-2007, Nick Galbreath
+Copyright (c) 2018 Alexander Chermyanin
+Portions (c) International Organization
+Copyright (c) 2015 The Chromium Authors.
+Copyright (c) The Internet Society 1997.
+Copyright (c) 2004-2006 Intel Corporation
+Copyright (c) 2013-2017, Milosz Krajewski
+Copyright (c) 2016-2017, Matthieu Darbois
+Copyright (c) .NET Foundation Contributors
+Copyright (c) The Internet Society (2003).
+Copyright (c) .NET Foundation and Contributors
+Copyright (c) 2019 Microsoft Corporation, Daan Leijen
+Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler
+Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com)
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors.
+Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com
+Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
+Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS
+Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California.
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass.
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To
+
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+System.Security.AccessControl 5.0.0 - MIT
+
+
+(c) Microsoft Corporation.
+Copyright (c) Andrew Arnott
+Copyright 2018 Daniel Lemire
+Copyright 2012 the V8 project
+Copyright (c) .NET Foundation.
+Copyright (c) 2011, Google Inc.
+Copyright (c) 1998 Microsoft. To
+(c) 1997-2005 Sean Eron Anderson.
+Copyright (c) 2017 Yoshifumi Kawai
+Copyright (c) Microsoft Corporation
+Copyright (c) 2007 James Newton-King
+Copyright (c) 2012-2014, Yann Collet
+Copyright (c) 2013-2017, Alfred Klomp
+Copyright (c) 2015-2017, Wojciech Mula
+Copyright (c) 2005-2007, Nick Galbreath
+Copyright (c) 2018 Alexander Chermyanin
+Portions (c) International Organization
+Copyright (c) 2015 The Chromium Authors.
+Copyright (c) The Internet Society 1997.
+Copyright (c) 2004-2006 Intel Corporation
+Copyright (c) 2013-2017, Milosz Krajewski
+Copyright (c) 2016-2017, Matthieu Darbois
+Copyright (c) .NET Foundation Contributors
+Copyright (c) The Internet Society (2003).
+Copyright (c) .NET Foundation and Contributors
+Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler
+Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com)
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors.
+Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com
+Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
+Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS
+Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California.
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass.
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To
+
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+System.Threading.Channels 6.0.0 - MIT
+
+
+(c) Microsoft Corporation.
+Copyright (c) Andrew Arnott
+Copyright 2018 Daniel Lemire
+Copyright 2012 the V8 project
+Copyright (c) .NET Foundation.
+Copyright (c) 2011, Google Inc.
+Copyright (c) 1998 Microsoft. To
+(c) 1997-2005 Sean Eron Anderson.
+Copyright (c) 2017 Yoshifumi Kawai
+Copyright (c) Microsoft Corporation
+Copyright (c) 2007 James Newton-King
+Copyright (c) 2012-2014, Yann Collet
+Copyright (c) 2013-2017, Alfred Klomp
+Copyright (c) 2015-2017, Wojciech Mula
+Copyright (c) 2005-2007, Nick Galbreath
+Copyright (c) 2018 Alexander Chermyanin
+Portions (c) International Organization
+Copyright (c) 2015 The Chromium Authors.
+Copyright (c) The Internet Society 1997.
+Copyright (c) 2004-2006 Intel Corporation
+Copyright (c) 2013-2017, Milosz Krajewski
+Copyright (c) 2016-2017, Matthieu Darbois
+Copyright (c) .NET Foundation Contributors
+Copyright (c) The Internet Society (2003).
+Copyright (c) .NET Foundation and Contributors
+Copyright (c) 2019 Microsoft Corporation, Daan Leijen
+Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler
+Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com)
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors.
+Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com
+Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
+Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers THIS WORK IS PROVIDED AS
+Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California.
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass.
+Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass. To
+
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
+
+---------------------------------------------------------
+
+System.ValueTuple 4.5.0 - MIT
+
+
+(c) 2023 GitHub, Inc.
+(c) Microsoft Corporation
+Copyright (c) 2011, Google Inc.
+(c) 1997-2005 Sean Eron Anderson
+Copyright (c) 1991-2017 Unicode, Inc.
+Copyright (c) 2015 The Chromium Authors
+Portions (c) International Organization
+Copyright (c) 2004-2006 Intel Corporation
+Copyright (c) .NET Foundation Contributors
+Copyright (c) .NET Foundation and Contributors
+Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+Copyright (c) 1995-2017 Jean-loup Gailly and Mark Adler
+Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com)
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors
+Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang). Disclaimers
+
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+---------------------------------------------------------
diff --git a/PowerShellEditorServices.Common.props b/PowerShellEditorServices.Common.props
index 80d45b7ba..2af5f41b1 100644
--- a/PowerShellEditorServices.Common.props
+++ b/PowerShellEditorServices.Common.props
@@ -1,6 +1,6 @@
- 3.18.1
+ 4.6.0
Microsoft
© Microsoft Corporation.
@@ -11,8 +11,6 @@
git
https://github.com/PowerShell/PowerShellEditorServices
portable
-
- true
true
true
diff --git a/PowerShellEditorServices.build.ps1 b/PowerShellEditorServices.build.ps1
index 7c0319a95..62cb53369 100644
--- a/PowerShellEditorServices.build.ps1
+++ b/PowerShellEditorServices.build.ps1
@@ -7,11 +7,7 @@ param(
[switch]$LocalOmniSharp,
- [string]$PsesSubmodulePath = "$PSScriptRoot/module",
-
- [string]$ModulesJsonPath = "$PSScriptRoot/modules.json",
-
- [string]$DefaultModuleRepository = "PSGallery",
+ [string]$PSRepository = "PSGallery",
[string]$Verbosity = "minimal",
@@ -22,8 +18,8 @@ param(
[string[]]$TestArgs = @("--logger", "console;verbosity=minimal", "--logger", "trx")
)
-#Requires -Modules @{ModuleName="InvokeBuild"; ModuleVersion="5.0.0"}
-#Requires -Modules @{ModuleName="platyPS"; ModuleVersion="0.14.0"}
+#Requires -Modules @{ModuleName = "InvokeBuild"; ModuleVersion = "5.0.0"}
+#Requires -Modules @{ModuleName = "platyPS"; ModuleVersion = "0.14.2"}
$script:dotnetBuildArgs = @(
"--verbosity"
@@ -40,29 +36,21 @@ $script:dotnetTestArgs = @("test") + $script:dotnetBuildArgs + $TestArgs + @(
)
$script:IsNix = $IsLinux -or $IsMacOS
-# For Apple M1, pwsh might be getting emulated, in which case we need to check
-# for the proc_translated flag, otherwise we can check the architecture.
-$script:IsAppleM1 = $IsMacOS -and ((sysctl -n sysctl.proc_translated 2> $null) -eq 1 -or
- [System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture -eq "Arm64")
-$script:IsArm64 = -not $script:IsNix -and @("ARM64") -contains $env:PROCESSOR_ARCHITECTURE
-$script:BuildInfoPath = [System.IO.Path]::Combine($PSScriptRoot, "src", "PowerShellEditorServices.Hosting", "BuildInfo.cs")
-$script:PsesCommonProps = [xml](Get-Content -Raw "$PSScriptRoot/PowerShellEditorServices.Common.props")
+$script:BuildInfoPath = "src/PowerShellEditorServices.Hosting/BuildInfo.cs"
$script:NetFramework = @{
PS51 = 'net462'
- PS72 = 'net6.0'
- PS73 = 'net7.0'
PS74 = 'net8.0'
Standard = 'netstandard2.0'
}
-$script:HostCoreOutput = "$PSScriptRoot/src/PowerShellEditorServices.Hosting/bin/$Configuration/$($script:NetFramework.PS72)/publish"
-$script:HostDeskOutput = "$PSScriptRoot/src/PowerShellEditorServices.Hosting/bin/$Configuration/$($script:NetFramework.PS51)/publish"
-$script:PsesOutput = "$PSScriptRoot/src/PowerShellEditorServices/bin/$Configuration/$($script:NetFramework.Standard)/publish"
+$script:HostCoreOutput = "src/PowerShellEditorServices.Hosting/bin/$Configuration/$($script:NetFramework.PS74)/publish"
+$script:HostDeskOutput = "src/PowerShellEditorServices.Hosting/bin/$Configuration/$($script:NetFramework.PS51)/publish"
+$script:PsesOutput = "src/PowerShellEditorServices/bin/$Configuration/$($script:NetFramework.Standard)/publish"
if (Get-Command git -ErrorAction SilentlyContinue) {
# ignore changes to this file
- git update-index --assume-unchanged "$PSScriptRoot/src/PowerShellEditorServices.Hosting/BuildInfo.cs"
+ git update-index --assume-unchanged $script:BuildInfoPath
}
Task FindDotNet {
@@ -72,61 +60,36 @@ Task FindDotNet {
[Version]$existingVersion, $null = (dotnet --version) -split " " -split "-"
Assert ($existingVersion -ge [Version]("8.0")) ".NET SDK 8.0 or higher is required, please update it: https://aka.ms/dotnet-cli"
- Write-Host "Using dotnet v$(dotnet --version) at path $((Get-Command dotnet).Source)" -ForegroundColor Green
+ Write-Build DarkGreen "Using dotnet v$(dotnet --version) at path $((Get-Command dotnet).Source)"
}
-Task BinClean {
- Remove-BuildItem $PSScriptRoot\.tmp
- Remove-BuildItem $PSScriptRoot\module\PowerShellEditorServices\bin
-}
-
-Task Clean FindDotNet, BinClean, {
+Task Clean FindDotNet, {
+ Write-Build DarkMagenta "Cleaning PowerShellEditorServices"
Invoke-BuildExec { & dotnet clean --verbosity $Verbosity }
- Remove-BuildItem $PSScriptRoot\src\*.nupkg
- Remove-BuildItem $PSScriptRoot\PowerShellEditorServices*.zip
- Remove-BuildItem $PSScriptRoot\module\PowerShellEditorServices\Commands\en-US\*-help.xml
-
- # Remove bundled component modules
- $moduleJsonPath = "$PSScriptRoot\modules.json"
- if (Test-Path $moduleJsonPath) {
- Get-Content -Raw $moduleJsonPath |
- ConvertFrom-Json |
- ForEach-Object { $_.PSObject.Properties.Name } |
- ForEach-Object { Remove-BuildItem -Path "$PSScriptRoot/module/$_" }
- }
+ Remove-BuildItem module/PowerShellEditorServices/bin
+ Remove-BuildItem module/PowerShellEditorServices/Commands/en-US/*-help.xml
+ Remove-BuildItem module/PSReadLine
+ Remove-BuildItem module/PSScriptAnalyzer
}
Task CreateBuildInfo {
- $buildVersion = ""
$buildOrigin = "Development"
$buildCommit = git rev-parse HEAD
+ [xml]$xml = Get-Content "PowerShellEditorServices.Common.props"
+ $buildVersion = $xml.Project.PropertyGroup.VersionPrefix
+ $prerelease = $xml.Project.PropertyGroup.VersionSuffix
+ if ($prerelease) { $buildVersion += "-$prerelease" }
+
# Set build info fields on build platforms
- if ($env:TF_BUILD) {
- if ($env:BUILD_BUILDNUMBER -like "PR-*") {
- $buildOrigin = "PR"
- } elseif ($env:BUILD_DEFINITIONNAME -like "*-CI") {
- $buildOrigin = "CI"
- } else {
+ if ($env:TF_BUILD) { # Azure DevOps AKA OneBranch
+ if ($env:BUILD_REASON -like "Manual") {
$buildOrigin = "Release"
+ } else {
+ $buildOrigin = "AzureDevOps-CI"
}
-
- $propsXml = [xml](Get-Content -Raw -LiteralPath "$PSScriptRoot/PowerShellEditorServices.Common.props")
- $propsBody = $propsXml.Project.PropertyGroup
- $buildVersion = $propsBody.VersionPrefix
-
- if ($propsBody.VersionSuffix) {
- $buildVersion += '-' + $propsBody.VersionSuffix
- }
- }
-
- # Allow override of build info fields (except date)
- if ($env:PSES_BUILD_VERSION) {
- $buildVersion = $env:PSES_BUILD_VERSION
- }
-
- if ($env:PSES_BUILD_ORIGIN) {
- $buildOrigin = $env:PSES_BUILD_ORIGIN
+ } elseif ($env:GITHUB_ACTIONS) {
+ $buildOrigin = "GitHub-CI"
}
[string]$buildTime = [datetime]::Today.ToString("s", [System.Globalization.CultureInfo]::InvariantCulture)
@@ -150,49 +113,183 @@ namespace Microsoft.PowerShell.EditorServices.Hosting
"@
if (Compare-Object $buildInfoContents.Split([Environment]::NewLine) (Get-Content $script:BuildInfoPath)) {
- Write-Host "Updating build info."
+ Write-Build DarkMagenta "Updating build info"
Set-Content -LiteralPath $script:BuildInfoPath -Value $buildInfoContents -Force
}
}
-Task SetupHelpForTests {
- # TODO: Check if it must be updated in a compatible way!
- Write-Host "Updating help for tests."
- Update-Help -Module Microsoft.PowerShell.Management,Microsoft.PowerShell.Utility -Force -Scope CurrentUser -UICulture en-US
+task RestorePsesModules {
+ # NOTE: When updating module versions, ensure they are also saved to the CFS feed
+ if (-not (Test-Path "module/PSScriptAnalyzer")) {
+ Write-Build DarkMagenta "Restoring PSScriptAnalyzer module"
+ Save-PSResource -Path module -Name PSScriptAnalyzer -Version "1.25.0" -Repository $PSRepository -TrustRepository -Verbose
+ }
+ if (-not (Test-Path "module/PSReadLine")) {
+ Write-Build DarkMagenta "Restoring PSReadLine module"
+ Save-PSResource -Path module -Name PSReadLine -Version "2.4.5" -Repository $PSRepository -TrustRepository -Verbose
+ }
}
-Task Build FindDotNet, CreateBuildInfo, {
- Invoke-BuildExec { & dotnet publish $script:dotnetBuildArgs .\src\PowerShellEditorServices\PowerShellEditorServices.csproj -f $script:NetFramework.Standard }
- Invoke-BuildExec { & dotnet publish $script:dotnetBuildArgs .\src\PowerShellEditorServices.Hosting\PowerShellEditorServices.Hosting.csproj -f $script:NetFramework.PS72 }
+Task Build FindDotNet, CreateBuildInfo, RestorePsesModules, {
+ Write-Build DarkGreen 'Building PowerShellEditorServices'
+ Invoke-BuildExec { & dotnet publish $script:dotnetBuildArgs ./src/PowerShellEditorServices/PowerShellEditorServices.csproj -f $script:NetFramework.Standard }
+ Invoke-BuildExec { & dotnet publish $script:dotnetBuildArgs ./src/PowerShellEditorServices.Hosting/PowerShellEditorServices.Hosting.csproj -f $script:NetFramework.PS74 }
if (-not $script:IsNix) {
- Invoke-BuildExec { & dotnet publish $script:dotnetBuildArgs .\src\PowerShellEditorServices.Hosting\PowerShellEditorServices.Hosting.csproj -f $script:NetFramework.PS51 }
+ Invoke-BuildExec { & dotnet publish $script:dotnetBuildArgs ./src/PowerShellEditorServices.Hosting/PowerShellEditorServices.Hosting.csproj -f $script:NetFramework.PS51 }
}
+} -If {
+ $Null -eq $script:ChangesDetected -or $true -eq $script:ChangesDetected
}
-# The concise set of tests (for pull requests)
-Task Test TestPS74, TestE2EPwsh, TestPS51, TestE2EPowerShell
+Task AssembleModule -After Build {
+ Write-Build DarkGreen 'Assembling PowerShellEditorServices module'
+ $psesOutputPath = './module/PowerShellEditorServices'
+ $psesBinOutputPath = "$psesOutputPath/bin"
+ $psesDepsPath = "$psesBinOutputPath/Common"
+ $psesCoreHostPath = "$psesBinOutputPath/Core"
+ $psesDeskHostPath = "$psesBinOutputPath/Desktop"
+
+ foreach ($dir in $psesDepsPath, $psesCoreHostPath, $psesDeskHostPath) {
+ New-Item -Force -Path $dir -ItemType Directory | Out-Null
+ }
-# Every combination of tests (for main branch)
-Task TestFull Test, TestPS73, TestPS72, TestE2EPwshCLM, TestE2EPowerShellCLM
+ # Copy documents to module root
+ foreach ($document in @('LICENSE', 'NOTICE.txt', 'README.md', 'SECURITY.md')) {
+ Copy-Item -Force -Path $document -Destination './module'
+ }
-Task TestPS74 Build, SetupHelpForTests, {
- Set-Location .\test\PowerShellEditorServices.Test\
- Invoke-BuildExec { & dotnet $script:dotnetTestArgs $script:NetFramework.PS74 }
+ # Assemble PSES module
+ $includedDlls = [System.Collections.Generic.HashSet[string]]::new()
+ [void]$includedDlls.Add('System.Management.Automation.dll')
+
+ # PSES/bin/Common
+ foreach ($psesComponent in Get-ChildItem $script:PsesOutput) {
+ if ($psesComponent.Name -eq 'System.Management.Automation.dll' -or
+ $psesComponent.Name -eq 'System.Runtime.InteropServices.RuntimeInformation.dll') {
+ continue
+ }
+
+ if ($psesComponent.Extension) {
+ [void]$includedDlls.Add($psesComponent.Name)
+ Copy-Item -Path $psesComponent.FullName -Destination $psesDepsPath -Force
+ }
+ }
+
+ # PSES/bin/Core
+ foreach ($hostComponent in Get-ChildItem $script:HostCoreOutput) {
+ if (-not $includedDlls.Contains($hostComponent.Name)) {
+ Copy-Item -Path $hostComponent.FullName -Destination $psesCoreHostPath -Force
+ }
+ }
+
+ # PSES/bin/Desktop
+ if (-not $script:IsNix) {
+ foreach ($hostComponent in Get-ChildItem $script:HostDeskOutput) {
+ if (-not $includedDlls.Contains($hostComponent.Name)) {
+ Copy-Item -Path $hostComponent.FullName -Destination $psesDeskHostPath -Force
+ }
+ }
+ }
}
-Task TestPS73 Build, SetupHelpForTests, {
- Set-Location .\test\PowerShellEditorServices.Test\
- Invoke-BuildExec { & dotnet $script:dotnetTestArgs $script:NetFramework.PS73 }
+Task BuildCmdletHelp -After AssembleModule {
+ Write-Build DarkGreen 'Building cmdlet help'
+ New-ExternalHelp -Path ./module/docs -OutputPath ./module/PowerShellEditorServices/Commands/en-US -Force
+}
+
+Task SetupHelpForTests {
+ # Some CI do not ship with help included, and the secure devops pipeline also does not allow internet access, so we must update help from our local repository source.
+
+ # Only commands in Microsoft.PowerShell.Archive can be tested for help so as to minimize the repository storage.
+ # This requires admin rights for PS5.1
+
+ # NOTE: You can run this task once as admin or update help separately, and continue to run tests as non-admin, if for instance developing locally.
+
+ $installHelpScript = {
+ param(
+ [Parameter(Position = 0)][string]$helpPath
+ )
+ $PSVersion = $PSVersionTable.PSVersion
+ $ErrorActionPreference = 'Stop'
+ $helpPath = Resolve-Path $helpPath
+ if ($PSEdition -ne 'Desktop') {
+ $helpPath = Join-Path $helpPath '7'
+ }
+
+ if ((Get-Help Expand-Archive).remarks -notlike 'Get-Help cannot find the Help files*') {
+ Write-Host -ForegroundColor Green "PowerShell $PSVersion Archive help is already installed"
+ return
+ }
+
+ if ($PSEdition -eq 'Desktop') {
+ # Cant use requires RunAsAdministrator because PS isn't smart enough to know this is a subscript.
+ if (-not [Security.Principal.WindowsPrincipal]::new(
+ [Security.Principal.WindowsIdentity]::GetCurrent()
+ ).IsInRole(
+ [Security.Principal.WindowsBuiltInRole]::Administrator
+ )) {
+ throw 'Windows PowerShell Update-Help requires admin rights. Please re-run the script in an elevated PowerShell session!'
+ }
+ }
+
+ Write-Host -ForegroundColor Magenta "PowerShell $PSVersion Archive help is not installed, installing from $helpPath"
+
+ $updateHelpParams = @{
+ Module = 'Microsoft.PowerShell.Archive'
+ SourcePath = $helpPath
+ UICulture = 'en-US'
+ Force = $true
+ Verbose = $true
+ }
+
+ # PS7+ does not require admin rights if CurrentUser is used for scope. PS5.1 does not have this option.
+ if ($PSEdition -ne 'Desktop') {
+ $updateHelpParams.'Scope' = 'CurrentUser'
+ }
+ # Update the help and capture verbose output
+ $updateHelpOutput = Update-Help @updateHelpParams *>&1
+
+ if ((Get-Help Expand-Archive).remarks -like 'Get-Help cannot find the Help files*') {
+ throw "Failed to install PowerShell $PSVersion Help: $updateHelpOutput"
+ } else {
+ Write-Host -ForegroundColor Green "PowerShell $PSVersion Archive help installed successfully"
+ }
+ }
+
+ # Need this to inject the help file path since PSScriptRoot won't work inside the script
+ $helpPath = Resolve-Path "$PSScriptRoot\test\PowerShellEditorServices.Test.Shared\PSHelp" -ErrorAction Stop
+ Write-Build DarkMagenta "Runner help located at $helpPath"
+
+ if (Get-Command powershell.exe -CommandType Application -ea 0) {
+ Write-Build DarkMagenta 'Checking PowerShell 5.1 help'
+ & powershell.exe -NoProfile -NonInteractive -Command $installHelpScript -args $helpPath
+ if ($LASTEXITCODE -ne 0) {
+ throw 'Failed to install PowerShell 5.1 help!'
+ }
+ }
+
+ if ($PwshPreview -and (Get-Command $PwshPreview -ea 0)) {
+ Write-Build DarkMagenta "Checking PowerShell Preview help at $PwshPreview"
+ Invoke-BuildExec { & $PwshPreview -NoProfile -NonInteractive -Command $installHelpScript -args $helpPath }
+ if ($LASTEXITCODE -ne 0) {
+ throw 'Failed to install PowerShell Preview help!'
+ }
+ }
+
+ if ($PSEdition -eq 'Core') {
+ Write-Build DarkMagenta "Checking this PowerShell process's help"
+ & $installHelpScript $helpPath
+ }
}
-Task TestPS72 Build, SetupHelpForTests, {
- Set-Location .\test\PowerShellEditorServices.Test\
- Invoke-BuildExec { & dotnet $script:dotnetTestArgs $script:NetFramework.PS72 }
+Task TestPS74 Build, SetupHelpForTests, {
+ Set-Location ./test/PowerShellEditorServices.Test/
+ Invoke-BuildExec { & dotnet $script:dotnetTestArgs $script:NetFramework.PS74 }
}
Task TestPS51 -If (-not $script:IsNix) Build, SetupHelpForTests, {
- Set-Location .\test\PowerShellEditorServices.Test\
+ Set-Location ./test/PowerShellEditorServices.Test/
# TODO: See https://github.com/dotnet/sdk/issues/18353 for x64 test host
# that is debuggable! If architecture is added, the assembly path gets an
# additional folder, necessitating fixes to find the commands definition
@@ -201,7 +298,7 @@ Task TestPS51 -If (-not $script:IsNix) Build, SetupHelpForTests, {
# TODO: See https://github.com/PowerShell/vscode-powershell/issues/3886
# Inheriting the module path for powershell.exe breaks things!
$originalModulePath = $env:PSModulePath
- $env:PSModulePath = ""
+ $env:PSModulePath = ''
Invoke-BuildExec { & dotnet $script:dotnetTestArgs $script:NetFramework.PS51 }
} finally {
$env:PSModulePath = $originalModulePath
@@ -211,32 +308,33 @@ Task TestPS51 -If (-not $script:IsNix) Build, SetupHelpForTests, {
# NOTE: The framework for the E2E tests applies to the mock client, and so
# should just be the latest supported framework.
Task TestE2EPwsh Build, SetupHelpForTests, {
- Set-Location .\test\PowerShellEditorServices.Test.E2E\
- $env:PWSH_EXE_NAME = "pwsh"
+ Set-Location ./test/PowerShellEditorServices.Test.E2E/
+ $env:PWSH_EXE_NAME = 'pwsh'
Invoke-BuildExec { & dotnet $script:dotnetTestArgs $script:NetFramework.PS74 }
}
-$PwshDaily = if ($script:IsNix) {
- "$HOME/.powershell-daily/pwsh"
+if ($env:GITHUB_ACTIONS) {
+ $PwshPreview = if ($script:IsNix) { "$PSScriptRoot/preview/pwsh" } else { "$PSScriptRoot/preview/pwsh.exe" }
} else {
- "$env:LOCALAPPDATA\Microsoft\powershell-daily\pwsh.exe"
+ $PwshPreview = if ($script:IsNix) { "$HOME/.powershell-preview/pwsh" } else { "$env:LOCALAPPDATA/Microsoft/powershell-preview/pwsh.exe" }
}
-Task TestE2EDaily -If (Test-Path $PwshDaily) Build, SetupHelpForTests, {
- Set-Location .\test\PowerShellEditorServices.Test.E2E\
- $env:PWSH_EXE_NAME = $PwshDaily
- Write-Host "Running end-to-end tests with: $(& $PwshDaily --version)"
+Task TestE2EPreview -If (-not $env:TF_BUILD) Build, SetupHelpForTests, {
+ Assert (Test-Path $PwshPreview) "PowerShell Preview not found at $PwshPreview, please install it: https://github.com/PowerShell/PowerShell/blob/master/tools/install-powershell.ps1"
+ Set-Location ./test/PowerShellEditorServices.Test.E2E/
+ $env:PWSH_EXE_NAME = $PwshPreview
+ Write-Build DarkGreen "Running end-to-end tests with: $(& $PwshPreview --version)"
Invoke-BuildExec { & dotnet $script:dotnetTestArgs $script:NetFramework.PS74 }
}
Task TestE2EPowerShell -If (-not $script:IsNix) Build, SetupHelpForTests, {
- Set-Location .\test\PowerShellEditorServices.Test.E2E\
- $env:PWSH_EXE_NAME = "powershell"
+ Set-Location ./test/PowerShellEditorServices.Test.E2E/
+ $env:PWSH_EXE_NAME = 'powershell'
try {
# TODO: See https://github.com/PowerShell/vscode-powershell/issues/3886
# Inheriting the module path for powershell.exe breaks things!
$originalModulePath = $env:PSModulePath
- $env:PSModulePath = ""
+ $env:PSModulePath = ''
Invoke-BuildExec { & dotnet $script:dotnetTestArgs $script:NetFramework.PS74 }
} finally {
$env:PSModulePath = $originalModulePath
@@ -244,150 +342,65 @@ Task TestE2EPowerShell -If (-not $script:IsNix) Build, SetupHelpForTests, {
}
Task TestE2EPwshCLM -If (-not $script:IsNix) Build, SetupHelpForTests, {
- Set-Location .\test\PowerShellEditorServices.Test.E2E\
- $env:PWSH_EXE_NAME = "pwsh"
+ Set-Location ./test/PowerShellEditorServices.Test.E2E/
+ $env:PWSH_EXE_NAME = 'pwsh'
- if (-not [Security.Principal.WindowsIdentity]::GetCurrent().Owner.IsWellKnown("BuiltInAdministratorsSid")) {
- Write-Warning "Skipping Constrained Language Mode tests as they must be ran in an elevated process."
+ if (-not [Security.Principal.WindowsIdentity]::GetCurrent().Owner.IsWellKnown('BuiltInAdministratorsSid')) {
+ Write-Build DarkRed 'Skipping Constrained Language Mode tests as they must be ran in an elevated process'
return
}
try {
- Write-Host "Running end-to-end tests in Constrained Language Mode."
- [System.Environment]::SetEnvironmentVariable("__PSLockdownPolicy", "0x80000007", [System.EnvironmentVariableTarget]::Machine)
+ Write-Build DarkGreen 'Running end-to-end tests in Constrained Language Mode'
+ [System.Environment]::SetEnvironmentVariable('__PSLockdownPolicy', '0x80000007', [System.EnvironmentVariableTarget]::Machine)
Invoke-BuildExec { & dotnet $script:dotnetTestArgs $script:NetFramework.PS74 }
} finally {
- [System.Environment]::SetEnvironmentVariable("__PSLockdownPolicy", $null, [System.EnvironmentVariableTarget]::Machine)
+ [System.Environment]::SetEnvironmentVariable('__PSLockdownPolicy', $null, [System.EnvironmentVariableTarget]::Machine)
}
}
Task TestE2EPowerShellCLM -If (-not $script:IsNix) Build, SetupHelpForTests, {
- Set-Location .\test\PowerShellEditorServices.Test.E2E\
- $env:PWSH_EXE_NAME = "powershell"
+ Set-Location ./test/PowerShellEditorServices.Test.E2E/
+ $env:PWSH_EXE_NAME = 'powershell'
- if (-not [Security.Principal.WindowsIdentity]::GetCurrent().Owner.IsWellKnown("BuiltInAdministratorsSid")) {
- Write-Warning "Skipping Constrained Language Mode tests as they must be ran in an elevated process."
+ if (-not [Security.Principal.WindowsIdentity]::GetCurrent().Owner.IsWellKnown('BuiltInAdministratorsSid')) {
+ Write-Build DarkRed 'Skipping Constrained Language Mode tests as they must be ran in an elevated process'
return
}
try {
- Write-Host "Running end-to-end tests in Constrained Language Mode."
- [System.Environment]::SetEnvironmentVariable("__PSLockdownPolicy", "0x80000007", [System.EnvironmentVariableTarget]::Machine)
+ Write-Build DarkGreen 'Running end-to-end tests in Constrained Language Mode'
+ [System.Environment]::SetEnvironmentVariable('__PSLockdownPolicy', '0x80000007', [System.EnvironmentVariableTarget]::Machine)
# TODO: See https://github.com/PowerShell/vscode-powershell/issues/3886
# Inheriting the module path for powershell.exe breaks things!
$originalModulePath = $env:PSModulePath
- $env:PSModulePath = ""
+ $env:PSModulePath = ''
Invoke-BuildExec { & dotnet $script:dotnetTestArgs $script:NetFramework.PS74 }
} finally {
- [System.Environment]::SetEnvironmentVariable("__PSLockdownPolicy", $null, [System.EnvironmentVariableTarget]::Machine)
+ [System.Environment]::SetEnvironmentVariable('__PSLockdownPolicy', $null, [System.EnvironmentVariableTarget]::Machine)
$env:PSModulePath = $originalModulePath
}
}
-Task LayoutModule -After Build {
- $modulesDir = "$PSScriptRoot/module"
- $psesOutputPath = "$modulesDir/PowerShellEditorServices"
- $psesBinOutputPath = "$PSScriptRoot/module/PowerShellEditorServices/bin"
- $psesDepsPath = "$psesBinOutputPath/Common"
- $psesCoreHostPath = "$psesBinOutputPath/Core"
- $psesDeskHostPath = "$psesBinOutputPath/Desktop"
-
- foreach ($dir in $psesDepsPath, $psesCoreHostPath, $psesDeskHostPath) {
- New-Item -Force -Path $dir -ItemType Directory | Out-Null
- }
-
- # Copy Third Party Notices.txt to module folder
- Copy-Item -Force -Path "$PSScriptRoot\Third Party Notices.txt" -Destination $psesOutputPath
-
- # Assemble PSES module
-
- $includedDlls = [System.Collections.Generic.HashSet[string]]::new()
- [void]$includedDlls.Add('System.Management.Automation.dll')
-
- # PSES/bin/Common
- foreach ($psesComponent in Get-ChildItem $script:PsesOutput) {
- if ($psesComponent.Name -eq 'System.Management.Automation.dll' -or
- $psesComponent.Name -eq 'System.Runtime.InteropServices.RuntimeInformation.dll') {
- continue
- }
-
- if ($psesComponent.Extension) {
- [void]$includedDlls.Add($psesComponent.Name)
- Copy-Item -Path $psesComponent.FullName -Destination $psesDepsPath -Force
- }
- }
-
- # PSES/bin/Core
- foreach ($hostComponent in Get-ChildItem $script:HostCoreOutput) {
- if (-not $includedDlls.Contains($hostComponent.Name)) {
- Copy-Item -Path $hostComponent.FullName -Destination $psesCoreHostPath -Force
- }
- }
-
- # PSES/bin/Desktop
- if (-not $script:IsNix) {
- foreach ($hostComponent in Get-ChildItem $script:HostDeskOutput) {
- if (-not $includedDlls.Contains($hostComponent.Name)) {
- Copy-Item -Path $hostComponent.FullName -Destination $psesDeskHostPath -Force
- }
- }
- }
+Task BuildIfChanged.Init -Before BuildIfChanged {
+ [bool]$script:ChangesDetected = $false
}
-task RestorePsesModules -After Build {
- $submodulePath = (Resolve-Path $PsesSubmodulePath).Path + [IO.Path]::DirectorySeparatorChar
- Write-Host "Restoring EditorServices modules..."
-
- # Read in the modules.json file as a hashtable so it can be splatted
- $moduleInfos = @{}
-
- (Get-Content -Raw $ModulesJsonPath | ConvertFrom-Json).PSObject.Properties | ForEach-Object {
- $name = $_.Name
- $body = @{
- Name = $name
- Version = $_.Value.Version
- AllowPrerelease = $_.Value.AllowPrerelease
- Repository = if ($_.Value.Repository) { $_.Value.Repository } else { $DefaultModuleRepository }
- Path = $submodulePath
- }
-
- if (-not $name) {
- throw "EditorServices module listed without name in '$ModulesJsonPath'"
- }
-
- $moduleInfos.Add($name, $body)
- }
-
- # Save each module in the modules.json file
- foreach ($moduleName in $moduleInfos.Keys) {
- if (Test-Path -Path (Join-Path -Path $submodulePath -ChildPath $moduleName)) {
- Write-Host "`tModule '${moduleName}' already detected, skipping!"
- continue
- }
-
- $moduleInstallDetails = $moduleInfos[$moduleName]
+Task BuildIfChanged -Inputs {
+ $slash = [IO.Path]::DirectorySeparatorChar
+ Get-ChildItem ./src -Filter '*.cs' -Recurse
+ | Where-Object FullName -NotLike ('*' + $slash + 'obj' + $slash + '*')
+ | Where-Object FullName -NotLike ('*' + $slash + 'bin' + $slash + '*')
+} -Outputs {
+ './src/PowerShellEditorServices/bin/Debug/netstandard2.0/Microsoft.PowerShell.EditorServices.dll'
+ './src/PowerShellEditorServices.Hosting/bin/Debug/net8.0/Microsoft.PowerShell.EditorServices.Hosting.dll'
+} -Jobs {
+ Write-Build DarkMagenta 'Changes detected, rebuilding'
+ $script:ChangesDetected = $true
+}, Build
- $splatParameters = @{
- Name = $moduleName
- RequiredVersion = $moduleInstallDetails.Version
- Repository = if ($moduleInstallDetails.Repository) { $moduleInstallDetails.Repository } else { $DefaultModuleRepository }
- Path = $submodulePath
- }
-
- # There's a bug in PowerShell get where this argument isn't correctly translated when it's false.
- if ($moduleInstallDetails.AllowPrerelease) {
- $splatParameters["AllowPrerelease"] = $moduleInstallDetails.AllowPrerelease
- }
-
- Write-Host "`tInstalling module: ${moduleName} with arguments $(ConvertTo-Json $splatParameters)"
-
- Save-Module @splatParameters
- }
-}
+Task Test TestPS74, TestE2EPwsh, TestPS51, TestE2EPowerShell
-Task BuildCmdletHelp -After LayoutModule {
- New-ExternalHelp -Path $PSScriptRoot\module\docs -OutputPath $PSScriptRoot\module\PowerShellEditorServices\Commands\en-US -Force | Out-Null
-}
+Task TestFull Test, TestE2EPreview, TestE2EPwshCLM, TestE2EPowerShellCLM
-# The default task is to run the entire CI build
Task . Clean, Build, Test
diff --git a/PowerShellEditorServices.sln b/PowerShellEditorServices.sln
index c41d92df0..754851233 100644
--- a/PowerShellEditorServices.sln
+++ b/PowerShellEditorServices.sln
@@ -3,158 +3,55 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F594E7FD-1E72-4E51-A496-B019C2BA3180}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{F46EF430-95AA-4386-9259-292A443AB715}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{422E561A-8118-4BE7-A54F-9309E4F03AAE}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerShellEditorServices.Test.Shared", "test\PowerShellEditorServices.Test.Shared\PowerShellEditorServices.Test.Shared.csproj", "{9D307AF9-D1F7-4185-AE9B-2DD3F178832C}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerShellEditorServices.Test", "test\PowerShellEditorServices.Test\PowerShellEditorServices.Test.csproj", "{8ED116F4-9DDF-4C49-AB96-AE462E3D64C3}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerShellEditorServices.Test", "test\PowerShellEditorServices.Test\PowerShellEditorServices.Test.csproj", "{DFD3C9C2-F9E6-4EE3-B614-A8EA7D1E1A98}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerShellEditorServices.Test.Shared", "test\PowerShellEditorServices.Test.Shared\PowerShellEditorServices.Test.Shared.csproj", "{6A20B9E9-DE66-456E-B4F5-ACFD1A95C3CA}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerShellEditorServices.Test.E2E", "test\PowerShellEditorServices.Test.E2E\PowerShellEditorServices.Test.E2E.csproj", "{AA007633-5178-4D73-A262-CCE7247BDE93}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{E2316F5C-A551-4A8D-8103-E42CA6D757E2}"
- ProjectSection(SolutionItems) = preProject
- scripts\AddCopyrightHeaders.ps1 = scripts\AddCopyrightHeaders.ps1
- EndProjectSection
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F40C4EC9-AE86-4A26-974F-95381888DCDC}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerShellEditorServices", "src\PowerShellEditorServices\PowerShellEditorServices.csproj", "{29EEDF03-0990-45F4-846E-2616970D1FA2}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerShellEditorServices", "src\PowerShellEditorServices\PowerShellEditorServices.csproj", "{B4431254-9A2F-43DE-A998-12B22A1593CE}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerShellEditorServices.Test.E2E", "test\PowerShellEditorServices.Test.E2E\PowerShellEditorServices.Test.E2E.csproj", "{2561F253-8F72-436A-BCC3-AA63AB82EDC0}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerShellEditorServices.Hosting", "src\PowerShellEditorServices.Hosting\PowerShellEditorServices.Hosting.csproj", "{3CC791E7-6FC9-4DDE-B4A2-547266977E4E}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerShellEditorServices.Hosting", "src\PowerShellEditorServices.Hosting\PowerShellEditorServices.Hosting.csproj", "{983D05F2-3C77-4B51-9A28-A8C6595911BA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
- CoreCLR|Any CPU = CoreCLR|Any CPU
- CoreCLR|x64 = CoreCLR|x64
- CoreCLR|x86 = CoreCLR|x86
Debug|Any CPU = Debug|Any CPU
- Debug|x64 = Debug|x64
- Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
- Release|x64 = Release|x64
- Release|x86 = Release|x86
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {8ED116F4-9DDF-4C49-AB96-AE462E3D64C3}.CoreCLR|Any CPU.ActiveCfg = Release|Any CPU
- {8ED116F4-9DDF-4C49-AB96-AE462E3D64C3}.CoreCLR|Any CPU.Build.0 = Release|Any CPU
- {8ED116F4-9DDF-4C49-AB96-AE462E3D64C3}.CoreCLR|x64.ActiveCfg = Release|Any CPU
- {8ED116F4-9DDF-4C49-AB96-AE462E3D64C3}.CoreCLR|x64.Build.0 = Release|Any CPU
- {8ED116F4-9DDF-4C49-AB96-AE462E3D64C3}.CoreCLR|x86.ActiveCfg = Release|Any CPU
- {8ED116F4-9DDF-4C49-AB96-AE462E3D64C3}.CoreCLR|x86.Build.0 = Release|Any CPU
- {8ED116F4-9DDF-4C49-AB96-AE462E3D64C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {8ED116F4-9DDF-4C49-AB96-AE462E3D64C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {8ED116F4-9DDF-4C49-AB96-AE462E3D64C3}.Debug|x64.ActiveCfg = Debug|Any CPU
- {8ED116F4-9DDF-4C49-AB96-AE462E3D64C3}.Debug|x64.Build.0 = Debug|Any CPU
- {8ED116F4-9DDF-4C49-AB96-AE462E3D64C3}.Debug|x86.ActiveCfg = Debug|Any CPU
- {8ED116F4-9DDF-4C49-AB96-AE462E3D64C3}.Debug|x86.Build.0 = Debug|Any CPU
- {8ED116F4-9DDF-4C49-AB96-AE462E3D64C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {8ED116F4-9DDF-4C49-AB96-AE462E3D64C3}.Release|Any CPU.Build.0 = Release|Any CPU
- {8ED116F4-9DDF-4C49-AB96-AE462E3D64C3}.Release|x64.ActiveCfg = Release|Any CPU
- {8ED116F4-9DDF-4C49-AB96-AE462E3D64C3}.Release|x64.Build.0 = Release|Any CPU
- {8ED116F4-9DDF-4C49-AB96-AE462E3D64C3}.Release|x86.ActiveCfg = Release|Any CPU
- {8ED116F4-9DDF-4C49-AB96-AE462E3D64C3}.Release|x86.Build.0 = Release|Any CPU
- {6A20B9E9-DE66-456E-B4F5-ACFD1A95C3CA}.CoreCLR|Any CPU.ActiveCfg = Release|Any CPU
- {6A20B9E9-DE66-456E-B4F5-ACFD1A95C3CA}.CoreCLR|Any CPU.Build.0 = Release|Any CPU
- {6A20B9E9-DE66-456E-B4F5-ACFD1A95C3CA}.CoreCLR|x64.ActiveCfg = Release|Any CPU
- {6A20B9E9-DE66-456E-B4F5-ACFD1A95C3CA}.CoreCLR|x64.Build.0 = Release|Any CPU
- {6A20B9E9-DE66-456E-B4F5-ACFD1A95C3CA}.CoreCLR|x86.ActiveCfg = Release|Any CPU
- {6A20B9E9-DE66-456E-B4F5-ACFD1A95C3CA}.CoreCLR|x86.Build.0 = Release|Any CPU
- {6A20B9E9-DE66-456E-B4F5-ACFD1A95C3CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {6A20B9E9-DE66-456E-B4F5-ACFD1A95C3CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {6A20B9E9-DE66-456E-B4F5-ACFD1A95C3CA}.Debug|x64.ActiveCfg = Debug|Any CPU
- {6A20B9E9-DE66-456E-B4F5-ACFD1A95C3CA}.Debug|x64.Build.0 = Debug|Any CPU
- {6A20B9E9-DE66-456E-B4F5-ACFD1A95C3CA}.Debug|x86.ActiveCfg = Debug|Any CPU
- {6A20B9E9-DE66-456E-B4F5-ACFD1A95C3CA}.Debug|x86.Build.0 = Debug|Any CPU
- {6A20B9E9-DE66-456E-B4F5-ACFD1A95C3CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {6A20B9E9-DE66-456E-B4F5-ACFD1A95C3CA}.Release|Any CPU.Build.0 = Release|Any CPU
- {6A20B9E9-DE66-456E-B4F5-ACFD1A95C3CA}.Release|x64.ActiveCfg = Release|Any CPU
- {6A20B9E9-DE66-456E-B4F5-ACFD1A95C3CA}.Release|x64.Build.0 = Release|Any CPU
- {6A20B9E9-DE66-456E-B4F5-ACFD1A95C3CA}.Release|x86.ActiveCfg = Release|Any CPU
- {6A20B9E9-DE66-456E-B4F5-ACFD1A95C3CA}.Release|x86.Build.0 = Release|Any CPU
- {3B38E8DA-8BFF-4264-AF16-47929E6398A3}.CoreCLR|Any CPU.ActiveCfg = CoreCLR|Any CPU
- {3B38E8DA-8BFF-4264-AF16-47929E6398A3}.CoreCLR|Any CPU.Build.0 = CoreCLR|Any CPU
- {3B38E8DA-8BFF-4264-AF16-47929E6398A3}.CoreCLR|x64.ActiveCfg = CoreCLR|Any CPU
- {3B38E8DA-8BFF-4264-AF16-47929E6398A3}.CoreCLR|x64.Build.0 = CoreCLR|Any CPU
- {3B38E8DA-8BFF-4264-AF16-47929E6398A3}.CoreCLR|x86.ActiveCfg = CoreCLR|Any CPU
- {3B38E8DA-8BFF-4264-AF16-47929E6398A3}.CoreCLR|x86.Build.0 = CoreCLR|Any CPU
- {3B38E8DA-8BFF-4264-AF16-47929E6398A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {3B38E8DA-8BFF-4264-AF16-47929E6398A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {3B38E8DA-8BFF-4264-AF16-47929E6398A3}.Debug|x64.ActiveCfg = Debug|Any CPU
- {3B38E8DA-8BFF-4264-AF16-47929E6398A3}.Debug|x64.Build.0 = Debug|Any CPU
- {3B38E8DA-8BFF-4264-AF16-47929E6398A3}.Debug|x86.ActiveCfg = Debug|Any CPU
- {3B38E8DA-8BFF-4264-AF16-47929E6398A3}.Debug|x86.Build.0 = Debug|Any CPU
- {3B38E8DA-8BFF-4264-AF16-47929E6398A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {3B38E8DA-8BFF-4264-AF16-47929E6398A3}.Release|Any CPU.Build.0 = Release|Any CPU
- {3B38E8DA-8BFF-4264-AF16-47929E6398A3}.Release|x64.ActiveCfg = Release|Any CPU
- {3B38E8DA-8BFF-4264-AF16-47929E6398A3}.Release|x64.Build.0 = Release|Any CPU
- {3B38E8DA-8BFF-4264-AF16-47929E6398A3}.Release|x86.ActiveCfg = Release|Any CPU
- {3B38E8DA-8BFF-4264-AF16-47929E6398A3}.Release|x86.Build.0 = Release|Any CPU
- {29EEDF03-0990-45F4-846E-2616970D1FA2}.CoreCLR|Any CPU.ActiveCfg = Release|Any CPU
- {29EEDF03-0990-45F4-846E-2616970D1FA2}.CoreCLR|Any CPU.Build.0 = Release|Any CPU
- {29EEDF03-0990-45F4-846E-2616970D1FA2}.CoreCLR|x64.ActiveCfg = Release|Any CPU
- {29EEDF03-0990-45F4-846E-2616970D1FA2}.CoreCLR|x64.Build.0 = Release|Any CPU
- {29EEDF03-0990-45F4-846E-2616970D1FA2}.CoreCLR|x86.ActiveCfg = Release|Any CPU
- {29EEDF03-0990-45F4-846E-2616970D1FA2}.CoreCLR|x86.Build.0 = Release|Any CPU
- {29EEDF03-0990-45F4-846E-2616970D1FA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {29EEDF03-0990-45F4-846E-2616970D1FA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {29EEDF03-0990-45F4-846E-2616970D1FA2}.Debug|x64.ActiveCfg = Debug|Any CPU
- {29EEDF03-0990-45F4-846E-2616970D1FA2}.Debug|x64.Build.0 = Debug|Any CPU
- {29EEDF03-0990-45F4-846E-2616970D1FA2}.Debug|x86.ActiveCfg = Debug|Any CPU
- {29EEDF03-0990-45F4-846E-2616970D1FA2}.Debug|x86.Build.0 = Debug|Any CPU
- {29EEDF03-0990-45F4-846E-2616970D1FA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {29EEDF03-0990-45F4-846E-2616970D1FA2}.Release|Any CPU.Build.0 = Release|Any CPU
- {29EEDF03-0990-45F4-846E-2616970D1FA2}.Release|x64.ActiveCfg = Release|Any CPU
- {29EEDF03-0990-45F4-846E-2616970D1FA2}.Release|x64.Build.0 = Release|Any CPU
- {29EEDF03-0990-45F4-846E-2616970D1FA2}.Release|x86.ActiveCfg = Release|Any CPU
- {29EEDF03-0990-45F4-846E-2616970D1FA2}.Release|x86.Build.0 = Release|Any CPU
- {2561F253-8F72-436A-BCC3-AA63AB82EDC0}.CoreCLR|Any CPU.ActiveCfg = Release|Any CPU
- {2561F253-8F72-436A-BCC3-AA63AB82EDC0}.CoreCLR|Any CPU.Build.0 = Release|Any CPU
- {2561F253-8F72-436A-BCC3-AA63AB82EDC0}.CoreCLR|x64.ActiveCfg = Release|Any CPU
- {2561F253-8F72-436A-BCC3-AA63AB82EDC0}.CoreCLR|x64.Build.0 = Release|Any CPU
- {2561F253-8F72-436A-BCC3-AA63AB82EDC0}.CoreCLR|x86.ActiveCfg = Release|Any CPU
- {2561F253-8F72-436A-BCC3-AA63AB82EDC0}.CoreCLR|x86.Build.0 = Release|Any CPU
- {2561F253-8F72-436A-BCC3-AA63AB82EDC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {2561F253-8F72-436A-BCC3-AA63AB82EDC0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {2561F253-8F72-436A-BCC3-AA63AB82EDC0}.Debug|x64.ActiveCfg = Debug|Any CPU
- {2561F253-8F72-436A-BCC3-AA63AB82EDC0}.Debug|x64.Build.0 = Debug|Any CPU
- {2561F253-8F72-436A-BCC3-AA63AB82EDC0}.Debug|x86.ActiveCfg = Debug|Any CPU
- {2561F253-8F72-436A-BCC3-AA63AB82EDC0}.Debug|x86.Build.0 = Debug|Any CPU
- {2561F253-8F72-436A-BCC3-AA63AB82EDC0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {2561F253-8F72-436A-BCC3-AA63AB82EDC0}.Release|Any CPU.Build.0 = Release|Any CPU
- {2561F253-8F72-436A-BCC3-AA63AB82EDC0}.Release|x64.ActiveCfg = Release|Any CPU
- {2561F253-8F72-436A-BCC3-AA63AB82EDC0}.Release|x64.Build.0 = Release|Any CPU
- {2561F253-8F72-436A-BCC3-AA63AB82EDC0}.Release|x86.ActiveCfg = Release|Any CPU
- {2561F253-8F72-436A-BCC3-AA63AB82EDC0}.Release|x86.Build.0 = Release|Any CPU
- {3CC791E7-6FC9-4DDE-B4A2-547266977E4E}.CoreCLR|Any CPU.ActiveCfg = Release|Any CPU
- {3CC791E7-6FC9-4DDE-B4A2-547266977E4E}.CoreCLR|Any CPU.Build.0 = Release|Any CPU
- {3CC791E7-6FC9-4DDE-B4A2-547266977E4E}.CoreCLR|x64.ActiveCfg = Release|Any CPU
- {3CC791E7-6FC9-4DDE-B4A2-547266977E4E}.CoreCLR|x64.Build.0 = Release|Any CPU
- {3CC791E7-6FC9-4DDE-B4A2-547266977E4E}.CoreCLR|x86.ActiveCfg = Release|Any CPU
- {3CC791E7-6FC9-4DDE-B4A2-547266977E4E}.CoreCLR|x86.Build.0 = Release|Any CPU
- {3CC791E7-6FC9-4DDE-B4A2-547266977E4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {3CC791E7-6FC9-4DDE-B4A2-547266977E4E}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {3CC791E7-6FC9-4DDE-B4A2-547266977E4E}.Debug|x64.ActiveCfg = Debug|Any CPU
- {3CC791E7-6FC9-4DDE-B4A2-547266977E4E}.Debug|x64.Build.0 = Debug|Any CPU
- {3CC791E7-6FC9-4DDE-B4A2-547266977E4E}.Debug|x86.ActiveCfg = Debug|Any CPU
- {3CC791E7-6FC9-4DDE-B4A2-547266977E4E}.Debug|x86.Build.0 = Debug|Any CPU
- {3CC791E7-6FC9-4DDE-B4A2-547266977E4E}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {3CC791E7-6FC9-4DDE-B4A2-547266977E4E}.Release|Any CPU.Build.0 = Release|Any CPU
- {3CC791E7-6FC9-4DDE-B4A2-547266977E4E}.Release|x64.ActiveCfg = Release|Any CPU
- {3CC791E7-6FC9-4DDE-B4A2-547266977E4E}.Release|x64.Build.0 = Release|Any CPU
- {3CC791E7-6FC9-4DDE-B4A2-547266977E4E}.Release|x86.ActiveCfg = Release|Any CPU
- {3CC791E7-6FC9-4DDE-B4A2-547266977E4E}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
- GlobalSection(NestedProjects) = preSolution
- {8ED116F4-9DDF-4C49-AB96-AE462E3D64C3} = {422E561A-8118-4BE7-A54F-9309E4F03AAE}
- {6A20B9E9-DE66-456E-B4F5-ACFD1A95C3CA} = {422E561A-8118-4BE7-A54F-9309E4F03AAE}
- {29EEDF03-0990-45F4-846E-2616970D1FA2} = {F594E7FD-1E72-4E51-A496-B019C2BA3180}
- {2561F253-8F72-436A-BCC3-AA63AB82EDC0} = {422E561A-8118-4BE7-A54F-9309E4F03AAE}
- {3CC791E7-6FC9-4DDE-B4A2-547266977E4E} = {F594E7FD-1E72-4E51-A496-B019C2BA3180}
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {9D307AF9-D1F7-4185-AE9B-2DD3F178832C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9D307AF9-D1F7-4185-AE9B-2DD3F178832C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9D307AF9-D1F7-4185-AE9B-2DD3F178832C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9D307AF9-D1F7-4185-AE9B-2DD3F178832C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DFD3C9C2-F9E6-4EE3-B614-A8EA7D1E1A98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DFD3C9C2-F9E6-4EE3-B614-A8EA7D1E1A98}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DFD3C9C2-F9E6-4EE3-B614-A8EA7D1E1A98}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DFD3C9C2-F9E6-4EE3-B614-A8EA7D1E1A98}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AA007633-5178-4D73-A262-CCE7247BDE93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AA007633-5178-4D73-A262-CCE7247BDE93}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AA007633-5178-4D73-A262-CCE7247BDE93}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AA007633-5178-4D73-A262-CCE7247BDE93}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B4431254-9A2F-43DE-A998-12B22A1593CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B4431254-9A2F-43DE-A998-12B22A1593CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B4431254-9A2F-43DE-A998-12B22A1593CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B4431254-9A2F-43DE-A998-12B22A1593CE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {983D05F2-3C77-4B51-9A28-A8C6595911BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {983D05F2-3C77-4B51-9A28-A8C6595911BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {983D05F2-3C77-4B51-9A28-A8C6595911BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {983D05F2-3C77-4B51-9A28-A8C6595911BA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {3B9E8987-D4AC-426B-86F6-889126243A9A}
+ GlobalSection(NestedProjects) = preSolution
+ {9D307AF9-D1F7-4185-AE9B-2DD3F178832C} = {F46EF430-95AA-4386-9259-292A443AB715}
+ {DFD3C9C2-F9E6-4EE3-B614-A8EA7D1E1A98} = {F46EF430-95AA-4386-9259-292A443AB715}
+ {AA007633-5178-4D73-A262-CCE7247BDE93} = {F46EF430-95AA-4386-9259-292A443AB715}
+ {B4431254-9A2F-43DE-A998-12B22A1593CE} = {F40C4EC9-AE86-4A26-974F-95381888DCDC}
+ {983D05F2-3C77-4B51-9A28-A8C6595911BA} = {F40C4EC9-AE86-4A26-974F-95381888DCDC}
EndGlobalSection
EndGlobal
diff --git a/README.md b/README.md
index bb672b7f9..ad35b4192 100644
--- a/README.md
+++ b/README.md
@@ -2,23 +2,32 @@
[](https://github.com/PowerShell/PowerShellEditorServices/actions/workflows/ci-test.yml)
[](https://aka.ms/psdiscord)
-[](https://gitter.im/PowerShell/PowerShellEditorServices?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
**PowerShell Editor Services** is a PowerShell module that provides common
functionality needed to enable a consistent and robust PowerShell development
experience in almost any editor or integrated development environment (IDE).
-## [Language Server Protocol](https://microsoft.github.io/language-server-protocol/) clients using PowerShell Editor Services:
+## [Language Server Protocol](https://microsoft.github.io/language-server-protocol/) clients using PowerShell Editor Services
+
+- [PowerShell for Visual Studio Code](https://github.com/PowerShell/vscode-powershell)
+> [!NOTE]
+> PowerShell for Azure Data Studio will no longer be updated or maintained.
The functionality in PowerShell Editor Services is available in the following editor extensions:
+> [!WARNING]
+> These clients are community maintained and may be very out of date.
+It is recommended to use a generic [LSP plugin](#Usage) with your client if possible.
-- [PowerShell for Visual Studio Code](https://github.com/PowerShell/vscode-powershell), also available in Azure Data Studio
- [lsp-pwsh](https://github.com/emacs-lsp/lsp-mode/blob/master/clients/lsp-pwsh.el), an Emacs PowerShell plugin
- [intellij-powershell](https://github.com/ant-druha/intellij-powershell), adds PowerShell language support to IntelliJ-based IDEs
- [coc-powershell](https://github.com/yatli/coc-powershell), a Vim and Neovim plugin
+- [powershell.nvim](https://github.com/TheLeoP/powershell.nvim) a Neovim plugin
+
+## Supported PowerShell Versions
+
+PSES runs as a PowerShell Module in [currently supported versions of PowerShell 7+](https://learn.microsoft.com/en-us/powershell/scripting/install/powershell-support-lifecycle).
-Please note that other than PowerShell for Visual Studio Code, these clients are community maintained and may be very out of date.
-It is recommended that you simply use an LSP plugin for your editor and configure it as demonstrated [below](#Usage).
+Windows PowerShell 5.1 is supported on a best-effort basis.
## Features
@@ -55,7 +64,7 @@ The start script, `Start-EditorServices.ps1`, is found in the `PowerShellEditorS
The session details (which named pipes were created) will be written to the given session details path,
and the client needs to point to these in order to connect.
-The Visual Studio Code, Vim, and IntelliJ extensions use named pipes.
+The Visual Studio Code, Vim, Neovim, and IntelliJ extensions use named pipes.
### Standard Input and Output
@@ -66,7 +75,7 @@ This is because because these two features require their own IO streams and stdi
Please see the [emacs-simple-test.el](test/emacs-simple-test.el),
[emacs-test.el](test/emacs-test.el),
-[vim-simple-test.el](test/vim-simple-test.vim) and [vim-test.vim](test/vim-test.vim) for examples of end-to-end tested configurations.
+[vim-simple-test.vim](test/vim-simple-test.vim) and [vim-test.vim](test/vim-test.vim) for examples of end-to-end tested configurations.
They use [eglot for Emacs](https://github.com/joaotavora/eglot) and [LanguageClient-neovim](https://github.com/autozimu/LanguageClient-neovim).
### Advanced Usage
@@ -86,7 +95,7 @@ $command = @(
"-HostName 'My Client'",
"-HostProfileId 'myclient'",
"-HostVersion 1.0.0",
- "-LogLevel Diagnostic"
+ "-LogLevel Trace"
) -join " "
$pwsh_arguments = "-NoLogo -NoProfile -Command $command"
@@ -126,7 +135,40 @@ If you want to take advantage of debugging,
your client must support the [Debug Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol/).
Your client should use the path to the debug named pipe found in the `session.json` file talked about above.
-Currently, only the Visual Studio Code extension supports debugging.
+The debugging functionality in PowerShell Editor Services is available in the following editor extensions:
+
+- [PowerShell for Visual Studio Code](https://github.com/PowerShell/vscode-powershell)
+- [nvim-dap-powershell for Neovim](https://github.com/Willem-J-an/nvim-dap-powershell)
+- [powershell.nvim for Neovim](https://github.com/TheLeoP/powershell.nvim)
+- [intellij-powershell](https://github.com/ant-druha/intellij-powershell)
+
+### Rename Disclaimer
+
+PowerShell is not a statically typed language. As such, the renaming of functions, parameters, and other symbols can only be done on a best effort basis. While this is sufficient for the majority of use cases, it cannot be relied upon to find all instances of a symbol and rename them across an entire code base such as in C# or TypeScript.
+
+There are several edge case scenarios which may exist where rename is difficult or impossible, or unable to be determined due to the dynamic scoping nature of PowerShell.
+
+The focus of the rename support is on quick updates to variables or functions within a self-contained script file. It is not intended for module developers to find and rename a symbol across multiple files, which is very difficult to do as the relationships are primarily only computed at runtime and not possible to be statically analyzed.
+
+#### 👍 [Implemented and Tested Rename Scenarios](https://github.com/PowerShell/PowerShellEditorServices/blob/main/test/PowerShellEditorServices.Test.Shared/Refactoring) <- Link to Tests
+
+#### 🤚 Unsupported Scenarios
+
+- ❌ Renaming can only be done within a single file. Renaming symbols across multiple files is not supported, even if those are dotsourced from the source file.
+- ❌ Functions or variables must have a corresponding definition within their scope or above to be renamed. If we cannot find the original definition of a variable or function, the rename will not be supported.
+- ❌ Dynamic Parameters are not supported
+- ❌ Dynamically constructed splat parameters will not be renamed/updated (e.g. `$splat = @{};$splat.a = 5;Do-Thing @a`)
+- ❌ Scoped variables (e.g. $SCRIPT:test) are not currently supported
+- ❌ Renaming a variable inside of a scriptblock that is used in unscoped operations like `Foreach-Parallel` or `Start-Job` and the variable is not defined within the scriptblock is not supported and can have unexpected results.
+- ❌ Scriptblocks part of an assignment are considered isolated scopes. For example `$a = 5; $x = {$a}; & $x` does not consider the two $a to be related, even though in execution this reference matches.
+- ❌ Scriptblocks that are part of a parameter are assumed to not be executing in a different runspace. For example, the renaming behavior will treat `ForEach-Object -Parallel {$x}` the same as `Foreach-Object {$x}` for purposes of finding scope definitions. To avoid unexpected renaming, define/redefine all your variables in the scriptblock using a param block.
+- ❌ A lot of the logic relies on the position of items, so for example, defining a variable in a `begin` block and placing it after a `process` block, while technically correct in PowerShell, will not rename as expected.
+- ❌ Similarly, defining a function, and having the function rely on a variable that is assigned outside the function and after the function definition, will not find the outer variable reference.
+- ❌ `Get-Variable` and `Set-Variable` are not considered and not currently searched for renames
+
+#### 📄 Filing a Rename Issue
+
+If there is a rename scenario you feel can be reasonably supported in PowerShell, please file a bug report in the PowerShellEditorServices repository with the "Expected" and "Actual" being the before and after rename. We will evaluate it and accept or reject it and give reasons why. Items that fall under the Unsupported Scenarios above will be summarily rejected, however that does not mean that they may not be supported in the future if we come up with a reasonably safe way to implement a scenario.
## API Usage
@@ -138,9 +180,10 @@ Please note that we only consider the following as stable APIs that can be relie
The types of PowerShell Editor Services can change at any moment and should not be linked against in a production environment.
-## Development
+## Development Environment
-> NOTE: The easiest way to manually test changes you've made in PowerShellEditorServices is to follow the [vscode-powershell development doc](https://github.com/PowerShell/vscode-powershell/blob/main/docs/development.md) to get a local build of the VS Code extension to use your local build of PowerShellEditorServices.
+> [!TIP]
+> The easiest way to manually test changes you've made in PowerShellEditorServices is to follow the [vscode-powershell development doc](https://github.com/PowerShell/vscode-powershell/blob/main/docs/development.md).
### 1. Install PowerShell 7+
@@ -159,59 +202,60 @@ Install-Module InvokeBuild -Scope CurrentUser
Install-Module platyPS -Scope CurrentUser
```
-### 4. Delete `NuGet.Config`
+### 4. Adjust `nuget.config` if necessary
+
+Our NuGet configuration uses a secure feed with allow-listed third party dependency packages. If your contribution requires any changes to the included NuGet packages, you must disable this secure feed.
-Our NuGet configuration points to a private feed necessary for secure builds,
-and it must be committed to the repo as it is.
-The easiest way to build without access to that private feed is to delete the file:
+First, run this command to prevent accidentally commiting changes to this file
```powershell
-Remove-Item NuGet.Config
+git update-index --skip-worktree nuget.config
```
-Please be careful not to commit this change in a PR.
+Then, either delete the file or remove the `packagesources` section to use nuget.org again. Your PR _will_ fail automated build checks and you _must_ inform us at the top of your PR so the appropriate packages can be added if approved.
-Now you're ready to build the code.
-You can do so in one of two ways:
+## Build PowerShell Editor Services
+Now you're ready to build the code. You can do so in one of two ways:
-### Building the code from PowerShell
+### PowerShell
```powershell
-PS C:\path\to\PowerShellEditorServices> Invoke-Build Build
+PS C:\src\PowerShellEditorServices> Invoke-Build
```
-### Building the code from Visual Studio Code
+### Visual Studio Code
Open the PowerShellEditorServices folder that you cloned locally and press Ctrl+Shift+B
-(or Cmd+Shift+B on macOS).
+(or Cmd+Shift+B on macOS) which will run the default build task.
+
+## Code of Conduct
+
+Please see our [Code of Conduct](CODE_OF_CONDUCT.md) before participating in this project.
## Contributions Welcome
-We would love to incorporate community contributions into this project. If you would like to
-contribute code, documentation, tests, or bug reports, please read our [Contribution Guide](https://github.com/PowerShell/PowerShellEditorServices/blob/main/CONTRIBUTING.md) to learn more.
+We would love to incorporate community contributions into this project. If you would like to
+contribute code, documentation, tests, or bug reports, please read our [Contribution Guide](CONTRIBUTING.md) to learn more.
+
+## Security Note
+
+For any security issues, please see [here](SECURITY.md).
## Maintainers
-- [Justin Grote](https://github.com/JustinGrote) - [@JustinWGrote](https://twitter.com/justinwgrote)
-- [Patrick Meinecke](https://github.com/SeeminglyScience) - [@SeeminglyScienc](http://twitter.com/SeeminglyScienc)
-- [Andy Jordan](https://github.com/andschwa) - [andyleejordan.com](https://andyleejordan.com/)
+- Andy Jordan - [@andyleejordan](https://github.com/andyleejordan)
+- Patrick Meinecke - [@SeeminglyScience](https://github.com/SeeminglyScience)
+- Sydney Smith - [@SydneyhSmith](https://github.com/SydneyhSmith)
+- Justin Grote - [@JustinGrote](https://github.com/JustinGrote)
### Emeriti
-- [Rob Holt](https://github.com/rjmholt) - [@rjmholt](https://twitter.com/rjmholt)
-- [Tyler Leonhardt](https://github.com/TylerLeonhardt) - [tylerleonhardt.com](https://tylerleonhardt.com)
-- [David Wilson](https://github.com/daviwil) - [@daviwil](https://twitter.com/daviwil)
+- Rob Holt - [@rjmholt](https://github.com/rjmholt)
+- Tyler Leonhardt - [@TylerLeonhardt](https://github.com/TylerLeonhardt)
+- David Wilson - [@daviwil](https://github.com/daviwil)
## License
-This project is [licensed under the MIT License](LICENSE).
-
-## [Code of Conduct][conduct-md]
-
-This project has adopted the [Microsoft Open Source Code of Conduct][conduct-code].
-For more information, see the [Code of Conduct FAQ][conduct-FAQ] or contact [opencode@microsoft.com][conduct-email] with any additional questions or comments.
-
-[conduct-code]: http://opensource.microsoft.com/codeofconduct/
-[conduct-FAQ]: http://opensource.microsoft.com/codeofconduct/faq/
-[conduct-email]: mailto:opencode@microsoft.com
-[conduct-md]: https://github.com/PowerShell/PowerShellEditorServices/blob/main/CODE_OF_CONDUCT.md
+This project is [licensed under the MIT License](LICENSE). Please see the
+[third-party notices](NOTICE.txt) file for details on the third-party
+binaries that we include with releases of this project.
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 000000000..f941d308b
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,41 @@
+
+
+## Security
+
+Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin) and [PowerShell](https://github.com/PowerShell).
+
+If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/security.md/definition), please report it to us as described below.
+
+## Reporting Security Issues
+
+**Please do not report security vulnerabilities through public GitHub issues.**
+
+Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/security.md/msrc/create-report).
+
+If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/security.md/msrc/pgp).
+
+You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
+
+Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
+
+ * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
+ * Full paths of source file(s) related to the manifestation of the issue
+ * The location of the affected source code (tag/branch/commit or direct URL)
+ * Any special configuration required to reproduce the issue
+ * Step-by-step instructions to reproduce the issue
+ * Proof-of-concept or exploit code (if possible)
+ * Impact of the issue, including how an attacker might exploit the issue
+
+This information will help us triage your report more quickly.
+
+If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/security.md/msrc/bounty) page for more details about our active programs.
+
+## Preferred Languages
+
+We prefer all communications to be in English.
+
+## Policy
+
+Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/security.md/cvd).
+
+
diff --git a/Third Party Notices.txt b/Third Party Notices.txt
deleted file mode 100644
index 7a16849ba..000000000
--- a/Third Party Notices.txt
+++ /dev/null
@@ -1,75 +0,0 @@
-Do Not Translate or Localize
-
-This file is based on or incorporates material from the projects listed below (Third Party IP). The original copyright notice and the license under which Microsoft received such Third Party IP, are set forth below. Such licenses and notices are provided for informational purposes only. Microsoft licenses the Third Party IP to you under the licensing terms for the Microsoft product. Microsoft reserves all other rights not expressly granted under this agreement, whether by implication, estoppel or otherwise.
-
----
-
-Serilog
-
-Copyright 2013-2015 Serilog Contributors
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
----
-
-Serilog.Sinks.Async
-
-Copyright 2013-2015 Serilog Contributors
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
----
-
-Serilog.Sinks.File
-
-Copyright 2013-2015 Serilog Contributors
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
----
-
-Serilog.Sinks.Console
-
-Copyright 2013-2015 Serilog Contributors
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
diff --git a/build.ps1 b/build.ps1
deleted file mode 100644
index 913e907e4..000000000
--- a/build.ps1
+++ /dev/null
@@ -1,103 +0,0 @@
-#!/usr/bin/env pwsh
-
-# Copyright (c) Microsoft Corporation.
-# Licensed under the MIT License.
-
-param(
- [Parameter()]
- [switch]
- $Bootstrap,
-
- [Parameter()]
- [switch]
- $Clean,
-
- [Parameter()]
- [switch]
- $Test
-)
-
-$NeededTools = @{
- OpenSsl = "openssl for macOS"
- PowerShellGet = "PowerShellGet latest"
- InvokeBuild = "InvokeBuild latest"
-}
-
-if ((-not $PSVersionTable["OS"]) -or $PSVersionTable["OS"].Contains("Windows")) {
- $OS = "Windows"
-} elseif ($PSVersionTable["OS"].Contains("Darwin")) {
- $OS = "macOS"
-} else {
- $OS = "Linux"
-}
-
-
-function needsOpenSsl () {
- if ($OS -eq "macOS") {
- try {
- $opensslVersion = (openssl version)
- } catch {
- return $true
- }
- }
- return $false
-}
-
-function needsPowerShellGet () {
- if (Get-Module -ListAvailable -Name PowerShellGet) {
- return $false
- }
- return $true
-}
-
-function needsInvokeBuild () {
- if (Get-Module -ListAvailable -Name InvokeBuild) {
- return $false
- }
- return $true
-}
-
-function getMissingTools () {
- $missingTools = @()
-
- if (needsOpenSsl) {
- $missingTools += $NeededTools.OpenSsl
- }
- if (needsPowerShellGet) {
- $missingTools += $NeededTools.PowerShellGet
- }
- if (needsInvokeBuild) {
- $missingTools += $NeededTools.InvokeBuild
- }
-
- return $missingTools
-}
-
-function hasMissingTools () {
- return ((getMissingTools).Count -gt 0)
-}
-
-if ($Bootstrap) {
- $string = "Here is what your environment is missing:`n"
- $missingTools = getMissingTools
- if (($missingTools).Count -eq 0) {
- $string += "* nothing!`n`n Run this script without a flag to build or a -Clean to clean."
- } else {
- $missingTools | ForEach-Object {$string += "* $_`n"}
- $string += "`nAll instructions for installing these tools can be found on PowerShell Editor Services' Github:`n" `
- + "https://github.com/powershell/PowerShellEditorServices#development"
- }
- Write-Host "`n$string`n"
-} elseif(hasMissingTools) {
- Write-Host "You are missing needed tools. Run './build.ps1 -Bootstrap' to see what they are."
-} else {
- if($Clean) {
- Invoke-Build Clean
- }
-
- Invoke-Build Build
-
- if($Test) {
- Invoke-Build Test
- }
-}
diff --git a/docs/guide/getting_started.md b/docs/guide/getting_started.md
index 696e102af..ddfe78f7e 100644
--- a/docs/guide/getting_started.md
+++ b/docs/guide/getting_started.md
@@ -61,7 +61,7 @@ Once the basic language configurations have been installed, add this to your
```lua
local on_attach = function(client, bufnr)
-- Enable completion triggered by
- vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc')
+ vim.api.nvim_set_option_value("omnifunc", "v:lua.vim.lsp.omnifunc", { buf = bufnr })
local bufopts = { noremap = true, silent = true, buffer = bufnr }
vim.keymap.set('n', '', vim.lsp.buf.signature_help, bufopts)
@@ -101,6 +101,15 @@ lua << EOF
EOF
```
+#### Theme Troubleshooting
+If you find that your colorscheme appears correctly for a second and then
+changes to not having full highlighting, you'll need to disable semantic
+highlighting.
+Add this line to the `on_attach` function.
+```lua
+client.server_capabilities.semanticTokensProvider = nil
+```
+
#### Configure Additional Settings
To further configure the server, you can supply settings to the setup table.
For example, you can set the code formatting preset to one true brace style
@@ -112,6 +121,8 @@ require('lspconfig')['powershell_es'].setup {
settings = { powershell = { codeFormatting = { Preset = 'OTBS' } } }
}
```
+For a more complete list of options have a look at this schema:
+[nvim-lsp-installer powershell_es reference](https://github.com/williamboman/nvim-lsp-installer/blob/main/lua/nvim-lsp-installer/_generated/schemas/powershell_es.lua)
You can also set the bundled PSScriptAnalyzer's custom rule path like so:
```lua
@@ -122,3 +133,34 @@ require('lspconfig')['powershell_es'].setup {
settings = { powershell = { scriptAnalysis = { settingsPath = custom_settings_path } } }
}
```
+
+#### Autocomplete Brackets Troubleshooting
+If you're using `blink.cmp` and you're getting brackets when autocompleting
+cmdlet names, you'll need to add `{ "ps1", "psm1" }` to the blocked filetypes
+for both `kind_resolution` and `semantic_token_resolution` in the plugin's
+config file.
+
+[Blink.cmp completion reference](https://cmp.saghen.dev/configuration/reference#completion-accept)
+
+### Indentation
+
+Vim/Neovim does not contain default `:h indentexpr` for filetype `ps1`.
+So you might notice indentation on newline is not behaving as expected for powershell files.
+Luckily powershell has similar syntax like C, so we can use `:h cindent` to fix the indentation problem.
+You can use the following snippet to either callback of an autocmd or ftplugin.
+
+```lua
+--- ./nvim/lua/ftplugin/ps1.lua
+
+-- disable indent from powershell treesitter parser
+-- because the parse isn't mature currently
+-- you can ignore this step if don't use treesitter
+if pcall(require, 'nvim-treesitter') then
+ vim.schedule(function() vim.cmd([[TSBufDisable indent]]) end)
+end
+
+vim.opt_local.cindent = true
+vim.opt_local.cinoptions:append { 'J1', '(1s', '+0' } -- see :h cino-J, cino-(, cino-+
+
+vim.opt_local.iskeyword:remove { '-' } -- OPTIONALLY consider Verb-Noun as a whole word
+```
diff --git a/global.json b/global.json
index 4c4c3ae5e..910363ade 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version": "8.0.100",
+ "version": "8.0.416",
"rollForward": "latestFeature",
"allowPrerelease": false
}
diff --git a/module/PowerShellEditorServices/Commands/PowerShellEditorServices.Commands.psd1 b/module/PowerShellEditorServices/Commands/PowerShellEditorServices.Commands.psd1
index 69347beab..2ef9b51d0 100644
--- a/module/PowerShellEditorServices/Commands/PowerShellEditorServices.Commands.psd1
+++ b/module/PowerShellEditorServices/Commands/PowerShellEditorServices.Commands.psd1
@@ -79,7 +79,8 @@ FunctionsToExport = @('Register-EditorCommand',
'Test-ScriptExtent',
'Open-EditorFile',
'New-EditorFile',
- 'Clear-Host')
+ 'Clear-Host',
+ 'Start-DebugAttachSession')
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
CmdletsToExport = @()
diff --git a/module/PowerShellEditorServices/Commands/Public/Start-DebugAttachSession.ps1 b/module/PowerShellEditorServices/Commands/Public/Start-DebugAttachSession.ps1
new file mode 100644
index 000000000..2ef978070
--- /dev/null
+++ b/module/PowerShellEditorServices/Commands/Public/Start-DebugAttachSession.ps1
@@ -0,0 +1,201 @@
+# Copyright (c) Microsoft Corporation.
+# Licensed under the MIT License.
+
+using namespace System.Collections
+using namespace System.Management.Automation
+using namespace System.Reflection
+using namespace System.Threading
+using namespace System.Threading.Tasks
+
+function Start-DebugAttachSession {
+ <#
+ .EXTERNALHELP ..\PowerShellEditorServices.Commands-help.xml
+ #>
+ [OutputType([System.Management.Automation.Job2])]
+ [CmdletBinding(DefaultParameterSetName = 'ProcessId')]
+ param(
+ [Parameter()]
+ [string]
+ $Name,
+
+ [Parameter(ParameterSetName = 'ProcessId')]
+ [int]
+ $ProcessId,
+
+ [Parameter(ParameterSetName = 'CustomPipeName')]
+ [string]
+ $CustomPipeName,
+
+ [Parameter()]
+ [string]
+ $RunspaceName,
+
+ [Parameter()]
+ [int]
+ $RunspaceId,
+
+ [Parameter()]
+ [string]
+ $ComputerName,
+
+ [Parameter()]
+ [ValidateSet('Close', 'Hide', 'Keep')]
+ [string]
+ $WindowActionOnEnd,
+
+ [Parameter()]
+ [IDictionary[]]
+ $PathMapping,
+
+ [Parameter()]
+ [switch]
+ $AsJob
+ )
+
+ $ErrorActionPreference = 'Stop'
+
+ try {
+ if ($PSBoundParameters.ContainsKey('RunspaceId') -and $RunspaceName) {
+ $err = [ErrorRecord]::new(
+ [ArgumentException]::new("Cannot specify both RunspaceId and RunspaceName parameters"),
+ "InvalidRunspaceParameters",
+ [ErrorCategory]::InvalidArgument,
+ $null)
+ $err.ErrorDetails = [ErrorDetails]::new("")
+ $err.ErrorDetails.RecommendedAction = 'Specify only one of RunspaceId or RunspaceName.'
+ $PSCmdlet.WriteError($err)
+ return
+ }
+
+ # Var will be set by PSES in configurationDone before launching script
+ $debugServer = Get-Variable -Name __psEditorServices_DebugServer -ValueOnly -ErrorAction Ignore
+ if (-not $debugServer) {
+ $err = [ErrorRecord]::new(
+ [Exception]::new("Cannot start a new attach debug session unless running in an existing launch debug session not in a temporary console"),
+ "NoDebugSession",
+ [ErrorCategory]::InvalidOperation,
+ $null)
+ $err.ErrorDetails = [ErrorDetails]::new("")
+ $err.ErrorDetails.RecommendedAction = 'Launch script with debugging to ensure the debug session is available.'
+ $PSCmdlet.WriteError($err)
+ return
+ }
+
+ if ($AsJob -and -not (Get-Command -Name Start-ThreadJob -ErrorAction Ignore)) {
+ $err = [ErrorRecord]::new(
+ [Exception]::new("Cannot use the -AsJob parameter unless running on PowerShell 7+ or the ThreadJob module is present"),
+ "NoThreadJob",
+ [ErrorCategory]::InvalidArgument,
+ $null)
+ $err.ErrorDetails = [ErrorDetails]::new("")
+ $err.ErrorDetails.RecommendedAction = 'Install the ThreadJob module or run on PowerShell 7+.'
+ $PSCmdlet.WriteError($err)
+ return
+ }
+
+ $configuration = @{
+ type = 'PowerShell'
+ request = 'attach'
+ # A temp console is also needed as the current one is busy running
+ # this code. Failing to set this will cause a deadlock.
+ createTemporaryIntegratedConsole = $true
+ }
+
+ if ($ProcessId) {
+ if ($ProcessId -eq $PID) {
+ $err = [ErrorRecord]::new(
+ [ArgumentException]::new("PSES does not support attaching to the current editor process"),
+ "AttachToCurrentProcess",
+ [ErrorCategory]::InvalidArgument,
+ $PID)
+ $err.ErrorDetails = [ErrorDetails]::new("")
+ $err.ErrorDetails.RecommendedAction = 'Specify a different process id.'
+ $PSCmdlet.WriteError($err)
+ return
+ }
+
+ if ($Name) {
+ $configuration.name = $Name
+ }
+ else {
+ $configuration.name = "Attach Process $ProcessId"
+ }
+ $configuration.processId = $ProcessId
+ }
+ elseif ($CustomPipeName) {
+ if ($Name) {
+ $configuration.name = $Name
+ }
+ else {
+ $configuration.name = "Attach Pipe $CustomPipeName"
+ }
+ $configuration.customPipeName = $CustomPipeName
+ }
+ else {
+ $configuration.name = 'Attach Session'
+ }
+
+ if ($ComputerName) {
+ $configuration.computerName = $ComputerName
+ }
+
+ if ($PSBoundParameters.ContainsKey('RunspaceId')) {
+ $configuration.runspaceId = $RunspaceId
+ }
+ elseif ($RunspaceName) {
+ $configuration.runspaceName = $RunspaceName
+ }
+
+ if ($WindowActionOnEnd) {
+ $configuration.temporaryConsoleWindowActionOnDebugEnd = $WindowActionOnEnd.ToLowerInvariant()
+ }
+
+ if ($PathMapping) {
+ $configuration.pathMappings = $PathMapping
+ }
+
+ # https://microsoft.github.io/debug-adapter-protocol/specification#Reverse_Requests_StartDebugging
+ $resp = $debugServer.SendRequest(
+ 'startDebugging',
+ @{
+ configuration = $configuration
+ request = 'attach'
+ }
+ )
+
+ # PipelineStopToken added in pwsh 7.6
+ $cancelToken = if ($PSCmdlet.PipelineStopToken) {
+ $PSCmdlet.PipelineStopToken
+ }
+ else {
+ [CancellationToken]::new($false)
+ }
+
+ # There is no response for a startDebugging request
+ $task = $resp.ReturningVoid($cancelToken)
+
+ $waitTask = {
+ [CmdletBinding()]
+ param ([Parameter(Mandatory)][Task]$Task)
+
+ while (-not $Task.AsyncWaitHandle.WaitOne(300)) {}
+ $null = $Task.GetAwaiter().GetResult()
+ }
+
+ if ($AsJob) {
+ # Using the Ast to build the scriptblock allows the job to inherit
+ # the using namespace entries and include the proper line/script
+ # paths in any error traces that are emitted.
+ Start-ThreadJob -ScriptBlock {
+ & ($args[0]).Ast.GetScriptBlock() $args[1]
+ } -ArgumentList $waitTask, $task
+ }
+ else {
+ & $waitTask $task
+ }
+ }
+ catch {
+ $PSCmdlet.WriteError($_)
+ return
+ }
+}
\ No newline at end of file
diff --git a/module/PowerShellEditorServices/PowerShellEditorServices.psd1 b/module/PowerShellEditorServices/PowerShellEditorServices.psd1
index ebeba42f9..4fb2ea16a 100644
--- a/module/PowerShellEditorServices/PowerShellEditorServices.psd1
+++ b/module/PowerShellEditorServices/PowerShellEditorServices.psd1
@@ -19,7 +19,7 @@ RootModule = if ($PSEdition -eq 'Core')
}
# Version number of this module.
-ModuleVersion = '3.18.1'
+ModuleVersion = '4.6.0'
# ID used to uniquely identify this module
GUID = '9ca15887-53a2-479a-9cda-48d26bcb6c47'
diff --git a/module/PowerShellEditorServices/Start-EditorServices.ps1 b/module/PowerShellEditorServices/Start-EditorServices.ps1
index 3e445679a..c61503c65 100644
--- a/module/PowerShellEditorServices/Start-EditorServices.ps1
+++ b/module/PowerShellEditorServices/Start-EditorServices.ps1
@@ -46,7 +46,7 @@ param(
[ValidateNotNullOrEmpty()]
$LogPath,
- [ValidateSet("Diagnostic", "Verbose", "Normal", "Warning", "Error")]
+ [ValidateSet("Diagnostic", "Verbose", "Normal", "Warning", "Error", "Trace", "Debug", "Information", "Critical", "None")]
$LogLevel,
[ValidateNotNullOrEmpty()]
@@ -107,5 +107,13 @@ param(
$DebugServiceOutPipeName
)
+#Translate legacy PSES log levels to MEL levels
+$LogLevel = switch ($LogLevel) {
+ 'Diagnostic' { 'Trace' }
+ 'Verbose' { 'Debug' }
+ 'Normal' { 'Information' }
+ default { $LogLevel }
+}
+
Import-Module -Name "$PSScriptRoot/PowerShellEditorServices.psd1"
Start-EditorServices @PSBoundParameters
diff --git a/module/docs/PowerShellEditorServices.Commands.md b/module/docs/PowerShellEditorServices.Commands.md
index ca417c173..017432f8c 100644
--- a/module/docs/PowerShellEditorServices.Commands.md
+++ b/module/docs/PowerShellEditorServices.Commands.md
@@ -46,6 +46,10 @@ The Set-ScriptExtent function can insert or replace text at a specified position
You can use the Find-Ast function to easily find the desired extent.
+### [Start-DebugAttachSession](Start-DebugAttachSession.md)
+
+The Start-DebugAttachSession function can start a new debug session that is attached to the specified PowerShell instance.
+
### [Test-ScriptExtent](Test-ScriptExtent.md)
The Test-ScriptExtent function can be used to determine if a ScriptExtent object is before, after, or inside another ScriptExtent object. You can also test for any combination of these with separate ScriptExtent objects to test against.
diff --git a/module/docs/Start-DebugAttachSession.md b/module/docs/Start-DebugAttachSession.md
new file mode 100644
index 000000000..2601cd263
--- /dev/null
+++ b/module/docs/Start-DebugAttachSession.md
@@ -0,0 +1,273 @@
+---
+external help file: PowerShellEditorServices.Commands-help.xml
+Module Name: PowerShellEditorServices.Commands
+online version: https://github.com/PowerShell/PowerShellEditorServices/tree/main/module/docs/Start-DebugAttachSession.md
+schema: 2.0.0
+---
+
+# Start-DebugAttachSession
+
+## SYNOPSIS
+
+Starts a new debug session attached to the specified PowerShell instance.
+
+## SYNTAX
+
+### ProcessId (Default)
+```
+Start-DebugAttachSession [-Name ] [-ProcessId ] [-RunspaceName ] [-RunspaceId ]
+ [-ComputerName ] [-WindowActionOnEnd {Close | Hide | Keep}] [-PathMapping ] [-AsJob]
+ []
+```
+
+### CustomPipeName
+```
+Start-DebugAttachSession [-Name ] [-CustomPipeName ] [-RunspaceName ]
+ [-RunspaceId ] [-ComputerName ] [-WindowActionOnEnd {Close | Hide | Keep}]
+ [-PathMapping ] [-AsJob] []
+```
+
+## DESCRIPTION
+
+The Start-DebugAttachSession function can be used to start a new debug session that is attached to the specified PowerShell instance. The caller must be running in an existing launched debug session, the launched session is not running in a temporary console, and the launched session is not entered into a remote PSSession. If the callers script ends before the new debug session is completed, the debug session for the child will also end.
+
+The function will return once the attach response was received by the debug server. For an example, an attach request will return once PowerShell has attached to the process and has called `Debug-Runspace`. If you need to return early use the `-AsJob` parameter to return a `Job` object immediately that can be used to wait for the response at a later time.
+
+If `-ProcessId` or `-CustomPipeName` is not specified, the debug client will prompt for process to connect to. If `-RunspaceId` or `-RunspaceName` is not specified, the debug client will prompt for which runspace to connect to.
+
+## EXAMPLES
+
+### -------------------------- EXAMPLE 1 --------------------------
+
+```powershell
+$pipeName = "TestPipe-$(New-Guid)"
+$procParams = @{
+ FilePath = 'pwsh'
+ ArgumentList = ('-CustomPipeName {0} -File other-script.ps1' -f $pipeName)
+ PassThru = $true
+}
+$proc = Start-Process @procParams
+
+Start-DebugAttachSession -CustomPipeName $pipeName -RunspaceId 1
+$proc | Wait-Process
+
+
+<# The contents of `other-script.ps1` is #>
+# Waits until PowerShell has attached
+$runspaces = Get-Runspace
+while ($true) {
+ if (Get-Runspace | Where-Object { $_.Id -notin $runspaces.Id }) {
+ break
+ }
+ Start-Sleep -Seconds 1
+}
+
+# WinPS will only have breakpoints synced once the debugger has been hit.
+if ($PSVersionTable.PSVersion -lt '6.0') {
+ Wait-Debugger
+}
+
+# Place breakpoint below or use Wait-Debugger
+# to have the attach debug session break.
+$a = 'abc'
+$b = ''
+Write-Host "Test $a - $PID"
+```
+
+Launches a new PowerShell process with a custom pipe and starts a new attach configuration that will debug the new process under a child debugging session. The caller waits until the new process ends before ending the parent session.
+
+### -------------------------- EXAMPLE 2 --------------------------
+
+```powershell
+$attachParams = @{
+ ComputerName = 'remote-windows'
+ ProcessId = $remotePid
+ RunspaceId = 1
+ PathMapping = @(
+ @{
+ localRoot = 'C:\local\path\to\scripts\'
+ remoteRoot = 'C:\remote\path\on\remote-windows\'
+ }
+ )
+}
+Start-DebugAttachSession @attachParams
+```
+
+Attaches to a remote PSSession through the WSMan parameter and maps the remote path running the script in the PSSession to the same copy of files locally. For example `remote-windows` is running the script `C:\remote\path\on\remote-windows\script.ps1` but the same script(s) are located locally on the current host `C:\local\path\to\scripts\script.ps1`.
+
+The debug client can see the remote files as local when setting breakpoints and inspecting the callstack with this mapped path.
+
+## PARAMETERS
+
+### -AsJob
+
+Instead of waiting for the start debugging response before returning, the `-AsJob` parameter will output a job immediately after sending the request that waits for the job. This is useful if further work is needed for a debug session to successfully attach and start debugging the target runspace.
+
+This is only supported when the calling script is running on PowerShell 7+ or the `ThreadJob` module is present.
+
+```yaml
+Type: SwitchParameter
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -ComputerName
+
+The computer name to which a remote session will be established before attaching to the target runspace. If specified, the temporary console will run `Enter-PSSession -ComputerName ...` to connect to a host over WSMan before attaching to the requested PowerShell instance.
+
+```yaml
+Type: String
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -CustomPipeName
+
+The custom pipe name of the PowerShell host process to attach to. This option is mutually exclusive with `-ProcessId`.
+
+```yaml
+Type: String
+Parameter Sets: CustomPipeName
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -Name
+
+The name of the debug session to show in the debug client.
+
+```yaml
+Type: String
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -PathMapping
+
+An array of dictionaries with the keys `localRoot` and `remoteRoot` that maps a local and remote path root to each other. This option is useful when attaching to a PSSession running a script that is not accessible locally but can be found under a different path.
+
+It is a good idea to ensure the `localRoot` and `remoteRoot` entries are either the absolute path to a script or ends with the trailing directory separator if specifying a directory. A path can also be mapped from a Windows and non-Windows path, just ensure the correct directory separators are used for each OS type. For example `/` for non-Windows and `\` for Windows.
+
+```yaml
+Type: IDictionary[]
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -ProcessId
+
+The ID of the PowerShell host process that should be attached. This option is mutually exclusive with `-CustomPipeName`.
+
+```yaml
+Type: Int32
+Parameter Sets: ProcessId
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -RunspaceId
+
+The ID of the runspace to debug in the attached process. This option is mutually exclusive with `-RunspaceName`.
+
+```yaml
+Type: Int32
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -RunspaceName
+
+The name of the runspace to debug in the attached process. This option is mutually exclusive with `-RunspaceId`.
+
+```yaml
+Type: String
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -WindowActionOnEnd
+
+Specifies the action to take on the temporary debug console created by the debug client after the attached session ends. This corresponds to the VSCode attach configuration option `temporaryConsoleWindowActionOnDebugEnd`. Setting to `Close` will close the debug console, `Hide` will move back to the last debug console before the attach session started, and `Keep` (default) will keep the active terminal as the attached session.
+
+```yaml
+Type: String
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### CommonParameters
+This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
+
+## INPUTS
+
+### None
+
+You can't pipe objects to this function.
+
+## OUTPUTS
+
+### None
+
+By default, this function returns no output.
+
+### System.Management.Automation.Job2
+
+When you use the `-AsJob` parameter, this function returns the `Job` object that is waiting for the response.
+
+## NOTES
+
+The function will fail if the caller is not running under a debug session or was started through an attach request.
+
+## RELATED LINKS
diff --git a/modules.json b/modules.json
deleted file mode 100644
index a21a350b0..000000000
--- a/modules.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "PSScriptAnalyzer": {
- "Version": "1.22.0",
- "AllowPrerelease": false
- },
- "Plaster": {
- "Version": "1.1.3",
- "AllowPrerelease": false
- },
- "PSReadLine": {
- "Version": "2.4.0-beta0",
- "AllowPrerelease": true
- }
-}
diff --git a/NuGet.Config b/nuget.config
similarity index 64%
rename from NuGet.Config
rename to nuget.config
index f04dcd513..f003b0fbd 100644
--- a/NuGet.Config
+++ b/nuget.config
@@ -2,6 +2,6 @@
-
+
diff --git a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs
index 0eddc622b..6f2ec8851 100644
--- a/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs
+++ b/src/PowerShellEditorServices.Hosting/Commands/StartEditorServicesCommand.cs
@@ -138,7 +138,7 @@ public StartEditorServicesCommand()
/// The minimum log level that should be emitted.
///
[Parameter]
- public PsesLogLevel LogLevel { get; set; } = PsesLogLevel.Normal;
+ public string LogLevel { get; set; } = PsesLogLevel.Warning.ToString();
///
/// Paths to additional PowerShell modules to be imported at startup.
@@ -195,6 +195,11 @@ public StartEditorServicesCommand()
[Parameter]
public string StartupBanner { get; set; }
+ ///
+ /// Compatibility to store the currently supported PSESLogLevel Enum Value
+ ///
+ private PsesLogLevel _psesLogLevel = PsesLogLevel.Warning;
+
#pragma warning disable IDE0022
protected override void BeginProcessing()
{
@@ -215,11 +220,10 @@ protected override void BeginProcessing()
}
#pragma warning restore IDE0022
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Uses ThrowTerminatingError() instead")]
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "We have to wait here, it's the whole program.")]
protected override void EndProcessing()
{
- _logger.Log(PsesLogLevel.Diagnostic, "Beginning EndProcessing block");
-
+ _logger.Log(PsesLogLevel.Trace, "Beginning EndProcessing block");
try
{
// First try to remove PSReadLine to decomplicate startup
@@ -230,11 +234,9 @@ protected override void EndProcessing()
EditorServicesConfig editorServicesConfig = CreateConfigObject();
using EditorServicesLoader psesLoader = EditorServicesLoader.Create(_logger, editorServicesConfig, SessionDetailsPath, _loggerUnsubscribers);
- _logger.Log(PsesLogLevel.Verbose, "Loading EditorServices");
+ _logger.Log(PsesLogLevel.Debug, "Loading EditorServices");
// Synchronously start editor services and wait here until it shuts down.
-#pragma warning disable VSTHRD002
psesLoader.LoadAndRunEditorServicesAsync().GetAwaiter().GetResult();
-#pragma warning restore VSTHRD002
}
catch (Exception e)
{
@@ -260,7 +262,25 @@ protected override void EndProcessing()
private void StartLogging()
{
- _logger = new HostLogger(LogLevel);
+ bool isLegacyPsesLogLevel = false;
+ if (!Enum.TryParse(LogLevel, true, out _psesLogLevel))
+ {
+ // PSES used to have log levels that didn't match MEL levels, this is an adapter for those types and may eventually be removed once people migrate their settings.
+ isLegacyPsesLogLevel = true;
+ _psesLogLevel = LogLevel switch
+ {
+ "Diagnostic" => PsesLogLevel.Trace,
+ "Verbose" => PsesLogLevel.Debug,
+ "Normal" => PsesLogLevel.Information,
+ _ => PsesLogLevel.Trace
+ };
+ }
+
+ _logger = new HostLogger(_psesLogLevel);
+ if (isLegacyPsesLogLevel)
+ {
+ _logger.Log(PsesLogLevel.Warning, $"The log level '{LogLevel}' is deprecated and will be removed in a future release. Please update your settings or command line options to use one of the following options: 'Trace', 'Debug', 'Information', 'Warning', 'Error', 'Critical'.");
+ }
// We need to not write log messages to Stdio
// if it's being used as a protocol transport
@@ -284,7 +304,7 @@ private void StartLogging()
IDisposable fileLoggerUnsubscriber = _logger.Subscribe(fileLogger);
fileLogger.AddUnsubscriber(fileLoggerUnsubscriber);
_loggerUnsubscribers.Add(fileLoggerUnsubscriber);
- _logger.Log(PsesLogLevel.Diagnostic, "Logging started");
+ _logger.Log(PsesLogLevel.Trace, "Logging started");
}
// Sanitizes user input and ensures the directory is created.
@@ -302,7 +322,7 @@ private string GetLogDirPath()
private void RemovePSReadLineForStartup()
{
- _logger.Log(PsesLogLevel.Verbose, "Removing PSReadLine");
+ _logger.Log(PsesLogLevel.Debug, "Removing PSReadLine");
using SMA.PowerShell pwsh = SMA.PowerShell.Create(RunspaceMode.CurrentRunspace);
bool hasPSReadLine = pwsh.AddCommand(new CmdletInfo(@"Microsoft.PowerShell.Core\Get-Module", typeof(GetModuleCommand)))
.AddParameter("Name", "PSReadLine")
@@ -317,13 +337,13 @@ private void RemovePSReadLineForStartup()
.AddParameter("Name", "PSReadLine")
.AddParameter("ErrorAction", "SilentlyContinue");
- _logger.Log(PsesLogLevel.Verbose, "Removed PSReadLine");
+ _logger.Log(PsesLogLevel.Debug, "Removed PSReadLine");
}
}
private EditorServicesConfig CreateConfigObject()
{
- _logger.Log(PsesLogLevel.Diagnostic, "Creating host configuration");
+ _logger.Log(PsesLogLevel.Trace, "Creating host configuration");
string bundledModulesPath = BundledModulesPath;
if (!Path.IsPathRooted(bundledModulesPath))
@@ -352,7 +372,7 @@ private EditorServicesConfig CreateConfigObject()
LogPath)
{
FeatureFlags = FeatureFlags,
- LogLevel = LogLevel,
+ LogLevel = _psesLogLevel,
ConsoleRepl = GetReplKind(),
UseNullPSHostUI = Stdio, // If Stdio is used we can't write anything else out
AdditionalModules = AdditionalModules,
@@ -402,31 +422,31 @@ private string GetProfilePathFromProfileObject(PSObject profileObject, ProfileUs
// * On Linux or macOS on any version greater than or equal to 7
private ConsoleReplKind GetReplKind()
{
- _logger.Log(PsesLogLevel.Diagnostic, "Determining REPL kind");
+ _logger.Log(PsesLogLevel.Trace, "Determining REPL kind");
if (Stdio || !EnableConsoleRepl)
{
- _logger.Log(PsesLogLevel.Diagnostic, "REPL configured as None");
+ _logger.Log(PsesLogLevel.Trace, "REPL configured as None");
return ConsoleReplKind.None;
}
if (UseLegacyReadLine)
{
- _logger.Log(PsesLogLevel.Diagnostic, "REPL configured as Legacy");
+ _logger.Log(PsesLogLevel.Trace, "REPL configured as Legacy");
return ConsoleReplKind.LegacyReadLine;
}
- _logger.Log(PsesLogLevel.Diagnostic, "REPL configured as PSReadLine");
+ _logger.Log(PsesLogLevel.Trace, "REPL configured as PSReadLine");
return ConsoleReplKind.PSReadLine;
}
private ITransportConfig GetLanguageServiceTransport()
{
- _logger.Log(PsesLogLevel.Diagnostic, "Configuring LSP transport");
+ _logger.Log(PsesLogLevel.Trace, "Configuring LSP transport");
if (DebugServiceOnly)
{
- _logger.Log(PsesLogLevel.Diagnostic, "No LSP transport: PSES is debug only");
+ _logger.Log(PsesLogLevel.Trace, "No LSP transport: PSES is debug only");
return null;
}
@@ -450,11 +470,11 @@ private ITransportConfig GetLanguageServiceTransport()
private ITransportConfig GetDebugServiceTransport()
{
- _logger.Log(PsesLogLevel.Diagnostic, "Configuring debug transport");
+ _logger.Log(PsesLogLevel.Trace, "Configuring debug transport");
if (LanguageServiceOnly)
{
- _logger.Log(PsesLogLevel.Diagnostic, "No Debug transport: PSES is language service only");
+ _logger.Log(PsesLogLevel.Trace, "No Debug transport: PSES is language service only");
return null;
}
@@ -465,7 +485,7 @@ private ITransportConfig GetDebugServiceTransport()
return new StdioTransportConfig(_logger);
}
- _logger.Log(PsesLogLevel.Diagnostic, "No debug transport: Transport is Stdio with debug disabled");
+ _logger.Log(PsesLogLevel.Trace, "No debug transport: Transport is Stdio with debug disabled");
return null;
}
diff --git a/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs b/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs
index b2e683a2f..66bc7b1de 100644
--- a/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs
+++ b/src/PowerShellEditorServices.Hosting/Configuration/EditorServicesConfig.cs
@@ -90,14 +90,14 @@ public EditorServicesConfig(
public ConsoleReplKind ConsoleRepl { get; set; } = ConsoleReplKind.None;
///
- /// Will suppress messages to PSHost (to prevent Stdio clobbering)
+ /// Will suppress messages to PSHost (to prevent Stdio clobbering)
///
public bool UseNullPSHostUI { get; set; }
///
- /// The minimum log level to log events with.
+ /// The minimum log level to log events with. Defaults to warning but is usually overriden by the startup process.
///
- public PsesLogLevel LogLevel { get; set; } = PsesLogLevel.Normal;
+ public PsesLogLevel LogLevel { get; set; } = PsesLogLevel.Warning;
///
/// Configuration for the language server protocol transport to use.
diff --git a/src/PowerShellEditorServices.Hosting/Configuration/HostLogger.cs b/src/PowerShellEditorServices.Hosting/Configuration/HostLogger.cs
index 7ce6f66a9..1c8617341 100644
--- a/src/PowerShellEditorServices.Hosting/Configuration/HostLogger.cs
+++ b/src/PowerShellEditorServices.Hosting/Configuration/HostLogger.cs
@@ -12,21 +12,51 @@
namespace Microsoft.PowerShell.EditorServices.Hosting
{
///
- /// User-facing log level for editor services configuration.
+ /// Log Level for HostLogger. This is a direct copy of LogLevel from Microsoft.Extensions.Logging, and will map to
+ /// MEL.LogLevel once MEL is bootstrapped, but we don't want to load any MEL assemblies until the Assembly Load
+ /// Context is set up.
///
- ///
- /// The underlying values of this enum attempt to align to both
- /// and
- /// .
- ///
public enum PsesLogLevel
{
- Diagnostic = 0,
- Verbose = 1,
- Normal = 2,
+ ///
+ /// Logs that contain the most detailed messages. These messages may contain sensitive application data.
+ /// These messages are disabled by default and should never be enabled in a production environment.
+ ///
+ Trace = 0,
+
+ ///
+ /// Logs that are used for interactive investigation during development. These logs should primarily contain
+ /// information useful for debugging and have no long-term value.
+ ///
+ Debug = 1,
+
+ ///
+ /// Logs that track the general flow of the application. These logs should have long-term value.
+ ///
+ Information = 2,
+
+ ///
+ /// Logs that highlight an abnormal or unexpected event in the application flow, but do not otherwise cause the
+ /// application execution to stop.
+ ///
Warning = 3,
+
+ ///
+ /// Logs that highlight when the current flow of execution is stopped due to a failure. These should indicate a
+ /// failure in the current activity, not an application-wide failure.
+ ///
Error = 4,
- None = 5
+
+ ///
+ /// Logs that describe an unrecoverable application or system crash, or a catastrophic failure that requires
+ /// immediate attention.
+ ///
+ Critical = 5,
+
+ ///
+ /// Not used for writing log messages. Specifies that a logging category should not write any messages.
+ ///
+ None = 6,
}
///
@@ -181,16 +211,9 @@ public void LogException(
/// Since it's likely that the process will end when PSES shuts down,
/// there's no good reason to need objects rather than writing directly to the host.
///
- internal class PSHostLogger : IObserver<(PsesLogLevel logLevel, string message)>
+ /// The PowerShell host user interface object to log output to.
+ internal class PSHostLogger(PSHostUserInterface ui) : IObserver<(PsesLogLevel logLevel, string message)>
{
- private readonly PSHostUserInterface _ui;
-
- ///
- /// Create a new PowerShell host logger.
- ///
- /// The PowerShell host user interface object to log output to.
- public PSHostLogger(PSHostUserInterface ui) => _ui = ui;
-
public void OnCompleted()
{
// No-op since there's nothing to close or dispose,
@@ -201,35 +224,35 @@ public void OnCompleted()
public void OnNext((PsesLogLevel logLevel, string message) value)
{
- switch (value.logLevel)
+ (PsesLogLevel logLevel, string message) = value;
+ switch (logLevel)
{
- case PsesLogLevel.Diagnostic:
- _ui.WriteDebugLine(value.message);
- return;
-
- case PsesLogLevel.Verbose:
- _ui.WriteVerboseLine(value.message);
- return;
-
- case PsesLogLevel.Normal:
- _ui.WriteLine(value.message);
- return;
-
+ case PsesLogLevel.Trace:
+ ui.WriteDebugLine("[Trace] " + message);
+ break;
+ case PsesLogLevel.Debug:
+ ui.WriteDebugLine(message);
+ break;
+ case PsesLogLevel.Information:
+ ui.WriteVerboseLine(message);
+ break;
case PsesLogLevel.Warning:
- _ui.WriteWarningLine(value.message);
- return;
-
+ ui.WriteWarningLine(message);
+ break;
case PsesLogLevel.Error:
- _ui.WriteErrorLine(value.message);
- return;
-
+ case PsesLogLevel.Critical:
+ ui.WriteErrorLine(message);
+ break;
default:
- _ui.WriteLine(value.message);
- return;
+ ui.WriteDebugLine("UNKNOWN:" + message);
+ break;
}
}
}
+ ///
+ /// A simple log sink that logs to a stream, typically used to log to a file.
+ ///
internal class StreamLogger : IObserver<(PsesLogLevel logLevel, string message)>, IDisposable
{
public static StreamLogger CreateWithNewFile(string path)
@@ -284,9 +307,7 @@ public void OnCompleted()
}
_cancellationSource.Cancel();
-
_writerThread.Join();
-
_unsubscriber.Dispose();
_fileWriter.Flush();
_fileWriter.Close();
@@ -299,29 +320,17 @@ public void OnCompleted()
public void OnNext((PsesLogLevel logLevel, string message) value)
{
- string message = null;
- switch (value.logLevel)
+ string message = value.logLevel switch
{
- case PsesLogLevel.Diagnostic:
- message = $"[DBG]: {value.message}";
- break;
-
- case PsesLogLevel.Verbose:
- message = $"[VRB]: {value.message}";
- break;
-
- case PsesLogLevel.Normal:
- message = $"[INF]: {value.message}";
- break;
-
- case PsesLogLevel.Warning:
- message = $"[WRN]: {value.message}";
- break;
-
- case PsesLogLevel.Error:
- message = $"[ERR]: {value.message}";
- break;
- }
+ // String interpolation often considered a logging sin is OK here because our filtering happens before.
+ PsesLogLevel.Trace => $"[TRC]: {value.message}",
+ PsesLogLevel.Debug => $"[DBG]: {value.message}",
+ PsesLogLevel.Information => $"[INF]: {value.message}",
+ PsesLogLevel.Warning => $"[WRN]: {value.message}",
+ PsesLogLevel.Error => $"[ERR]: {value.message}",
+ PsesLogLevel.Critical => $"[CRT]: {value.message}",
+ _ => value.message,
+ };
_messageQueue.Add(message);
}
diff --git a/src/PowerShellEditorServices.Hosting/Configuration/SessionFileWriter.cs b/src/PowerShellEditorServices.Hosting/Configuration/SessionFileWriter.cs
index c5f351f91..bca1acd5e 100644
--- a/src/PowerShellEditorServices.Hosting/Configuration/SessionFileWriter.cs
+++ b/src/PowerShellEditorServices.Hosting/Configuration/SessionFileWriter.cs
@@ -63,7 +63,7 @@ public SessionFileWriter(HostLogger logger, string sessionFilePath, Version powe
/// The reason for the startup failure.
public void WriteSessionFailure(string reason)
{
- _logger.Log(PsesLogLevel.Diagnostic, "Writing session failure");
+ _logger.Log(PsesLogLevel.Trace, "Writing session failure");
Dictionary sessionObject = new()
{
@@ -81,7 +81,7 @@ public void WriteSessionFailure(string reason)
/// The debug adapter transport configuration.
public void WriteSessionStarted(ITransportConfig languageServiceTransport, ITransportConfig debugAdapterTransport)
{
- _logger.Log(PsesLogLevel.Diagnostic, "Writing session started");
+ _logger.Log(PsesLogLevel.Trace, "Writing session started");
Dictionary sessionObject = new()
{
@@ -142,7 +142,7 @@ private void WriteSessionObject(Dictionary sessionObject)
File.WriteAllText(_sessionFilePath, content, s_sessionFileEncoding);
}
- _logger.Log(PsesLogLevel.Verbose, $"Session file written to {_sessionFilePath} with content:\n{content}");
+ _logger.Log(PsesLogLevel.Debug, $"Session file written to {_sessionFilePath} with content:\n{content}");
}
}
}
diff --git a/src/PowerShellEditorServices.Hosting/Configuration/TransportConfig.cs b/src/PowerShellEditorServices.Hosting/Configuration/TransportConfig.cs
index be763737c..db64a27a7 100644
--- a/src/PowerShellEditorServices.Hosting/Configuration/TransportConfig.cs
+++ b/src/PowerShellEditorServices.Hosting/Configuration/TransportConfig.cs
@@ -53,7 +53,7 @@ public sealed class StdioTransportConfig : ITransportConfig
public Task<(Stream inStream, Stream outStream)> ConnectStreamsAsync()
{
- _logger.Log(PsesLogLevel.Diagnostic, "Connecting stdio streams");
+ _logger.Log(PsesLogLevel.Trace, "Connecting stdio streams");
return Task.FromResult((Console.OpenStandardInput(), Console.OpenStandardOutput()));
}
}
@@ -102,11 +102,11 @@ private DuplexNamedPipeTransportConfig(HostLogger logger, string pipeName)
public async Task<(Stream inStream, Stream outStream)> ConnectStreamsAsync()
{
- _logger.Log(PsesLogLevel.Diagnostic, "Creating named pipe");
+ _logger.Log(PsesLogLevel.Trace, "Creating named pipe");
NamedPipeServerStream namedPipe = NamedPipeUtils.CreateNamedPipe(_pipeName, PipeDirection.InOut);
- _logger.Log(PsesLogLevel.Diagnostic, "Waiting for named pipe connection");
+ _logger.Log(PsesLogLevel.Trace, "Waiting for named pipe connection");
await namedPipe.WaitForConnectionAsync().ConfigureAwait(false);
- _logger.Log(PsesLogLevel.Diagnostic, "Named pipe connected");
+ _logger.Log(PsesLogLevel.Trace, "Named pipe connected");
return (namedPipe, namedPipe);
}
}
@@ -173,18 +173,18 @@ private SimplexNamedPipeTransportConfig(HostLogger logger, string inPipeName, st
public async Task<(Stream inStream, Stream outStream)> ConnectStreamsAsync()
{
- _logger.Log(PsesLogLevel.Diagnostic, "Starting in pipe connection");
+ _logger.Log(PsesLogLevel.Trace, "Starting in pipe connection");
NamedPipeServerStream inPipe = NamedPipeUtils.CreateNamedPipe(_inPipeName, PipeDirection.InOut);
Task inPipeConnected = inPipe.WaitForConnectionAsync();
- _logger.Log(PsesLogLevel.Diagnostic, "Starting out pipe connection");
+ _logger.Log(PsesLogLevel.Trace, "Starting out pipe connection");
NamedPipeServerStream outPipe = NamedPipeUtils.CreateNamedPipe(_outPipeName, PipeDirection.Out);
Task outPipeConnected = outPipe.WaitForConnectionAsync();
- _logger.Log(PsesLogLevel.Diagnostic, "Wating for pipe connections");
+ _logger.Log(PsesLogLevel.Trace, "Wating for pipe connections");
await Task.WhenAll(inPipeConnected, outPipeConnected).ConfigureAwait(false);
- _logger.Log(PsesLogLevel.Diagnostic, "Simplex named pipe transport connected");
+ _logger.Log(PsesLogLevel.Trace, "Simplex named pipe transport connected");
return (inPipe, outPipe);
}
}
diff --git a/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs b/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs
index f2da0eb4e..eea23353c 100644
--- a/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs
+++ b/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs
@@ -70,20 +70,20 @@ public static EditorServicesLoader Create(
Version powerShellVersion = GetPSVersion();
SessionFileWriter sessionFileWriter = new(logger, sessionDetailsPath, powerShellVersion);
- logger.Log(PsesLogLevel.Diagnostic, "Session file writer created");
+ logger.Log(PsesLogLevel.Trace, "Session file writer created");
#if CoreCLR
// In .NET Core, we add an event here to redirect dependency loading to the new AssemblyLoadContext we load PSES' dependencies into
- logger.Log(PsesLogLevel.Verbose, "Adding AssemblyResolve event handler for new AssemblyLoadContext dependency loading");
+ logger.Log(PsesLogLevel.Debug, "Adding AssemblyResolve event handler for new AssemblyLoadContext dependency loading");
PsesLoadContext psesLoadContext = new(s_psesDependencyDirPath);
- if (hostConfig.LogLevel == PsesLogLevel.Diagnostic)
+ if (hostConfig.LogLevel == PsesLogLevel.Trace)
{
AppDomain.CurrentDomain.AssemblyLoad += (object sender, AssemblyLoadEventArgs args) =>
{
logger.Log(
- PsesLogLevel.Diagnostic,
+ PsesLogLevel.Trace,
$"Loaded into load context {AssemblyLoadContext.GetLoadContext(args.LoadedAssembly)}: {args.LoadedAssembly}");
};
}
@@ -91,9 +91,9 @@ public static EditorServicesLoader Create(
AssemblyLoadContext.Default.Resolving += (AssemblyLoadContext _, AssemblyName asmName) =>
{
#if ASSEMBLY_LOAD_STACKTRACE
- logger.Log(PsesLogLevel.Diagnostic, $"Assembly resolve event fired for {asmName}. Stacktrace:\n{new StackTrace()}");
+ logger.Log(PsesLogLevel.Trace, $"Assembly resolve event fired for {asmName}. Stacktrace:\n{new StackTrace()}");
#else
- logger.Log(PsesLogLevel.Diagnostic, $"Assembly resolve event fired for {asmName}");
+ logger.Log(PsesLogLevel.Trace, $"Assembly resolve event fired for {asmName}");
#endif
// We only want the Editor Services DLL; the new ALC will lazily load its dependencies automatically
@@ -104,15 +104,15 @@ public static EditorServicesLoader Create(
string asmPath = Path.Combine(s_psesDependencyDirPath, $"{asmName.Name}.dll");
- logger.Log(PsesLogLevel.Verbose, "Loading PSES DLL using new assembly load context");
+ logger.Log(PsesLogLevel.Debug, "Loading PSES DLL using new assembly load context");
return psesLoadContext.LoadFromAssemblyPath(asmPath);
};
#else
// In .NET Framework we add an event here to redirect dependency loading in the current AppDomain for PSES' dependencies
- logger.Log(PsesLogLevel.Verbose, "Adding AssemblyResolve event handler for dependency loading");
+ logger.Log(PsesLogLevel.Debug, "Adding AssemblyResolve event handler for dependency loading");
- if (hostConfig.LogLevel == PsesLogLevel.Diagnostic)
+ if (hostConfig.LogLevel == PsesLogLevel.Trace)
{
AppDomain.CurrentDomain.AssemblyLoad += (object sender, AssemblyLoadEventArgs args) =>
{
@@ -122,7 +122,7 @@ public static EditorServicesLoader Create(
}
logger.Log(
- PsesLogLevel.Diagnostic,
+ PsesLogLevel.Trace,
$"Loaded '{args.LoadedAssembly.GetName()}' from '{args.LoadedAssembly.Location}'");
};
}
@@ -131,9 +131,9 @@ public static EditorServicesLoader Create(
AppDomain.CurrentDomain.AssemblyResolve += (object sender, ResolveEventArgs args) =>
{
#if ASSEMBLY_LOAD_STACKTRACE
- logger.Log(PsesLogLevel.Diagnostic, $"Assembly resolve event fired for {args.Name}. Stacktrace:\n{new StackTrace()}");
+ logger.Log(PsesLogLevel.Trace, $"Assembly resolve event fired for {args.Name}. Stacktrace:\n{new StackTrace()}");
#else
- logger.Log(PsesLogLevel.Diagnostic, $"Assembly resolve event fired for {args.Name}");
+ logger.Log(PsesLogLevel.Trace, $"Assembly resolve event fired for {args.Name}");
#endif
AssemblyName asmName = new(args.Name);
@@ -143,7 +143,7 @@ public static EditorServicesLoader Create(
string baseDirAsmPath = Path.Combine(s_psesBaseDirPath, dllName);
if (File.Exists(baseDirAsmPath))
{
- logger.Log(PsesLogLevel.Diagnostic, $"Loading {args.Name} from PSES base dir into LoadFile context");
+ logger.Log(PsesLogLevel.Trace, $"Loading {args.Name} from PSES base dir into LoadFile context");
return Assembly.LoadFile(baseDirAsmPath);
}
@@ -151,7 +151,7 @@ public static EditorServicesLoader Create(
string asmPath = Path.Combine(s_psesDependencyDirPath, dllName);
if (File.Exists(asmPath))
{
- logger.Log(PsesLogLevel.Diagnostic, $"Loading {args.Name} from PSES dependency dir into LoadFile context");
+ logger.Log(PsesLogLevel.Trace, $"Loading {args.Name} from PSES dependency dir into LoadFile context");
return Assembly.LoadFile(asmPath);
}
@@ -212,10 +212,10 @@ public Task LoadAndRunEditorServicesAsync()
ValidateConfiguration();
// Method with no implementation that forces the PSES assembly to load, triggering an AssemblyResolve event
- _logger.Log(PsesLogLevel.Verbose, "Loading PowerShell Editor Services");
+ _logger.Log(PsesLogLevel.Information, "Loading PowerShell Editor Services Assemblies");
LoadEditorServices();
- _logger.Log(PsesLogLevel.Verbose, "Starting EditorServices");
+ _logger.Log(PsesLogLevel.Information, "Starting PowerShell Editor Services");
_editorServicesRunner = new EditorServicesRunner(_logger, _hostConfig, _sessionFileWriter, _loggersToUnsubscribe);
@@ -225,7 +225,7 @@ public Task LoadAndRunEditorServicesAsync()
public void Dispose()
{
- _logger.Log(PsesLogLevel.Diagnostic, "Loader disposed");
+ _logger.Log(PsesLogLevel.Trace, "Loader disposed");
_editorServicesRunner?.Dispose();
// TODO:
@@ -242,7 +242,7 @@ private void CheckPowerShellVersion()
{
PSLanguageMode languageMode = Runspace.DefaultRunspace.SessionStateProxy.LanguageMode;
- _logger.Log(PsesLogLevel.Verbose, $@"
+ _logger.Log(PsesLogLevel.Trace, $@"
== PowerShell Details ==
- PowerShell version: {_powerShellVersion}
- Language mode: {languageMode}
@@ -261,7 +261,7 @@ private void CheckPowerShellVersion()
#if !CoreCLR
private void CheckDotNetVersion()
{
- _logger.Log(PsesLogLevel.Verbose, "Checking that .NET Framework version is at least 4.8");
+ _logger.Log(PsesLogLevel.Debug, "Checking that .NET Framework version is at least 4.8");
using RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Net Framework Setup\NDP\v4\Full");
object netFxValue = key?.GetValue("Release");
if (netFxValue == null || netFxValue is not int netFxVersion)
@@ -269,7 +269,7 @@ private void CheckDotNetVersion()
return;
}
- _logger.Log(PsesLogLevel.Verbose, $".NET registry version: {netFxVersion}");
+ _logger.Log(PsesLogLevel.Debug, $".NET registry version: {netFxVersion}");
if (netFxVersion < Net48Version)
{
@@ -283,26 +283,26 @@ private void UpdatePSModulePath()
{
if (string.IsNullOrEmpty(_hostConfig.BundledModulePath))
{
- _logger.Log(PsesLogLevel.Diagnostic, "BundledModulePath not set, skipping");
+ _logger.Log(PsesLogLevel.Trace, "BundledModulePath not set, skipping");
return;
}
string psModulePath = Environment.GetEnvironmentVariable("PSModulePath").TrimEnd(Path.PathSeparator);
if ($"{psModulePath}{Path.PathSeparator}".Contains($"{_hostConfig.BundledModulePath}{Path.PathSeparator}"))
{
- _logger.Log(PsesLogLevel.Diagnostic, "BundledModulePath already set, skipping");
+ _logger.Log(PsesLogLevel.Trace, "BundledModulePath already set, skipping");
return;
}
psModulePath = $"{psModulePath}{Path.PathSeparator}{_hostConfig.BundledModulePath}";
Environment.SetEnvironmentVariable("PSModulePath", psModulePath);
- _logger.Log(PsesLogLevel.Verbose, $"Updated PSModulePath to: '{psModulePath}'");
+ _logger.Log(PsesLogLevel.Trace, $"Updated PSModulePath to: '{psModulePath}'");
}
private void LogHostInformation()
{
- _logger.Log(PsesLogLevel.Verbose, $"PID: {System.Diagnostics.Process.GetCurrentProcess().Id}");
+ _logger.Log(PsesLogLevel.Trace, $"PID: {System.Diagnostics.Process.GetCurrentProcess().Id}");
- _logger.Log(PsesLogLevel.Verbose, $@"
+ _logger.Log(PsesLogLevel.Debug, $@"
== Build Details ==
- Editor Services version: {BuildInfo.BuildVersion}
- Build origin: {BuildInfo.BuildOrigin}
@@ -310,7 +310,7 @@ private void LogHostInformation()
- Build time: {BuildInfo.BuildTime}
");
- _logger.Log(PsesLogLevel.Verbose, $@"
+ _logger.Log(PsesLogLevel.Debug, $@"
== Host Startup Configuration Details ==
- Host name: {_hostConfig.HostInfo.Name}
- Host version: {_hostConfig.HostInfo.Version}
@@ -333,14 +333,14 @@ private void LogHostInformation()
+ CurrentUserCurrentHost: {_hostConfig.ProfilePaths.CurrentUserCurrentHost ?? ""}
");
- _logger.Log(PsesLogLevel.Verbose, $@"
+ _logger.Log(PsesLogLevel.Debug, $@"
== Console Details ==
- Console input encoding: {Console.InputEncoding.EncodingName}
- Console output encoding: {Console.OutputEncoding.EncodingName}
- PowerShell output encoding: {GetPSOutputEncoding()}
");
- _logger.Log(PsesLogLevel.Verbose, $@"
+ _logger.Log(PsesLogLevel.Debug, $@"
== Environment Details ==
- OS description: {RuntimeInformation.OSDescription}
- OS architecture: {RuntimeInformation.OSArchitecture}
@@ -359,7 +359,7 @@ private static string GetPSOutputEncoding()
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2208:Instantiate argument exceptions correctly", Justification = "Checking user-defined configuration")]
private void ValidateConfiguration()
{
- _logger.Log(PsesLogLevel.Diagnostic, "Validating configuration");
+ _logger.Log(PsesLogLevel.Debug, "Validating configuration");
bool lspUsesStdio = _hostConfig.LanguageServiceTransport is StdioTransportConfig;
bool debugUsesStdio = _hostConfig.DebugServiceTransport is StdioTransportConfig;
@@ -382,6 +382,7 @@ private void ValidateConfiguration()
}
}
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1825:Avoid zero-length array allocations", Justification = "Cannot use Array.Empty, since it must work in net452")]
private static Version GetPSVersion()
{
// In order to read the $PSVersionTable variable,
@@ -389,12 +390,10 @@ private static Version GetPSVersion()
// which is expensive.
// Rather than do that, we instead go straight to the source,
// which is a static property, internal in WinPS and public in PS 6+
-#pragma warning disable CA1825
return typeof(PSObject).Assembly
.GetType("System.Management.Automation.PSVersionInfo")
.GetMethod("get_PSVersion", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
- .Invoke(null, new object[0] /* Cannot use Array.Empty, since it must work in net452 */) as Version;
-#pragma warning restore CA1825
+ .Invoke(null, new object[0]) as Version;
}
}
}
diff --git a/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs b/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs
index 8f868d393..5d8c368c9 100644
--- a/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs
+++ b/src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs
@@ -42,7 +42,7 @@ public EditorServicesRunner(
_config = config;
_sessionFileWriter = sessionFileWriter;
// NOTE: This factory helps to isolate `Microsoft.Extensions.Logging/DependencyInjection`.
- _serverFactory = EditorServicesServerFactory.Create(_config.LogPath, (int)_config.LogLevel, logger);
+ _serverFactory = new(logger);
_alreadySubscribedDebug = false;
_loggersToUnsubscribe = loggersToUnsubscribe;
}
@@ -60,11 +60,11 @@ public Task RunUntilShutdown()
Task runAndAwaitShutdown = CreateEditorServicesAndRunUntilShutdown();
// Now write the session file
- _logger.Log(PsesLogLevel.Diagnostic, "Writing session file");
+ _logger.Log(PsesLogLevel.Trace, "Writing session file");
_sessionFileWriter.WriteSessionStarted(_config.LanguageServiceTransport, _config.DebugServiceTransport);
// Finally, wait for Editor Services to shut down
- _logger.Log(PsesLogLevel.Diagnostic, "Waiting on PSES run/shutdown");
+ _logger.Log(PsesLogLevel.Debug, "Waiting on PSES run/shutdown");
return runAndAwaitShutdown;
}
@@ -124,7 +124,7 @@ private async Task CreateEditorServicesAndRunUntilShutdown()
{
try
{
- _logger.Log(PsesLogLevel.Diagnostic, "Creating/running editor services");
+ _logger.Log(PsesLogLevel.Debug, "Creating/running editor services");
bool creatingLanguageServer = _config.LanguageServiceTransport != null;
bool creatingDebugServer = _config.DebugServiceTransport != null;
@@ -140,6 +140,9 @@ private async Task CreateEditorServicesAndRunUntilShutdown()
return;
}
+ _logger.Log(PsesLogLevel.Information, "PSES Startup Completed. Starting Language Server.");
+ _logger.Log(PsesLogLevel.Information, "Please check the LSP log file in your client for further messages. In VSCode, this is the 'PowerShell' output pane");
+
// We want LSP and maybe debugging
// To do that we:
// - Create the LSP server
@@ -149,7 +152,6 @@ private async Task CreateEditorServicesAndRunUntilShutdown()
// - Wait for the LSP server to finish
// Unsubscribe the host logger here so that the Extension Terminal is not polluted with input after the first prompt
- _logger.Log(PsesLogLevel.Verbose, "Starting server, deregistering host logger and registering shutdown listener");
if (_loggersToUnsubscribe != null)
{
foreach (IDisposable loggerToUnsubscribe in _loggersToUnsubscribe)
@@ -193,14 +195,15 @@ private async Task CreateEditorServicesAndRunUntilShutdown()
private async Task RunTempDebugSessionAsync(HostStartupInfo hostDetails)
{
- _logger.Log(PsesLogLevel.Diagnostic, "Running temp debug session");
+ _logger.Log(PsesLogLevel.Information, "Starting temporary debug session");
PsesDebugServer debugServer = await CreateDebugServerForTempSessionAsync(hostDetails).ConfigureAwait(false);
- _logger.Log(PsesLogLevel.Verbose, "Debug server created");
+ _logger.Log(PsesLogLevel.Debug, "Debug server created");
await debugServer.StartAsync().ConfigureAwait(false);
- _logger.Log(PsesLogLevel.Verbose, "Debug server started");
+ _logger.Log(PsesLogLevel.Debug, "Debug server started");
await debugServer.WaitForShutdown().ConfigureAwait(false);
}
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD003:Avoid awaiting foreign Tasks", Justification = "It's a wrapper.")]
private async Task StartDebugServer(Task debugServerCreation)
{
PsesDebugServer debugServer = await debugServerCreation.ConfigureAwait(false);
@@ -209,47 +212,47 @@ private async Task StartDebugServer(Task debugServerCreation)
// To do this, we set an event to allow it to create a new debug server as its session ends
if (!_alreadySubscribedDebug)
{
- _logger.Log(PsesLogLevel.Diagnostic, "Subscribing debug server for session ended event");
+ _logger.Log(PsesLogLevel.Trace, "Subscribing debug server for session ended event");
_alreadySubscribedDebug = true;
debugServer.SessionEnded += DebugServer_OnSessionEnded;
}
- _logger.Log(PsesLogLevel.Diagnostic, "Starting debug server");
+ _logger.Log(PsesLogLevel.Trace, "Starting debug server");
await debugServer.StartAsync().ConfigureAwait(false);
}
private Task RestartDebugServerAsync(PsesDebugServer debugServer)
{
- _logger.Log(PsesLogLevel.Diagnostic, "Restarting debug server");
+ _logger.Log(PsesLogLevel.Debug, "Restarting debug server");
Task debugServerCreation = RecreateDebugServerAsync(debugServer);
return StartDebugServer(debugServerCreation);
}
private async Task CreateLanguageServerAsync(HostStartupInfo hostDetails)
{
- _logger.Log(PsesLogLevel.Verbose, $"Creating LSP transport with endpoint {_config.LanguageServiceTransport.EndpointDetails}");
+ _logger.Log(PsesLogLevel.Trace, $"Creating LSP transport with endpoint {_config.LanguageServiceTransport.EndpointDetails}");
(Stream inStream, Stream outStream) = await _config.LanguageServiceTransport.ConnectStreamsAsync().ConfigureAwait(false);
- _logger.Log(PsesLogLevel.Diagnostic, "Creating language server");
+ _logger.Log(PsesLogLevel.Debug, "Creating language server");
return _serverFactory.CreateLanguageServer(inStream, outStream, hostDetails);
}
private async Task CreateDebugServerWithLanguageServerAsync(PsesLanguageServer languageServer)
{
- _logger.Log(PsesLogLevel.Verbose, $"Creating debug adapter transport with endpoint {_config.DebugServiceTransport.EndpointDetails}");
+ _logger.Log(PsesLogLevel.Trace, $"Creating debug adapter transport with endpoint {_config.DebugServiceTransport.EndpointDetails}");
(Stream inStream, Stream outStream) = await _config.DebugServiceTransport.ConnectStreamsAsync().ConfigureAwait(false);
- _logger.Log(PsesLogLevel.Diagnostic, "Creating debug adapter");
+ _logger.Log(PsesLogLevel.Debug, "Creating debug adapter");
return _serverFactory.CreateDebugServerWithLanguageServer(inStream, outStream, languageServer);
}
private async Task RecreateDebugServerAsync(PsesDebugServer debugServer)
{
- _logger.Log(PsesLogLevel.Diagnostic, "Recreating debug adapter transport");
+ _logger.Log(PsesLogLevel.Debug, "Recreating debug adapter transport");
(Stream inStream, Stream outStream) = await _config.DebugServiceTransport.ConnectStreamsAsync().ConfigureAwait(false);
- _logger.Log(PsesLogLevel.Diagnostic, "Recreating debug adapter");
+ _logger.Log(PsesLogLevel.Debug, "Recreating debug adapter");
return _serverFactory.RecreateDebugServer(inStream, outStream, debugServer);
}
@@ -262,20 +265,14 @@ private async Task CreateDebugServerForTempSessionAsync(HostSta
private HostStartupInfo CreateHostStartupInfo()
{
- _logger.Log(PsesLogLevel.Diagnostic, "Creating startup info object");
+ _logger.Log(PsesLogLevel.Debug, "Creating startup info object");
- ProfilePathInfo profilePaths = null;
- if (_config.ProfilePaths.AllUsersAllHosts != null
- || _config.ProfilePaths.AllUsersCurrentHost != null
- || _config.ProfilePaths.CurrentUserAllHosts != null
- || _config.ProfilePaths.CurrentUserCurrentHost != null)
- {
- profilePaths = new ProfilePathInfo(
- _config.ProfilePaths.CurrentUserAllHosts,
- _config.ProfilePaths.CurrentUserCurrentHost,
- _config.ProfilePaths.AllUsersAllHosts,
- _config.ProfilePaths.AllUsersCurrentHost);
- }
+ ProfilePathInfo profilePaths = new(
+ _config.ProfilePaths.CurrentUserAllHosts,
+ _config.ProfilePaths.CurrentUserCurrentHost,
+ _config.ProfilePaths.AllUsersAllHosts,
+ _config.ProfilePaths.AllUsersCurrentHost
+ );
return new HostStartupInfo(
_config.HostInfo.Name,
@@ -287,7 +284,7 @@ private HostStartupInfo CreateHostStartupInfo()
_config.AdditionalModules,
_config.InitialSessionState,
_config.LogPath,
- (int)_config.LogLevel,
+ (int)_config.LogLevel, //This maps to MEL log levels, we use int so this is easily supplied externally.
consoleReplEnabled: _config.ConsoleRepl != ConsoleReplKind.None,
useNullPSHostUI: _config.UseNullPSHostUI,
usesLegacyReadLine: _config.ConsoleRepl == ConsoleReplKind.LegacyReadLine,
@@ -304,9 +301,10 @@ private void WriteStartupBanner()
_config.PSHost.UI.WriteLine(_config.StartupBanner);
}
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD110:Observe result of async calls", Justification = "Intentionally fire and forget.")]
private void DebugServer_OnSessionEnded(object sender, EventArgs args)
{
- _logger.Log(PsesLogLevel.Verbose, "Debug session ended, restarting debug service...");
+ _logger.Log(PsesLogLevel.Debug, "Debug session ended, restarting debug service...");
PsesDebugServer oldServer = (PsesDebugServer)sender;
oldServer.Dispose();
_alreadySubscribedDebug = false;
diff --git a/src/PowerShellEditorServices.Hosting/PowerShellEditorServices.Hosting.csproj b/src/PowerShellEditorServices.Hosting/PowerShellEditorServices.Hosting.csproj
index 5c31f0758..1c30a93df 100644
--- a/src/PowerShellEditorServices.Hosting/PowerShellEditorServices.Hosting.csproj
+++ b/src/PowerShellEditorServices.Hosting/PowerShellEditorServices.Hosting.csproj
@@ -1,8 +1,9 @@
-
+
- net6.0;net462
+ net8.0;net462
Microsoft.PowerShell.EditorServices.Hosting
@@ -11,10 +12,15 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
@@ -22,7 +28,7 @@
-
+
diff --git a/src/PowerShellEditorServices.Hosting/packages.lock.json b/src/PowerShellEditorServices.Hosting/packages.lock.json
deleted file mode 100644
index 8be3c7711..000000000
--- a/src/PowerShellEditorServices.Hosting/packages.lock.json
+++ /dev/null
@@ -1,979 +0,0 @@
-{
- "version": 1,
- "dependencies": {
- ".NETFramework,Version=v4.6.2": {
- "Microsoft.NETFramework.ReferenceAssemblies": {
- "type": "Direct",
- "requested": "[1.0.3, )",
- "resolved": "1.0.3",
- "contentHash": "vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==",
- "dependencies": {
- "Microsoft.NETFramework.ReferenceAssemblies.net462": "1.0.3"
- }
- },
- "NETStandard.Library": {
- "type": "Direct",
- "requested": "[2.0.3, )",
- "resolved": "2.0.3",
- "contentHash": "st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==",
- "dependencies": {
- "Microsoft.NETCore.Platforms": "1.1.0"
- }
- },
- "PowerShellStandard.Library": {
- "type": "Direct",
- "requested": "[5.1.1, )",
- "resolved": "5.1.1",
- "contentHash": "e31xJjG+Kjbv6YF3Yq6D4Dl3or8v7LrNF41k3CXrWozW6hR1zcOe5KYuZJaGSiAgLnwP8wcW+I3+IWEzMPZKXQ=="
- },
- "System.IO.Pipes.AccessControl": {
- "type": "Direct",
- "requested": "[5.0.0, )",
- "resolved": "5.0.0",
- "contentHash": "P0FIsXSFNL1AXlHO9zpJ9atRUzVyoPZCkcbkYGZfXXMx9xlGA2H3HOGBwIhpKhB+h0eL3hry/z0UcfJZ+yb2kQ==",
- "dependencies": {
- "System.Security.AccessControl": "5.0.0",
- "System.Security.Principal.Windows": "5.0.0"
- }
- },
- "System.Runtime.InteropServices.RuntimeInformation": {
- "type": "Direct",
- "requested": "[4.3.0, )",
- "resolved": "4.3.0",
- "contentHash": "cbz4YJMqRDR7oLeMRbdYv7mYzc++17lNhScCX0goO2XpGWdvAt60CGN+FHdePUEHCe/Jy9jUlvNAiNdM+7jsOw=="
- },
- "System.ValueTuple": {
- "type": "Direct",
- "requested": "[4.5.0, )",
- "resolved": "4.5.0",
- "contentHash": "okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ=="
- },
- "MediatR": {
- "type": "Transitive",
- "resolved": "8.1.0",
- "contentHash": "KJFnA0MV83bNOhvYbjIX1iDykhwFXoQu0KV7E1SVbNA/CmO2I7SAm2Baly0eS7VJ2GwlmStLajBfeiNgTpvYzQ=="
- },
- "Microsoft.Bcl.AsyncInterfaces": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "3WA9q9yVqJp222P3x1wYIGDAkpjAku0TMUaaQV22g6L67AI0LdOIrVS7Ht2vJfLHGSPVuqN94vIr15qn+HEkHw==",
- "dependencies": {
- "System.Threading.Tasks.Extensions": "4.5.4"
- }
- },
- "Microsoft.CSharp": {
- "type": "Transitive",
- "resolved": "4.7.0",
- "contentHash": "pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA=="
- },
- "Microsoft.Extensions.Configuration": {
- "type": "Transitive",
- "resolved": "6.0.1",
- "contentHash": "BUyFU9t+HzlSE7ri4B+AQN2BgTgHv/uM82s5ZkgU1BApyzWzIl48nDsG5wR1t0pniNuuyTBzG3qCW8152/NtSw==",
- "dependencies": {
- "Microsoft.Extensions.Configuration.Abstractions": "6.0.0",
- "Microsoft.Extensions.Primitives": "6.0.0"
- }
- },
- "Microsoft.Extensions.Configuration.Abstractions": {
- "type": "Transitive",
- "resolved": "6.0.0",
- "contentHash": "qWzV9o+ZRWq+pGm+1dF+R7qTgTYoXvbyowRoBxQJGfqTpqDun2eteerjRQhq5PQ/14S+lqto3Ft4gYaRyl4rdQ==",
- "dependencies": {
- "Microsoft.Extensions.Primitives": "6.0.0",
- "System.ValueTuple": "4.5.0"
- }
- },
- "Microsoft.Extensions.Configuration.Binder": {
- "type": "Transitive",
- "resolved": "6.0.0",
- "contentHash": "b3ErKzND8LIC7o08QAVlKfaEIYEvLJbtmVbFZVBRXeu9YkKfSSzLZfR1SUfQPBIy9mKLhEtJgGYImkcMNaKE0A==",
- "dependencies": {
- "Microsoft.Extensions.Configuration.Abstractions": "6.0.0"
- }
- },
- "Microsoft.Extensions.DependencyInjection": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "V8S3bsm50ig6JSyrbcJJ8bW2b9QLGouz+G1miK3UTaOWmMtFwNNNzUf4AleyDWUmTrWMLNnFSLEQtxmxgNQnNQ==",
- "dependencies": {
- "Microsoft.Bcl.AsyncInterfaces": "8.0.0",
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "System.Threading.Tasks.Extensions": "4.5.4"
- }
- },
- "Microsoft.Extensions.DependencyInjection.Abstractions": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==",
- "dependencies": {
- "Microsoft.Bcl.AsyncInterfaces": "8.0.0",
- "System.Threading.Tasks.Extensions": "4.5.4"
- }
- },
- "Microsoft.Extensions.FileSystemGlobbing": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "OK+670i7esqlQrPjdIKRbsyMCe9g5kSLpRRQGSr4Q58AOYEe/hCnfLZprh7viNisSUUQZmMrbbuDaIrP+V1ebQ=="
- },
- "Microsoft.Extensions.Logging": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "tvRkov9tAJ3xP51LCv3FJ2zINmv1P8Hi8lhhtcKGqM+ImiTCC84uOPEI4z8Cdq2C3o9e+Aa0Gw0rmrsJD77W+w==",
- "dependencies": {
- "Microsoft.Bcl.AsyncInterfaces": "8.0.0",
- "Microsoft.Extensions.DependencyInjection": "8.0.0",
- "Microsoft.Extensions.Logging.Abstractions": "8.0.0",
- "Microsoft.Extensions.Options": "8.0.0",
- "System.Diagnostics.DiagnosticSource": "8.0.0",
- "System.ValueTuple": "4.5.0"
- }
- },
- "Microsoft.Extensions.Logging.Abstractions": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "arDBqTgFCyS0EvRV7O3MZturChstm50OJ0y9bDJvAcmEPJm0FFpFyjU/JLYyStNGGey081DvnQYlncNX5SJJGA==",
- "dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "System.Buffers": "4.5.1",
- "System.Memory": "4.5.5"
- }
- },
- "Microsoft.Extensions.Options": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "JOVOfqpnqlVLUzINQ2fox8evY2SKLYJ3BV8QDe/Jyp21u1T7r45x/R/5QdteURMR5r01GxeJSBBUOCOyaNXA3g==",
- "dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "Microsoft.Extensions.Primitives": "8.0.0",
- "System.ValueTuple": "4.5.0"
- }
- },
- "Microsoft.Extensions.Options.ConfigurationExtensions": {
- "type": "Transitive",
- "resolved": "6.0.0",
- "contentHash": "bXWINbTn0vC0FYc9GaQTISbxhQLAMrvtbuvD9N6JelEaIS/Pr62wUCinrq5bf1WRBGczt1v4wDhxFtVFNcMdUQ==",
- "dependencies": {
- "Microsoft.Extensions.Configuration.Abstractions": "6.0.0",
- "Microsoft.Extensions.Configuration.Binder": "6.0.0",
- "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
- "Microsoft.Extensions.Options": "6.0.0",
- "Microsoft.Extensions.Primitives": "6.0.0"
- }
- },
- "Microsoft.Extensions.Primitives": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==",
- "dependencies": {
- "System.Memory": "4.5.5",
- "System.Runtime.CompilerServices.Unsafe": "6.0.0"
- }
- },
- "Microsoft.NETCore.Platforms": {
- "type": "Transitive",
- "resolved": "1.1.0",
- "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A=="
- },
- "Microsoft.NETFramework.ReferenceAssemblies.net462": {
- "type": "Transitive",
- "resolved": "1.0.3",
- "contentHash": "IzAV30z22ESCeQfxP29oVf4qEo8fBGXLXSU6oacv/9Iqe6PzgHDKCaWfwMBak7bSJQM0F5boXWoZS+kChztRIQ=="
- },
- "Microsoft.VisualStudio.Threading": {
- "type": "Transitive",
- "resolved": "17.6.40",
- "contentHash": "hLa/0xargG7p3bF7aeq2/lRYn/bVnfZXurUWVHx+MNqxxAUjIDMKi4OIOWbYQ/DTkbn9gv8TLvgso+6EtHVQQg==",
- "dependencies": {
- "Microsoft.Bcl.AsyncInterfaces": "7.0.0",
- "Microsoft.VisualStudio.Threading.Analyzers": "17.6.40",
- "Microsoft.VisualStudio.Validation": "17.0.71",
- "Microsoft.Win32.Registry": "5.0.0",
- "System.Threading.Tasks.Extensions": "4.5.4"
- }
- },
- "Microsoft.VisualStudio.Threading.Analyzers": {
- "type": "Transitive",
- "resolved": "17.6.40",
- "contentHash": "uU8vYr/Nx3ldEWcsbiHiyAX1G7od3eFK1+Aga6ZvgCvU+nQkcXYVkIMcSEkIDWkFaldx1dkoVvX3KRNQD0R7dw=="
- },
- "Microsoft.VisualStudio.Validation": {
- "type": "Transitive",
- "resolved": "17.6.11",
- "contentHash": "J+9L/iac6c8cwcgVSCMuoIYOlD1Jw4mbZ8XMe1IZVj8p8+3dJ46LnnkIkTRMjK7xs9UtU9MoUp1JGhWoN6fAEw=="
- },
- "Microsoft.Win32.Registry": {
- "type": "Transitive",
- "resolved": "5.0.0",
- "contentHash": "dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==",
- "dependencies": {
- "System.Security.AccessControl": "5.0.0",
- "System.Security.Principal.Windows": "5.0.0"
- }
- },
- "Nerdbank.Streams": {
- "type": "Transitive",
- "resolved": "2.10.69",
- "contentHash": "YIudzeVyQRJAqytjpo1jdHkh2t+vqQqyusBqb2sFSOAOGEnyOXhcHx/rQqSuCIXUDr50a3XuZnamGRfQVBOf4g==",
- "dependencies": {
- "Microsoft.Bcl.AsyncInterfaces": "7.0.0",
- "Microsoft.VisualStudio.Threading": "17.6.40",
- "Microsoft.VisualStudio.Validation": "17.6.11",
- "System.IO.Pipelines": "7.0.0",
- "System.Runtime.CompilerServices.Unsafe": "6.0.0"
- }
- },
- "Newtonsoft.Json": {
- "type": "Transitive",
- "resolved": "13.0.3",
- "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
- },
- "OmniSharp.Extensions.DebugAdapter": {
- "type": "Transitive",
- "resolved": "0.19.9",
- "contentHash": "Jy9RlVei7ay3LavvPH4F8BnIIMAo5th5EI8JnVe1RQlOxvu18H8hOyZ8fLFHtzbObs+oTONsJ9aynqeyMOErgA==",
- "dependencies": {
- "Microsoft.Extensions.Configuration": "6.0.1",
- "OmniSharp.Extensions.JsonRpc": "0.19.9",
- "OmniSharp.Extensions.JsonRpc.Generators": "0.19.9"
- }
- },
- "OmniSharp.Extensions.DebugAdapter.Server": {
- "type": "Transitive",
- "resolved": "0.19.9",
- "contentHash": "XRJ6EW44DaODkzjAuN1XbpnPFkciJIM2sIx4KpsvV/2Rle1CdRJY4gA6vJn+2uNh5hRr1d0SqZSieqV9Ly0utw==",
- "dependencies": {
- "OmniSharp.Extensions.DebugAdapter.Shared": "0.19.9"
- }
- },
- "OmniSharp.Extensions.DebugAdapter.Shared": {
- "type": "Transitive",
- "resolved": "0.19.9",
- "contentHash": "A4psuqk+slrs585cCkZkwUO08nW0I6SVH4u7B7d8wU9lH0LLRTvQBlo3QlxrVAMxjwljPFzXaaRHv7D7X1BXbw==",
- "dependencies": {
- "OmniSharp.Extensions.DebugAdapter": "0.19.9",
- "OmniSharp.Extensions.JsonRpc": "0.19.9"
- }
- },
- "OmniSharp.Extensions.JsonRpc": {
- "type": "Transitive",
- "resolved": "0.19.9",
- "contentHash": "utFvrx9OYXhCS5rnfWAVeedJCrucuDLAOrKXjohf/NOjG9FFVbcp+hLqj9Ng+AxoADRD+rSJYHfBOeqGl5zW0A==",
- "dependencies": {
- "MediatR": "8.1.0",
- "Microsoft.Extensions.DependencyInjection": "6.0.1",
- "Microsoft.Extensions.Logging": "6.0.0",
- "Nerdbank.Streams": "2.10.69",
- "Newtonsoft.Json": "13.0.3",
- "OmniSharp.Extensions.JsonRpc.Generators": "0.19.9",
- "System.Collections.Immutable": "5.0.0",
- "System.Reactive": "6.0.0",
- "System.Threading.Channels": "6.0.0"
- }
- },
- "OmniSharp.Extensions.JsonRpc.Generators": {
- "type": "Transitive",
- "resolved": "0.19.9",
- "contentHash": "hiWC0yGcKM+K00fgiL7KBmlvULmkKNhm40ZSzxqT+jNV21r+YZgKzEREhQe40ufb4tjcIxdYkif++IzGl/3H/Q=="
- },
- "OmniSharp.Extensions.LanguageProtocol": {
- "type": "Transitive",
- "resolved": "0.19.9",
- "contentHash": "d0crY6w5SyunGlERP27YeUeJnJfUjvJoALFlPMU4CHu3jovG1Y8RxLpihCPX8fKdjzgy7Ii+VjFYtIpDEEQqYQ==",
- "dependencies": {
- "Microsoft.Extensions.Configuration": "6.0.1",
- "Microsoft.Extensions.Configuration.Binder": "6.0.0",
- "Microsoft.Extensions.Options.ConfigurationExtensions": "6.0.0",
- "OmniSharp.Extensions.JsonRpc": "0.19.9",
- "OmniSharp.Extensions.JsonRpc.Generators": "0.19.9"
- }
- },
- "OmniSharp.Extensions.LanguageServer": {
- "type": "Transitive",
- "resolved": "0.19.9",
- "contentHash": "g09wOOCQ/oFqtZ47Q5R9E78tz2a5ODEB+V+S65wAiiRskR7xwL78Tse4/8ToBc8G/ZgQgqLtAOPo/BSPmHNlbw==",
- "dependencies": {
- "Microsoft.Extensions.Configuration": "6.0.1",
- "OmniSharp.Extensions.JsonRpc": "0.19.9",
- "OmniSharp.Extensions.LanguageProtocol": "0.19.9",
- "OmniSharp.Extensions.LanguageServer.Shared": "0.19.9"
- }
- },
- "OmniSharp.Extensions.LanguageServer.Shared": {
- "type": "Transitive",
- "resolved": "0.19.9",
- "contentHash": "+p+py79MrNG3QnqRrBp5J7Wc810HFFczMH8/WLIiUqih1bqmKPFY9l/uzBvq1Ko8+YO/8tzI7BDffHvaguISEw==",
- "dependencies": {
- "OmniSharp.Extensions.LanguageProtocol": "0.19.9"
- }
- },
- "Serilog": {
- "type": "Transitive",
- "resolved": "3.1.1",
- "contentHash": "P6G4/4Kt9bT635bhuwdXlJ2SCqqn2nhh4gqFqQueCOr9bK/e7W9ll/IoX1Ter948cV2Z/5+5v8pAfJYUISY03A==",
- "dependencies": {
- "System.Diagnostics.DiagnosticSource": "7.0.2",
- "System.ValueTuple": "4.5.0"
- }
- },
- "Serilog.Extensions.Logging": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "YEAMWu1UnWgf1c1KP85l1SgXGfiVo0Rz6x08pCiPOIBt2Qe18tcZLvdBUuV5o1QHvrs8FAry9wTIhgBRtjIlEg==",
- "dependencies": {
- "Microsoft.Extensions.Logging": "8.0.0",
- "Serilog": "3.1.1"
- }
- },
- "Serilog.Sinks.Async": {
- "type": "Transitive",
- "resolved": "1.5.0",
- "contentHash": "csHYIqAwI4Gy9oAhXYRwxGrQEAtBg3Ep7WaCzsnA1cZuBZjVAU0n7hWaJhItjO7hbLHh/9gRVxALCUB4Dv+gZw==",
- "dependencies": {
- "Serilog": "2.9.0"
- }
- },
- "Serilog.Sinks.File": {
- "type": "Transitive",
- "resolved": "5.0.0",
- "contentHash": "uwV5hdhWPwUH1szhO8PJpFiahqXmzPzJT/sOijH/kFgUx+cyoDTMM8MHD0adw9+Iem6itoibbUXHYslzXsLEAg==",
- "dependencies": {
- "Serilog": "2.10.0"
- }
- },
- "System.Buffers": {
- "type": "Transitive",
- "resolved": "4.5.1",
- "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg=="
- },
- "System.Collections.Immutable": {
- "type": "Transitive",
- "resolved": "5.0.0",
- "contentHash": "FXkLXiK0sVVewcso0imKQoOxjoPAj42R8HtjjbSjVPAzwDfzoyoznWxgA3c38LDbN9SJux1xXoXYAhz98j7r2g==",
- "dependencies": {
- "System.Memory": "4.5.4"
- }
- },
- "System.Diagnostics.DiagnosticSource": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "c9xLpVz6PL9lp/djOWtk5KPDZq3cSYpmXoJQY524EOtuFl5z9ZtsotpsyrDW40U1DRnQSYvcPKEUV0X//u6gkQ==",
- "dependencies": {
- "System.Memory": "4.5.5",
- "System.Runtime.CompilerServices.Unsafe": "6.0.0"
- }
- },
- "System.IO.Pipelines": {
- "type": "Transitive",
- "resolved": "7.0.0",
- "contentHash": "jRn6JYnNPW6xgQazROBLSfpdoczRw694vO5kKvMcNnpXuolEixUyw6IBuBs2Y2mlSX/LdLvyyWmfXhaI3ND1Yg==",
- "dependencies": {
- "System.Buffers": "4.5.1",
- "System.Memory": "4.5.5",
- "System.Threading.Tasks.Extensions": "4.5.4"
- }
- },
- "System.Memory": {
- "type": "Transitive",
- "resolved": "4.5.5",
- "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==",
- "dependencies": {
- "System.Buffers": "4.5.1",
- "System.Numerics.Vectors": "4.5.0",
- "System.Runtime.CompilerServices.Unsafe": "4.5.3"
- }
- },
- "System.Numerics.Vectors": {
- "type": "Transitive",
- "resolved": "4.5.0",
- "contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ=="
- },
- "System.Reactive": {
- "type": "Transitive",
- "resolved": "6.0.0",
- "contentHash": "31kfaW4ZupZzPsI5PVe77VhnvFF55qgma7KZr/E0iFTs6fmdhhG8j0mgEx620iLTey1EynOkEfnyTjtNEpJzGw==",
- "dependencies": {
- "System.Threading.Tasks.Extensions": "4.5.4"
- }
- },
- "System.Runtime.CompilerServices.Unsafe": {
- "type": "Transitive",
- "resolved": "6.0.0",
- "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
- },
- "System.Security.AccessControl": {
- "type": "Transitive",
- "resolved": "5.0.0",
- "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==",
- "dependencies": {
- "System.Security.Principal.Windows": "5.0.0"
- }
- },
- "System.Security.Principal": {
- "type": "Transitive",
- "resolved": "4.3.0",
- "contentHash": "I1tkfQlAoMM2URscUtpcRo/hX0jinXx6a/KUtEQoz3owaYwl3qwsO8cbzYVVnjxrzxjHo3nJC+62uolgeGIS9A=="
- },
- "System.Security.Principal.Windows": {
- "type": "Transitive",
- "resolved": "5.0.0",
- "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA=="
- },
- "System.Threading.Channels": {
- "type": "Transitive",
- "resolved": "6.0.0",
- "contentHash": "TY8/9+tI0mNaUMgntOxxaq2ndTkdXqLSxvPmas7XEqOlv9lQtB7wLjYGd756lOaO7Dvb5r/WXhluM+0Xe87v5Q==",
- "dependencies": {
- "System.Threading.Tasks.Extensions": "4.5.4"
- }
- },
- "System.Threading.Tasks.Extensions": {
- "type": "Transitive",
- "resolved": "4.5.4",
- "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==",
- "dependencies": {
- "System.Runtime.CompilerServices.Unsafe": "4.5.3"
- }
- },
- "Microsoft.PowerShell.EditorServices": {
- "type": "Project",
- "dependencies": {
- "Microsoft.CSharp": "[4.7.0, )",
- "Microsoft.Extensions.FileSystemGlobbing": "[8.0.0, )",
- "Microsoft.Extensions.Logging": "[8.0.0, )",
- "OmniSharp.Extensions.DebugAdapter.Server": "[0.19.9, )",
- "OmniSharp.Extensions.LanguageServer": "[0.19.9, )",
- "PowerShellStandard.Library": "[5.1.1, )",
- "Serilog": "[3.1.1, )",
- "Serilog.Extensions.Logging": "[8.0.0, )",
- "Serilog.Sinks.Async": "[1.5.0, )",
- "Serilog.Sinks.File": "[5.0.0, )",
- "System.IO.Pipes.AccessControl": "[5.0.0, )",
- "System.Security.Principal": "[4.3.0, )",
- "System.Security.Principal.Windows": "[5.0.0, )"
- }
- }
- },
- "net6.0": {
- "NETStandard.Library": {
- "type": "Direct",
- "requested": "[2.0.3, )",
- "resolved": "2.0.3",
- "contentHash": "st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==",
- "dependencies": {
- "Microsoft.NETCore.Platforms": "1.1.0"
- }
- },
- "PowerShellStandard.Library": {
- "type": "Direct",
- "requested": "[5.1.1, )",
- "resolved": "5.1.1",
- "contentHash": "e31xJjG+Kjbv6YF3Yq6D4Dl3or8v7LrNF41k3CXrWozW6hR1zcOe5KYuZJaGSiAgLnwP8wcW+I3+IWEzMPZKXQ=="
- },
- "System.IO.Pipes.AccessControl": {
- "type": "Direct",
- "requested": "[5.0.0, )",
- "resolved": "5.0.0",
- "contentHash": "P0FIsXSFNL1AXlHO9zpJ9atRUzVyoPZCkcbkYGZfXXMx9xlGA2H3HOGBwIhpKhB+h0eL3hry/z0UcfJZ+yb2kQ==",
- "dependencies": {
- "System.Security.AccessControl": "5.0.0",
- "System.Security.Principal.Windows": "5.0.0"
- }
- },
- "System.Runtime.InteropServices.RuntimeInformation": {
- "type": "Direct",
- "requested": "[4.3.0, )",
- "resolved": "4.3.0",
- "contentHash": "cbz4YJMqRDR7oLeMRbdYv7mYzc++17lNhScCX0goO2XpGWdvAt60CGN+FHdePUEHCe/Jy9jUlvNAiNdM+7jsOw==",
- "dependencies": {
- "System.Reflection": "4.3.0",
- "System.Reflection.Extensions": "4.3.0",
- "System.Resources.ResourceManager": "4.3.0",
- "System.Runtime": "4.3.0",
- "System.Runtime.InteropServices": "4.3.0",
- "System.Threading": "4.3.0",
- "runtime.native.System": "4.3.0"
- }
- },
- "MediatR": {
- "type": "Transitive",
- "resolved": "8.1.0",
- "contentHash": "KJFnA0MV83bNOhvYbjIX1iDykhwFXoQu0KV7E1SVbNA/CmO2I7SAm2Baly0eS7VJ2GwlmStLajBfeiNgTpvYzQ=="
- },
- "Microsoft.Bcl.AsyncInterfaces": {
- "type": "Transitive",
- "resolved": "7.0.0",
- "contentHash": "3aeMZ1N0lJoSyzqiP03hqemtb1BijhsJADdobn/4nsMJ8V1H+CrpuduUe4hlRdx+ikBQju1VGjMD1GJ3Sk05Eg=="
- },
- "Microsoft.CSharp": {
- "type": "Transitive",
- "resolved": "4.7.0",
- "contentHash": "pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA=="
- },
- "Microsoft.Extensions.Configuration": {
- "type": "Transitive",
- "resolved": "6.0.1",
- "contentHash": "BUyFU9t+HzlSE7ri4B+AQN2BgTgHv/uM82s5ZkgU1BApyzWzIl48nDsG5wR1t0pniNuuyTBzG3qCW8152/NtSw==",
- "dependencies": {
- "Microsoft.Extensions.Configuration.Abstractions": "6.0.0",
- "Microsoft.Extensions.Primitives": "6.0.0"
- }
- },
- "Microsoft.Extensions.Configuration.Abstractions": {
- "type": "Transitive",
- "resolved": "6.0.0",
- "contentHash": "qWzV9o+ZRWq+pGm+1dF+R7qTgTYoXvbyowRoBxQJGfqTpqDun2eteerjRQhq5PQ/14S+lqto3Ft4gYaRyl4rdQ==",
- "dependencies": {
- "Microsoft.Extensions.Primitives": "6.0.0"
- }
- },
- "Microsoft.Extensions.Configuration.Binder": {
- "type": "Transitive",
- "resolved": "6.0.0",
- "contentHash": "b3ErKzND8LIC7o08QAVlKfaEIYEvLJbtmVbFZVBRXeu9YkKfSSzLZfR1SUfQPBIy9mKLhEtJgGYImkcMNaKE0A==",
- "dependencies": {
- "Microsoft.Extensions.Configuration.Abstractions": "6.0.0"
- }
- },
- "Microsoft.Extensions.DependencyInjection": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "V8S3bsm50ig6JSyrbcJJ8bW2b9QLGouz+G1miK3UTaOWmMtFwNNNzUf4AleyDWUmTrWMLNnFSLEQtxmxgNQnNQ==",
- "dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0"
- }
- },
- "Microsoft.Extensions.DependencyInjection.Abstractions": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg=="
- },
- "Microsoft.Extensions.FileSystemGlobbing": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "OK+670i7esqlQrPjdIKRbsyMCe9g5kSLpRRQGSr4Q58AOYEe/hCnfLZprh7viNisSUUQZmMrbbuDaIrP+V1ebQ=="
- },
- "Microsoft.Extensions.Logging": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "tvRkov9tAJ3xP51LCv3FJ2zINmv1P8Hi8lhhtcKGqM+ImiTCC84uOPEI4z8Cdq2C3o9e+Aa0Gw0rmrsJD77W+w==",
- "dependencies": {
- "Microsoft.Extensions.DependencyInjection": "8.0.0",
- "Microsoft.Extensions.Logging.Abstractions": "8.0.0",
- "Microsoft.Extensions.Options": "8.0.0"
- }
- },
- "Microsoft.Extensions.Logging.Abstractions": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "arDBqTgFCyS0EvRV7O3MZturChstm50OJ0y9bDJvAcmEPJm0FFpFyjU/JLYyStNGGey081DvnQYlncNX5SJJGA==",
- "dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0"
- }
- },
- "Microsoft.Extensions.Options": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "JOVOfqpnqlVLUzINQ2fox8evY2SKLYJ3BV8QDe/Jyp21u1T7r45x/R/5QdteURMR5r01GxeJSBBUOCOyaNXA3g==",
- "dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "Microsoft.Extensions.Primitives": "8.0.0"
- }
- },
- "Microsoft.Extensions.Options.ConfigurationExtensions": {
- "type": "Transitive",
- "resolved": "6.0.0",
- "contentHash": "bXWINbTn0vC0FYc9GaQTISbxhQLAMrvtbuvD9N6JelEaIS/Pr62wUCinrq5bf1WRBGczt1v4wDhxFtVFNcMdUQ==",
- "dependencies": {
- "Microsoft.Extensions.Configuration.Abstractions": "6.0.0",
- "Microsoft.Extensions.Configuration.Binder": "6.0.0",
- "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
- "Microsoft.Extensions.Options": "6.0.0",
- "Microsoft.Extensions.Primitives": "6.0.0"
- }
- },
- "Microsoft.Extensions.Primitives": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==",
- "dependencies": {
- "System.Runtime.CompilerServices.Unsafe": "6.0.0"
- }
- },
- "Microsoft.NETCore.Platforms": {
- "type": "Transitive",
- "resolved": "5.0.0",
- "contentHash": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ=="
- },
- "Microsoft.NETCore.Targets": {
- "type": "Transitive",
- "resolved": "1.1.0",
- "contentHash": "aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg=="
- },
- "Microsoft.VisualStudio.Threading": {
- "type": "Transitive",
- "resolved": "17.6.40",
- "contentHash": "hLa/0xargG7p3bF7aeq2/lRYn/bVnfZXurUWVHx+MNqxxAUjIDMKi4OIOWbYQ/DTkbn9gv8TLvgso+6EtHVQQg==",
- "dependencies": {
- "Microsoft.Bcl.AsyncInterfaces": "7.0.0",
- "Microsoft.VisualStudio.Threading.Analyzers": "17.6.40",
- "Microsoft.VisualStudio.Validation": "17.0.71",
- "Microsoft.Win32.Registry": "5.0.0",
- "System.Threading.Tasks.Extensions": "4.5.4"
- }
- },
- "Microsoft.VisualStudio.Threading.Analyzers": {
- "type": "Transitive",
- "resolved": "17.6.40",
- "contentHash": "uU8vYr/Nx3ldEWcsbiHiyAX1G7od3eFK1+Aga6ZvgCvU+nQkcXYVkIMcSEkIDWkFaldx1dkoVvX3KRNQD0R7dw=="
- },
- "Microsoft.VisualStudio.Validation": {
- "type": "Transitive",
- "resolved": "17.6.11",
- "contentHash": "J+9L/iac6c8cwcgVSCMuoIYOlD1Jw4mbZ8XMe1IZVj8p8+3dJ46LnnkIkTRMjK7xs9UtU9MoUp1JGhWoN6fAEw=="
- },
- "Microsoft.Win32.Registry": {
- "type": "Transitive",
- "resolved": "5.0.0",
- "contentHash": "dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==",
- "dependencies": {
- "System.Security.AccessControl": "5.0.0",
- "System.Security.Principal.Windows": "5.0.0"
- }
- },
- "Nerdbank.Streams": {
- "type": "Transitive",
- "resolved": "2.10.69",
- "contentHash": "YIudzeVyQRJAqytjpo1jdHkh2t+vqQqyusBqb2sFSOAOGEnyOXhcHx/rQqSuCIXUDr50a3XuZnamGRfQVBOf4g==",
- "dependencies": {
- "Microsoft.Bcl.AsyncInterfaces": "7.0.0",
- "Microsoft.VisualStudio.Threading": "17.6.40",
- "Microsoft.VisualStudio.Validation": "17.6.11",
- "System.IO.Pipelines": "7.0.0",
- "System.Runtime.CompilerServices.Unsafe": "6.0.0"
- }
- },
- "Newtonsoft.Json": {
- "type": "Transitive",
- "resolved": "13.0.3",
- "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
- },
- "OmniSharp.Extensions.DebugAdapter": {
- "type": "Transitive",
- "resolved": "0.19.9",
- "contentHash": "Jy9RlVei7ay3LavvPH4F8BnIIMAo5th5EI8JnVe1RQlOxvu18H8hOyZ8fLFHtzbObs+oTONsJ9aynqeyMOErgA==",
- "dependencies": {
- "Microsoft.Extensions.Configuration": "6.0.1",
- "OmniSharp.Extensions.JsonRpc": "0.19.9",
- "OmniSharp.Extensions.JsonRpc.Generators": "0.19.9"
- }
- },
- "OmniSharp.Extensions.DebugAdapter.Server": {
- "type": "Transitive",
- "resolved": "0.19.9",
- "contentHash": "XRJ6EW44DaODkzjAuN1XbpnPFkciJIM2sIx4KpsvV/2Rle1CdRJY4gA6vJn+2uNh5hRr1d0SqZSieqV9Ly0utw==",
- "dependencies": {
- "OmniSharp.Extensions.DebugAdapter.Shared": "0.19.9"
- }
- },
- "OmniSharp.Extensions.DebugAdapter.Shared": {
- "type": "Transitive",
- "resolved": "0.19.9",
- "contentHash": "A4psuqk+slrs585cCkZkwUO08nW0I6SVH4u7B7d8wU9lH0LLRTvQBlo3QlxrVAMxjwljPFzXaaRHv7D7X1BXbw==",
- "dependencies": {
- "OmniSharp.Extensions.DebugAdapter": "0.19.9",
- "OmniSharp.Extensions.JsonRpc": "0.19.9"
- }
- },
- "OmniSharp.Extensions.JsonRpc": {
- "type": "Transitive",
- "resolved": "0.19.9",
- "contentHash": "utFvrx9OYXhCS5rnfWAVeedJCrucuDLAOrKXjohf/NOjG9FFVbcp+hLqj9Ng+AxoADRD+rSJYHfBOeqGl5zW0A==",
- "dependencies": {
- "MediatR": "8.1.0",
- "Microsoft.Extensions.DependencyInjection": "6.0.1",
- "Microsoft.Extensions.Logging": "6.0.0",
- "Nerdbank.Streams": "2.10.69",
- "Newtonsoft.Json": "13.0.3",
- "OmniSharp.Extensions.JsonRpc.Generators": "0.19.9",
- "System.Collections.Immutable": "5.0.0",
- "System.Reactive": "6.0.0",
- "System.Threading.Channels": "6.0.0"
- }
- },
- "OmniSharp.Extensions.JsonRpc.Generators": {
- "type": "Transitive",
- "resolved": "0.19.9",
- "contentHash": "hiWC0yGcKM+K00fgiL7KBmlvULmkKNhm40ZSzxqT+jNV21r+YZgKzEREhQe40ufb4tjcIxdYkif++IzGl/3H/Q=="
- },
- "OmniSharp.Extensions.LanguageProtocol": {
- "type": "Transitive",
- "resolved": "0.19.9",
- "contentHash": "d0crY6w5SyunGlERP27YeUeJnJfUjvJoALFlPMU4CHu3jovG1Y8RxLpihCPX8fKdjzgy7Ii+VjFYtIpDEEQqYQ==",
- "dependencies": {
- "Microsoft.Extensions.Configuration": "6.0.1",
- "Microsoft.Extensions.Configuration.Binder": "6.0.0",
- "Microsoft.Extensions.Options.ConfigurationExtensions": "6.0.0",
- "OmniSharp.Extensions.JsonRpc": "0.19.9",
- "OmniSharp.Extensions.JsonRpc.Generators": "0.19.9"
- }
- },
- "OmniSharp.Extensions.LanguageServer": {
- "type": "Transitive",
- "resolved": "0.19.9",
- "contentHash": "g09wOOCQ/oFqtZ47Q5R9E78tz2a5ODEB+V+S65wAiiRskR7xwL78Tse4/8ToBc8G/ZgQgqLtAOPo/BSPmHNlbw==",
- "dependencies": {
- "Microsoft.Extensions.Configuration": "6.0.1",
- "OmniSharp.Extensions.JsonRpc": "0.19.9",
- "OmniSharp.Extensions.LanguageProtocol": "0.19.9",
- "OmniSharp.Extensions.LanguageServer.Shared": "0.19.9"
- }
- },
- "OmniSharp.Extensions.LanguageServer.Shared": {
- "type": "Transitive",
- "resolved": "0.19.9",
- "contentHash": "+p+py79MrNG3QnqRrBp5J7Wc810HFFczMH8/WLIiUqih1bqmKPFY9l/uzBvq1Ko8+YO/8tzI7BDffHvaguISEw==",
- "dependencies": {
- "OmniSharp.Extensions.LanguageProtocol": "0.19.9"
- }
- },
- "runtime.native.System": {
- "type": "Transitive",
- "resolved": "4.3.0",
- "contentHash": "c/qWt2LieNZIj1jGnVNsE2Kl23Ya2aSTBuXMD6V7k9KWr6l16Tqdwq+hJScEpWER9753NWC8h96PaVNY5Ld7Jw==",
- "dependencies": {
- "Microsoft.NETCore.Platforms": "1.1.0",
- "Microsoft.NETCore.Targets": "1.1.0"
- }
- },
- "Serilog": {
- "type": "Transitive",
- "resolved": "3.1.1",
- "contentHash": "P6G4/4Kt9bT635bhuwdXlJ2SCqqn2nhh4gqFqQueCOr9bK/e7W9ll/IoX1Ter948cV2Z/5+5v8pAfJYUISY03A=="
- },
- "Serilog.Extensions.Logging": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "YEAMWu1UnWgf1c1KP85l1SgXGfiVo0Rz6x08pCiPOIBt2Qe18tcZLvdBUuV5o1QHvrs8FAry9wTIhgBRtjIlEg==",
- "dependencies": {
- "Microsoft.Extensions.Logging": "8.0.0",
- "Serilog": "3.1.1"
- }
- },
- "Serilog.Sinks.Async": {
- "type": "Transitive",
- "resolved": "1.5.0",
- "contentHash": "csHYIqAwI4Gy9oAhXYRwxGrQEAtBg3Ep7WaCzsnA1cZuBZjVAU0n7hWaJhItjO7hbLHh/9gRVxALCUB4Dv+gZw==",
- "dependencies": {
- "Serilog": "2.9.0"
- }
- },
- "Serilog.Sinks.File": {
- "type": "Transitive",
- "resolved": "5.0.0",
- "contentHash": "uwV5hdhWPwUH1szhO8PJpFiahqXmzPzJT/sOijH/kFgUx+cyoDTMM8MHD0adw9+Iem6itoibbUXHYslzXsLEAg==",
- "dependencies": {
- "Serilog": "2.10.0"
- }
- },
- "System.Collections.Immutable": {
- "type": "Transitive",
- "resolved": "5.0.0",
- "contentHash": "FXkLXiK0sVVewcso0imKQoOxjoPAj42R8HtjjbSjVPAzwDfzoyoznWxgA3c38LDbN9SJux1xXoXYAhz98j7r2g=="
- },
- "System.Globalization": {
- "type": "Transitive",
- "resolved": "4.3.0",
- "contentHash": "kYdVd2f2PAdFGblzFswE4hkNANJBKRmsfa2X5LG2AcWE1c7/4t0pYae1L8vfZ5xvE2nK/R9JprtToA61OSHWIg==",
- "dependencies": {
- "Microsoft.NETCore.Platforms": "1.1.0",
- "Microsoft.NETCore.Targets": "1.1.0",
- "System.Runtime": "4.3.0"
- }
- },
- "System.IO": {
- "type": "Transitive",
- "resolved": "4.3.0",
- "contentHash": "3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg==",
- "dependencies": {
- "Microsoft.NETCore.Platforms": "1.1.0",
- "Microsoft.NETCore.Targets": "1.1.0",
- "System.Runtime": "4.3.0",
- "System.Text.Encoding": "4.3.0",
- "System.Threading.Tasks": "4.3.0"
- }
- },
- "System.IO.Pipelines": {
- "type": "Transitive",
- "resolved": "7.0.0",
- "contentHash": "jRn6JYnNPW6xgQazROBLSfpdoczRw694vO5kKvMcNnpXuolEixUyw6IBuBs2Y2mlSX/LdLvyyWmfXhaI3ND1Yg=="
- },
- "System.Reactive": {
- "type": "Transitive",
- "resolved": "6.0.0",
- "contentHash": "31kfaW4ZupZzPsI5PVe77VhnvFF55qgma7KZr/E0iFTs6fmdhhG8j0mgEx620iLTey1EynOkEfnyTjtNEpJzGw=="
- },
- "System.Reflection": {
- "type": "Transitive",
- "resolved": "4.3.0",
- "contentHash": "KMiAFoW7MfJGa9nDFNcfu+FpEdiHpWgTcS2HdMpDvt9saK3y/G4GwprPyzqjFH9NTaGPQeWNHU+iDlDILj96aQ==",
- "dependencies": {
- "Microsoft.NETCore.Platforms": "1.1.0",
- "Microsoft.NETCore.Targets": "1.1.0",
- "System.IO": "4.3.0",
- "System.Reflection.Primitives": "4.3.0",
- "System.Runtime": "4.3.0"
- }
- },
- "System.Reflection.Extensions": {
- "type": "Transitive",
- "resolved": "4.3.0",
- "contentHash": "rJkrJD3kBI5B712aRu4DpSIiHRtr6QlfZSQsb0hYHrDCZORXCFjQfoipo2LaMUHoT9i1B7j7MnfaEKWDFmFQNQ==",
- "dependencies": {
- "Microsoft.NETCore.Platforms": "1.1.0",
- "Microsoft.NETCore.Targets": "1.1.0",
- "System.Reflection": "4.3.0",
- "System.Runtime": "4.3.0"
- }
- },
- "System.Reflection.Primitives": {
- "type": "Transitive",
- "resolved": "4.3.0",
- "contentHash": "5RXItQz5As4xN2/YUDxdpsEkMhvw3e6aNveFXUn4Hl/udNTCNhnKp8lT9fnc3MhvGKh1baak5CovpuQUXHAlIA==",
- "dependencies": {
- "Microsoft.NETCore.Platforms": "1.1.0",
- "Microsoft.NETCore.Targets": "1.1.0",
- "System.Runtime": "4.3.0"
- }
- },
- "System.Resources.ResourceManager": {
- "type": "Transitive",
- "resolved": "4.3.0",
- "contentHash": "/zrcPkkWdZmI4F92gL/TPumP98AVDu/Wxr3CSJGQQ+XN6wbRZcyfSKVoPo17ilb3iOr0cCRqJInGwNMolqhS8A==",
- "dependencies": {
- "Microsoft.NETCore.Platforms": "1.1.0",
- "Microsoft.NETCore.Targets": "1.1.0",
- "System.Globalization": "4.3.0",
- "System.Reflection": "4.3.0",
- "System.Runtime": "4.3.0"
- }
- },
- "System.Runtime": {
- "type": "Transitive",
- "resolved": "4.3.0",
- "contentHash": "JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==",
- "dependencies": {
- "Microsoft.NETCore.Platforms": "1.1.0",
- "Microsoft.NETCore.Targets": "1.1.0"
- }
- },
- "System.Runtime.CompilerServices.Unsafe": {
- "type": "Transitive",
- "resolved": "6.0.0",
- "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
- },
- "System.Runtime.Handles": {
- "type": "Transitive",
- "resolved": "4.3.0",
- "contentHash": "OKiSUN7DmTWeYb3l51A7EYaeNMnvxwE249YtZz7yooT4gOZhmTjIn48KgSsw2k2lYdLgTKNJw/ZIfSElwDRVgg==",
- "dependencies": {
- "Microsoft.NETCore.Platforms": "1.1.0",
- "Microsoft.NETCore.Targets": "1.1.0",
- "System.Runtime": "4.3.0"
- }
- },
- "System.Runtime.InteropServices": {
- "type": "Transitive",
- "resolved": "4.3.0",
- "contentHash": "uv1ynXqiMK8mp1GM3jDqPCFN66eJ5w5XNomaK2XD+TuCroNTLFGeZ+WCmBMcBDyTFKou3P6cR6J/QsaqDp7fGQ==",
- "dependencies": {
- "Microsoft.NETCore.Platforms": "1.1.0",
- "Microsoft.NETCore.Targets": "1.1.0",
- "System.Reflection": "4.3.0",
- "System.Reflection.Primitives": "4.3.0",
- "System.Runtime": "4.3.0",
- "System.Runtime.Handles": "4.3.0"
- }
- },
- "System.Security.AccessControl": {
- "type": "Transitive",
- "resolved": "5.0.0",
- "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==",
- "dependencies": {
- "Microsoft.NETCore.Platforms": "5.0.0",
- "System.Security.Principal.Windows": "5.0.0"
- }
- },
- "System.Security.Principal": {
- "type": "Transitive",
- "resolved": "4.3.0",
- "contentHash": "I1tkfQlAoMM2URscUtpcRo/hX0jinXx6a/KUtEQoz3owaYwl3qwsO8cbzYVVnjxrzxjHo3nJC+62uolgeGIS9A==",
- "dependencies": {
- "System.Runtime": "4.3.0"
- }
- },
- "System.Security.Principal.Windows": {
- "type": "Transitive",
- "resolved": "5.0.0",
- "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA=="
- },
- "System.Text.Encoding": {
- "type": "Transitive",
- "resolved": "4.3.0",
- "contentHash": "BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==",
- "dependencies": {
- "Microsoft.NETCore.Platforms": "1.1.0",
- "Microsoft.NETCore.Targets": "1.1.0",
- "System.Runtime": "4.3.0"
- }
- },
- "System.Threading": {
- "type": "Transitive",
- "resolved": "4.3.0",
- "contentHash": "VkUS0kOBcUf3Wwm0TSbrevDDZ6BlM+b/HRiapRFWjM5O0NS0LviG0glKmFK+hhPDd1XFeSdU1GmlLhb2CoVpIw==",
- "dependencies": {
- "System.Runtime": "4.3.0",
- "System.Threading.Tasks": "4.3.0"
- }
- },
- "System.Threading.Channels": {
- "type": "Transitive",
- "resolved": "6.0.0",
- "contentHash": "TY8/9+tI0mNaUMgntOxxaq2ndTkdXqLSxvPmas7XEqOlv9lQtB7wLjYGd756lOaO7Dvb5r/WXhluM+0Xe87v5Q=="
- },
- "System.Threading.Tasks": {
- "type": "Transitive",
- "resolved": "4.3.0",
- "contentHash": "LbSxKEdOUhVe8BezB/9uOGGppt+nZf6e1VFyw6v3DN6lqitm0OSn2uXMOdtP0M3W4iMcqcivm2J6UgqiwwnXiA==",
- "dependencies": {
- "Microsoft.NETCore.Platforms": "1.1.0",
- "Microsoft.NETCore.Targets": "1.1.0",
- "System.Runtime": "4.3.0"
- }
- },
- "System.Threading.Tasks.Extensions": {
- "type": "Transitive",
- "resolved": "4.5.4",
- "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg=="
- },
- "Microsoft.PowerShell.EditorServices": {
- "type": "Project",
- "dependencies": {
- "Microsoft.CSharp": "[4.7.0, )",
- "Microsoft.Extensions.FileSystemGlobbing": "[8.0.0, )",
- "Microsoft.Extensions.Logging": "[8.0.0, )",
- "OmniSharp.Extensions.DebugAdapter.Server": "[0.19.9, )",
- "OmniSharp.Extensions.LanguageServer": "[0.19.9, )",
- "PowerShellStandard.Library": "[5.1.1, )",
- "Serilog": "[3.1.1, )",
- "Serilog.Extensions.Logging": "[8.0.0, )",
- "Serilog.Sinks.Async": "[1.5.0, )",
- "Serilog.Sinks.File": "[5.0.0, )",
- "System.IO.Pipes.AccessControl": "[5.0.0, )",
- "System.Security.Principal": "[4.3.0, )",
- "System.Security.Principal.Windows": "[5.0.0, )"
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/PowerShellEditorServices/Extensions/EditorContext.cs b/src/PowerShellEditorServices/Extensions/EditorContext.cs
index f2ab42e8c..e79eb8c3b 100644
--- a/src/PowerShellEditorServices/Extensions/EditorContext.cs
+++ b/src/PowerShellEditorServices/Extensions/EditorContext.cs
@@ -92,9 +92,8 @@ public void SetSelection(
/// Sets a selection in the host editor's active buffer.
///
/// The range of the selection.
- #pragma warning disable VSTHRD002
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "Supporting synchronous API.")]
public void SetSelection(FileRange selectionRange) => editorOperations.SetSelectionAsync(selectionRange.ToBufferRange()).Wait();
- #pragma warning restore VSTHRD002
#endregion
}
diff --git a/src/PowerShellEditorServices/Extensions/EditorObject.cs b/src/PowerShellEditorServices/Extensions/EditorObject.cs
index 17006baf2..a43ab2995 100644
--- a/src/PowerShellEditorServices/Extensions/EditorObject.cs
+++ b/src/PowerShellEditorServices/Extensions/EditorObject.cs
@@ -115,13 +115,12 @@ internal EditorObject(
/// at the time this method is invoked.
///
/// A instance of the EditorContext class.
- #pragma warning disable VSTHRD002, VSTHRD104
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "Supporting synchronous API.")]
public EditorContext GetEditorContext() => _editorOperations.GetEditorContextAsync().Result;
- #pragma warning restore VSTHRD002, VSTHRD104
internal void SetAsStaticInstance()
{
- EditorObject.Instance = this;
+ Instance = this;
s_editorObjectReady.TrySetResult(true);
}
}
diff --git a/src/PowerShellEditorServices/Extensions/EditorWindow.cs b/src/PowerShellEditorServices/Extensions/EditorWindow.cs
index 8c9048c3c..6d9d4c3ff 100644
--- a/src/PowerShellEditorServices/Extensions/EditorWindow.cs
+++ b/src/PowerShellEditorServices/Extensions/EditorWindow.cs
@@ -43,24 +43,28 @@ internal EditorWindow(IEditorOperations editorOperations)
/// Shows an informational message to the user.
///
/// The message to be shown.
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "Supporting synchronous API.")]
public void ShowInformationMessage(string message) => editorOperations.ShowInformationMessageAsync(message).Wait();
///
/// Shows an error message to the user.
///
/// The message to be shown.
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "Supporting synchronous API.")]
public void ShowErrorMessage(string message) => editorOperations.ShowErrorMessageAsync(message).Wait();
///
/// Shows a warning message to the user.
///
/// The message to be shown.
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "Supporting synchronous API.")]
public void ShowWarningMessage(string message) => editorOperations.ShowWarningMessageAsync(message).Wait();
///
/// Sets the status bar message in the editor UI (if applicable).
///
/// The message to be shown.
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "Supporting synchronous API.")]
public void SetStatusBarMessage(string message) => editorOperations.SetStatusBarMessageAsync(message, null).Wait();
///
@@ -68,6 +72,7 @@ internal EditorWindow(IEditorOperations editorOperations)
///
/// The message to be shown.
/// A timeout in milliseconds for how long the message should remain visible.
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "Supporting synchronous API.")]
public void SetStatusBarMessage(string message, int timeout) => editorOperations.SetStatusBarMessageAsync(message, timeout).Wait();
#endregion
diff --git a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
index b01c6eca7..f3c40d74a 100644
--- a/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
+++ b/src/PowerShellEditorServices/Extensions/EditorWorkspace.cs
@@ -28,6 +28,11 @@ public sealed class EditorWorkspace
///
public string[] Paths => editorOperations.GetWorkspacePaths();
+ ///
+ /// Get all currently open documents in the workspace.
+ ///
+ public WorkspaceOpenDocument[] Documents => editorOperations.GetWorkspaceOpenDocuments();
+
#endregion
#region Constructors
@@ -42,12 +47,14 @@ public sealed class EditorWorkspace
///
/// Creates a new file in the editor.
///
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "Supporting synchronous API.")]
public void NewFile() => editorOperations.NewFileAsync(string.Empty).Wait();
///
/// Creates a new file in the editor.
///
/// The content to place in the new file.
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "Supporting synchronous API.")]
public void NewFile(string content) => editorOperations.NewFileAsync(content).Wait();
///
@@ -55,6 +62,7 @@ public sealed class EditorWorkspace
/// its buffer will be made active.
///
/// The path to the file to be opened.
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "Supporting synchronous API.")]
public void OpenFile(string filePath) => editorOperations.OpenFileAsync(filePath).Wait();
///
@@ -64,25 +72,31 @@ public sealed class EditorWorkspace
///
/// The path to the file to be opened.
/// Determines wether the file is opened as a preview or as a durable editor.
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "Supporting synchronous API.")]
public void OpenFile(string filePath, bool preview) => editorOperations.OpenFileAsync(filePath, preview).Wait();
///
/// Closes a file in the workspace.
///
/// The path to the file to be closed.
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "Supporting synchronous API.")]
public void CloseFile(string filePath) => editorOperations.CloseFileAsync(filePath).Wait();
+ public void CloseFile(WorkspaceOpenDocument document) => CloseFile(document.Path);
///
/// Saves an open file in the workspace.
///
/// The path to the file to be saved.
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "Supporting synchronous API.")]
public void SaveFile(string filePath) => editorOperations.SaveFileAsync(filePath).Wait();
+ public void SaveFile(WorkspaceOpenDocument document) => SaveFile(document.Path);
///
/// Saves a file with a new name AKA a copy.
///
/// The file to copy.
/// The file to create.
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "Supporting synchronous API.")]
public void SaveFile(string oldFilePath, string newFilePath) => editorOperations.SaveFileAsync(oldFilePath, newFilePath).Wait();
#endregion
diff --git a/src/PowerShellEditorServices/Extensions/FileContext.cs b/src/PowerShellEditorServices/Extensions/FileContext.cs
index c8c32e58e..39a4a275e 100644
--- a/src/PowerShellEditorServices/Extensions/FileContext.cs
+++ b/src/PowerShellEditorServices/Extensions/FileContext.cs
@@ -208,14 +208,13 @@ public void InsertText(
///
/// The text string to insert.
/// The buffer range which will be replaced by the string.
- #pragma warning disable VSTHRD002
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "Supporting synchronous API.")]
public void InsertText(string textToInsert, IFileRange insertRange)
{
editorOperations
.InsertTextAsync(scriptFile.DocumentUri.ToString(), textToInsert, insertRange.ToBufferRange())
.Wait();
}
- #pragma warning restore VSTHRD002
#endregion
@@ -224,6 +223,7 @@ public void InsertText(string textToInsert, IFileRange insertRange)
///
/// Saves this file.
///
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD110:Observe result of async calls", Justification = "Supporting synchronous API.")]
public void Save() => editorOperations.SaveFileAsync(scriptFile.FilePath);
///
@@ -233,7 +233,7 @@ public void InsertText(string textToInsert, IFileRange insertRange)
/// the path where the file should be saved,
/// including the file name with extension as the leaf
///
- #pragma warning disable VSTHRD002
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "Supporting synchronous API.")]
public void SaveAs(string newFilePath)
{
// Do some validation here so that we can provide a helpful error if the path won't work
@@ -248,7 +248,6 @@ public void SaveAs(string newFilePath)
editorOperations.SaveFileAsync(scriptFile.FilePath, newFilePath).Wait();
}
- #pragma warning restore VSTHRD002
#endregion
}
diff --git a/src/PowerShellEditorServices/Extensions/IEditorOperations.cs b/src/PowerShellEditorServices/Extensions/IEditorOperations.cs
index 3ec33ebc6..7fb39b22c 100644
--- a/src/PowerShellEditorServices/Extensions/IEditorOperations.cs
+++ b/src/PowerShellEditorServices/Extensions/IEditorOperations.cs
@@ -3,9 +3,34 @@
using System.Threading.Tasks;
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
+#nullable enable
namespace Microsoft.PowerShell.EditorServices.Extensions
{
+ public readonly struct WorkspaceOpenDocument(string path, bool saved)
+ {
+ ///
+ /// Gets the path or URI of the open document.
+ ///
+ public string Path { get; } = path;
+
+ ///
+ /// Gets whether the document is backed by a saved file path (not in-memory).
+ ///
+ public bool Saved { get; } = saved;
+
+ ///
+ /// Gets the display name of this document and unsaved status.
+ ///
+ /// The display name of this document.
+ public override string ToString()
+ {
+ string documentPath = Path ?? string.Empty;
+ string fileName = System.IO.Path.GetFileName(documentPath);
+ return Saved ? fileName : fileName + " [Unsaved]";
+ }
+ }
+
///
/// Provides an interface that must be implemented by an editor
/// host to perform operations invoked by extensions written in
@@ -32,6 +57,12 @@ internal interface IEditorOperations
///
string[] GetWorkspacePaths();
+ ///
+ /// Get all open documents in the current workspace session.
+ ///
+ /// All currently open documents.
+ WorkspaceOpenDocument[] GetWorkspaceOpenDocuments();
+
///
/// Resolves the given file path relative to the current workspace path.
///
diff --git a/src/PowerShellEditorServices/GlobalSuppressions.cs b/src/PowerShellEditorServices/GlobalSuppressions.cs
deleted file mode 100644
index 3c0be1568..000000000
--- a/src/PowerShellEditorServices/GlobalSuppressions.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-// This file is used by Code Analysis to maintain SuppressMessage
-// attributes that are applied to this project.
-// Project-level suppressions either have no target or are given
-// a specific target and scoped to a namespace, type, member, etc.
-
-[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1303:Do not pass literals as localized parameters", Justification = "PSES is not localized", Scope = "module")]
diff --git a/src/PowerShellEditorServices/Hosting/EditorServicesServerFactory.cs b/src/PowerShellEditorServices/Hosting/EditorServicesServerFactory.cs
index a9bbab38e..b981ea450 100644
--- a/src/PowerShellEditorServices/Hosting/EditorServicesServerFactory.cs
+++ b/src/PowerShellEditorServices/Hosting/EditorServicesServerFactory.cs
@@ -2,81 +2,30 @@
// Licensed under the MIT License.
using System;
-using System.Diagnostics;
using System.IO;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
-using Microsoft.PowerShell.EditorServices.Logging;
using Microsoft.PowerShell.EditorServices.Server;
-using Serilog;
-using Serilog.Events;
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
using Microsoft.PowerShell.EditorServices.Services.Extension;
-#if DEBUG
-using Serilog.Debugging;
-#endif
+// The HostLogger type isn't directly referenced from this assembly, however it uses a common IObservable interface and this alias helps make it more clear the purpose. We can use Microsoft.Extensions.Logging from this point because the ALC should be loaded, but we need to only expose the IObservable to the Hosting assembly so it doesn't try to load MEL before the ALC is ready.
+using HostLogger = System.IObservable<(int logLevel, string message)>;
namespace Microsoft.PowerShell.EditorServices.Hosting
{
///
- /// Factory class for hiding dependencies of Editor Services.
+ /// Factory for creating the LSP server and debug server instances.
///
- ///
- /// Dependency injection and logging are wrapped by factory methods on this class so that the
- /// host assembly can construct the LSP and debug servers without directly depending on and .
- ///
internal sealed class EditorServicesServerFactory : IDisposable
{
+ private readonly HostLogger _hostLogger;
+
///
- /// Create a new Editor Services factory. This method will instantiate logging.
+ /// Creates a loggerfactory for this instance
///
- ///
- ///
- /// This can only be called once because it sets global state (the logger) and that call is
- /// in .
- ///
- ///
- /// TODO: Why is this a static function wrapping a constructor instead of just a
- /// constructor? In the end it returns an instance (albeit a "singleton").
- ///
- ///
- /// The path of the log file to use.
- /// The minimum log level to use.
- /// The host logger?
- public static EditorServicesServerFactory Create(string logDirectoryPath, int minimumLogLevel, IObservable<(int logLevel, string message)> hostLogger)
- {
- // NOTE: Ignore the suggestion to use Environment.ProcessId as it doesn't work for
- // .NET 4.6.2 (for Windows PowerShell), and this won't be caught in CI.
- int currentPID = Process.GetCurrentProcess().Id;
- string logPath = Path.Combine(logDirectoryPath, $"PowerShellEditorServices-{currentPID}.log");
- Log.Logger = new LoggerConfiguration()
- .Enrich.FromLogContext()
- .WriteTo.Async(config => config.File(logPath))
- .MinimumLevel.Is((LogEventLevel)minimumLogLevel)
- .CreateLogger();
-
-#if DEBUG
- SelfLog.Enable(msg => Debug.WriteLine(msg));
-#endif
-
- LoggerFactory loggerFactory = new();
- loggerFactory.AddSerilog();
-
- // Hook up logging from the host so that its recorded in the log file
- hostLogger.Subscribe(new HostLoggerAdapter(loggerFactory));
-
- return new EditorServicesServerFactory(loggerFactory);
- }
-
- // TODO: Can we somehow refactor this member so the language and debug servers can be
- // instantiated using their constructors instead of tying them to this factory with `Create`
- // methods?
- private readonly ILoggerFactory _loggerFactory;
-
- private EditorServicesServerFactory(ILoggerFactory loggerFactory) => _loggerFactory = loggerFactory;
+ /// The hostLogger that will be provided to the language services for logging handoff
+ internal EditorServicesServerFactory(HostLogger hostLogger) => _hostLogger = hostLogger;
///
/// Create the LSP server.
@@ -92,7 +41,7 @@ public static EditorServicesServerFactory Create(string logDirectoryPath, int mi
public PsesLanguageServer CreateLanguageServer(
Stream inputStream,
Stream outputStream,
- HostStartupInfo hostStartupInfo) => new(_loggerFactory, inputStream, outputStream, hostStartupInfo);
+ HostStartupInfo hostStartupInfo) => new(_hostLogger, inputStream, outputStream, hostStartupInfo);
///
/// Create the debug server given a language server instance.
@@ -110,7 +59,7 @@ public PsesDebugServer CreateDebugServerWithLanguageServer(
PsesLanguageServer languageServer)
{
return new PsesDebugServer(
- _loggerFactory,
+ _hostLogger,
inputStream,
outputStream,
languageServer.LanguageServer.Services);
@@ -132,7 +81,7 @@ public PsesDebugServer RecreateDebugServer(
PsesDebugServer debugServer)
{
return new PsesDebugServer(
- _loggerFactory,
+ _hostLogger,
inputStream,
outputStream,
debugServer.ServiceProvider);
@@ -153,7 +102,6 @@ public PsesDebugServer CreateDebugServerForTempSession(
ServiceProvider serviceProvider = new ServiceCollection()
.AddLogging(builder => builder
.ClearProviders()
- .AddSerilog()
.SetMinimumLevel(LogLevel.Trace)) // TODO: Why randomly set to trace?
.AddSingleton(_ => null)
// TODO: Why add these for a debug server?!
@@ -171,25 +119,14 @@ public PsesDebugServer CreateDebugServerForTempSession(
serviceProvider.GetService();
return new PsesDebugServer(
- _loggerFactory,
+ _hostLogger,
inputStream,
outputStream,
serviceProvider,
isTemp: true);
}
- ///
- /// TODO: This class probably should not be as the primary
- /// intention of that interface is to provide cleanup of unmanaged resources, which the
- /// logger certainly is not. Nor is this class used with a . Instead,
- /// this class should call in a finalizer. This
- /// could potentially even be done with by passing dispose=true.
- ///
- public void Dispose()
- {
- Log.CloseAndFlush();
- _loggerFactory.Dispose();
- }
+ // TODO: Clean up host logger? Shouldn't matter since we start a new process after shutdown.
+ public void Dispose() { }
}
}
diff --git a/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs b/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs
index 964509626..3f82990cd 100644
--- a/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs
+++ b/src/PowerShellEditorServices/Hosting/HostStartupInfo.cs
@@ -1,5 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
+#nullable enable
using System;
using System.Collections.Generic;
@@ -107,9 +108,8 @@ public sealed class HostStartupInfo
/// The minimum log level of log events to be logged.
///
///
- /// This is cast to all of , , and , hence it is an int.
+ /// This primitive maps to and
///
public int LogLevel { get; }
@@ -191,32 +191,13 @@ public HostStartupInfo(
}
///
- /// This is a strange class that is generally null or otherwise just has a single path
- /// set. It is eventually parsed one-by-one when setting up the PowerShell runspace.
+ /// Stores profile information passed from Start-EditorServices to be used for loading profiles if configured
+ /// and for the $PROFILE variable in the initial session state.
///
- ///
- /// TODO: Simplify this as a .
- ///
- public sealed class ProfilePathInfo
- {
- public ProfilePathInfo(
- string currentUserAllHosts,
- string currentUserCurrentHost,
- string allUsersAllHosts,
- string allUsersCurrentHost)
- {
- CurrentUserAllHosts = currentUserAllHosts;
- CurrentUserCurrentHost = currentUserCurrentHost;
- AllUsersAllHosts = allUsersAllHosts;
- AllUsersCurrentHost = allUsersCurrentHost;
- }
-
- public string CurrentUserAllHosts { get; }
-
- public string CurrentUserCurrentHost { get; }
-
- public string AllUsersAllHosts { get; }
-
- public string AllUsersCurrentHost { get; }
- }
+ public readonly record struct ProfilePathInfo(
+ string CurrentUserAllHosts,
+ string CurrentUserCurrentHost,
+ string AllUsersAllHosts,
+ string AllUsersCurrentHost
+ );
}
diff --git a/src/PowerShellEditorServices/IsExternalInit.cs b/src/PowerShellEditorServices/IsExternalInit.cs
index c2a9d8275..c690a1820 100644
--- a/src/PowerShellEditorServices/IsExternalInit.cs
+++ b/src/PowerShellEditorServices/IsExternalInit.cs
@@ -1,4 +1,6 @@
-#pragma warning disable IDE0073
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
#if NET5_0_OR_GREATER
[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.IsExternalInit))]
#else
diff --git a/src/PowerShellEditorServices/Logging/HostLoggerAdapter.cs b/src/PowerShellEditorServices/Logging/HostLoggerAdapter.cs
index 3290b2b78..9ffe3c950 100644
--- a/src/PowerShellEditorServices/Logging/HostLoggerAdapter.cs
+++ b/src/PowerShellEditorServices/Logging/HostLoggerAdapter.cs
@@ -9,23 +9,18 @@ namespace Microsoft.PowerShell.EditorServices.Logging
///
/// Adapter class to allow logging events sent by the host to be recorded by PSES' logging infrastructure.
///
- internal class HostLoggerAdapter : IObserver<(int logLevel, string message)>
+ internal class HostLoggerAdapter(ILogger logger) : IObserver<(int logLevel, string message)>
{
- private readonly ILogger _logger;
+ public void OnError(Exception error) => logger.LogError(error, "Error in host logger");
///
- /// Create a new host logger adapter.
+ /// Log the message received from the host into MEL.
///
- /// Factory to create logger instances with.
- public HostLoggerAdapter(ILoggerFactory loggerFactory) => _logger = loggerFactory.CreateLogger("HostLogs");
+ public void OnNext((int logLevel, string message) value) => logger.Log((LogLevel)value.logLevel, value.message);
public void OnCompleted()
{
// Nothing to do; we simply don't send more log messages
}
-
- public void OnError(Exception error) => _logger.LogError(error, "Error in host logger");
-
- public void OnNext((int logLevel, string message) value) => _logger.Log((LogLevel)value.logLevel, value.message);
}
}
diff --git a/src/PowerShellEditorServices/Logging/LanguageServerLogger.cs b/src/PowerShellEditorServices/Logging/LanguageServerLogger.cs
new file mode 100644
index 000000000..5d368f912
--- /dev/null
+++ b/src/PowerShellEditorServices/Logging/LanguageServerLogger.cs
@@ -0,0 +1,184 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#nullable enable
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reactive.Disposables;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using Newtonsoft.Json;
+using OmniSharp.Extensions.LanguageServer.Protocol.Models;
+using OmniSharp.Extensions.LanguageServer.Protocol.Server;
+using OmniSharp.Extensions.LanguageServer.Protocol.Window;
+
+namespace Microsoft.PowerShell.EditorServices.Logging;
+
+internal class LanguageServerLogger(ILanguageServerFacade responseRouter, string categoryName) : ILogger
+{
+ public IDisposable? BeginScope(TState state) where TState : notnull => Disposable.Empty;
+ public bool IsEnabled(LogLevel logLevel) => true;
+
+ public void Log(
+ LogLevel logLevel, EventId eventId, TState state, Exception? exception,
+ Func formatter
+ )
+ {
+ if (responseRouter is null)
+ {
+ throw new InvalidOperationException("Log received without a valid responseRouter dependency. This is a bug, please report it.");
+ }
+ // Any Omnisharp or trace logs are directly LSP protocol related and we send them to the trace channel
+ // TODO: Dynamically adjust if SetTrace is reported
+ // BUG: There is an omnisharp filter incorrectly filtering this. As a workaround we will use logMessage for now.
+ // https://github.com/OmniSharp/csharp-language-server-protocol/issues/1390
+ //
+ // {
+ // // Everything with omnisharp goes directly to trace
+ // string eventMessage = string.Empty;
+ // string exceptionName = exception?.GetType().Name ?? string.Empty;
+ // if (eventId.Name is not null)
+ // {
+ // eventMessage = eventId.Id == 0 ? eventId.Name : $"{eventId.Name} [{eventId.Id}] ";
+ // }
+
+ // LogTraceParams trace = new()
+ // {
+ // Message = categoryName + ": " + eventMessage + exceptionName,
+ // Verbose = formatter(state, exception)
+ // };
+ // responseRouter.Client.LogTrace(trace);
+ // }
+
+ // Drop all omnisharp messages to trace. This isn't a MEL filter because it's specific only to this provider.
+ if (categoryName.StartsWith("OmniSharp.", StringComparison.OrdinalIgnoreCase))
+ {
+ logLevel = LogLevel.Trace;
+ }
+
+ (MessageType messageType, string messagePrepend) = GetMessageInfo(logLevel);
+
+ // The vscode-languageserver-node client doesn't support LogOutputChannel as of 2024-11-24 and also doesn't
+ // provide a way to middleware the incoming log messages, so our output channel has no idea what the logLevel
+ // is. As a workaround, we send the severity in-line with the message for the client to parse.
+ // BUG: https://github.com/microsoft/vscode-languageserver-node/issues/1116
+ if (responseRouter.Client?.ClientSettings?.ClientInfo?.Name == "Visual Studio Code")
+ {
+ messagePrepend = logLevel switch
+ {
+ LogLevel.Critical => "CRITICAL: ",
+ LogLevel.Error => "",
+ LogLevel.Warning => "",
+ LogLevel.Information => "",
+ LogLevel.Debug => "",
+ LogLevel.Trace => "",
+ _ => string.Empty
+ };
+
+ // The vscode formatter prepends some extra stuff to Info specifically, so we drop Info to Log, but it will get logged correctly on the other side thanks to our inline indicator that our custom parser on the other side will pick up and process.
+ if (messageType == MessageType.Info)
+ {
+ messageType = MessageType.Log;
+ }
+ }
+
+ LogMessageParams logMessage = new()
+ {
+ Type = messageType,
+ Message = messagePrepend + categoryName + ": " + formatter(state, exception) +
+ (exception != null ? " - " + exception : "") + " | " +
+ //Hopefully this isn't too expensive in the long run
+ FormatState(state, exception)
+ };
+ responseRouter.Window.Log(logMessage);
+ }
+
+ ///
+ /// Formats the state object into a string for logging.
+ ///
+ ///
+ /// This is copied from Omnisharp, we can probably do better.
+ ///
+ ///
+ ///
+ ///
+ ///
+ private static string FormatState(TState state, Exception? exception)
+ {
+ return state switch
+ {
+ IEnumerable> dict => string.Join(" ", dict.Where(z => z.Key != "{OriginalFormat}").Select(z => $"{z.Key}='{z.Value}'")),
+ _ => JsonConvert.SerializeObject(state).Replace("\"", "'")
+ };
+ }
+
+ ///
+ /// Maps MEL log levels to LSP message types
+ ///
+ private static (MessageType messageType, string messagePrepend) GetMessageInfo(LogLevel logLevel)
+ => logLevel switch
+ {
+ LogLevel.Critical => (MessageType.Error, "Critical: "),
+ LogLevel.Error => (MessageType.Error, string.Empty),
+ LogLevel.Warning => (MessageType.Warning, string.Empty),
+ LogLevel.Information => (MessageType.Info, string.Empty),
+ LogLevel.Debug => (MessageType.Log, string.Empty),
+ LogLevel.Trace => (MessageType.Log, "Trace: "),
+ _ => throw new ArgumentOutOfRangeException(nameof(logLevel), logLevel, null)
+ };
+}
+
+internal class LanguageServerLoggerProvider(ILanguageServerFacade languageServer) : ILoggerProvider
+{
+ public ILogger CreateLogger(string categoryName) => new LanguageServerLogger(languageServer, categoryName);
+
+ public void Dispose() { }
+}
+
+public static class LanguageServerLoggerExtensions
+{
+ ///
+ /// Adds a custom logger provider for PSES LSP, that provides more granular categorization than the default Omnisharp logger, such as separating Omnisharp and PSES messages to different channels.
+ ///
+ public static ILoggingBuilder AddPsesLanguageServerLogging(this ILoggingBuilder builder)
+ {
+ builder.Services.AddSingleton();
+ return builder;
+ }
+
+ public static ILoggingBuilder AddLspClientConfigurableMinimumLevel(
+ this ILoggingBuilder builder,
+ LogLevel initialLevel = LogLevel.Trace
+ )
+ {
+ builder.Services.AddOptions();
+ builder.Services.AddSingleton(sp =>
+ {
+ IOptionsMonitor optionsMonitor = sp.GetRequiredService>();
+ return new(initialLevel, optionsMonitor);
+ });
+ builder.Services.AddSingleton>(sp =>
+ sp.GetRequiredService());
+
+ return builder;
+ }
+}
+
+internal class DynamicLogLevelOptions(
+ LogLevel initialLevel,
+ IOptionsMonitor optionsMonitor) : IConfigureOptions
+{
+ private LogLevel _currentLevel = initialLevel;
+ private readonly IOptionsMonitor _optionsMonitor = optionsMonitor;
+
+ public void Configure(LoggerFilterOptions options) => options.MinLevel = _currentLevel;
+
+ public void SetLogLevel(LogLevel level)
+ {
+ _currentLevel = level;
+ // Trigger reload of options to apply new log level
+ _optionsMonitor.CurrentValue.MinLevel = level;
+ }
+}
diff --git a/src/PowerShellEditorServices/PowerShellEditorServices.csproj b/src/PowerShellEditorServices/PowerShellEditorServices.csproj
index 8581053ff..18948aabc 100644
--- a/src/PowerShellEditorServices/PowerShellEditorServices.csproj
+++ b/src/PowerShellEditorServices/PowerShellEditorServices.csproj
@@ -1,5 +1,6 @@
-
+
PowerShell Editor Services
@@ -32,17 +33,19 @@
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -54,16 +57,9 @@
-
-
+
+
-
-
-
-
-
-
-
diff --git a/src/PowerShellEditorServices/Server/PsesDebugServer.cs b/src/PowerShellEditorServices/Server/PsesDebugServer.cs
index 6aca82e04..9f48a0f2d 100644
--- a/src/PowerShellEditorServices/Server/PsesDebugServer.cs
+++ b/src/PowerShellEditorServices/Server/PsesDebugServer.cs
@@ -5,13 +5,15 @@
using System.IO;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Logging;
using Microsoft.PowerShell.EditorServices.Handlers;
using Microsoft.PowerShell.EditorServices.Services;
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Host;
using OmniSharp.Extensions.DebugAdapter.Server;
using OmniSharp.Extensions.LanguageServer.Server;
+// See EditorServicesServerFactory.cs for the explanation of this alias.
+using HostLogger = System.IObservable<(int logLevel, string message)>;
+
namespace Microsoft.PowerShell.EditorServices.Server
{
///
@@ -26,16 +28,17 @@ internal class PsesDebugServer : IDisposable
private PsesInternalHost _psesHost;
private bool _startedPses;
private readonly bool _isTemp;
- protected readonly ILoggerFactory _loggerFactory;
+ // FIXME: This was never actually used in the debug server. Since we never have a debug server without an LSP, we could probably remove this and either reuse the MEL from the LSP, or create a new one here. It is probably best to only use this for exceptions that we can't reasonably send via the DAP protocol, which should only be anything before the initialize request.
+ protected readonly HostLogger _hostLogger;
public PsesDebugServer(
- ILoggerFactory factory,
+ HostLogger hostLogger,
Stream inputStream,
Stream outputStream,
IServiceProvider serviceProvider,
bool isTemp = false)
{
- _loggerFactory = factory;
+ _hostLogger = hostLogger;
_inputStream = inputStream;
_outputStream = outputStream;
ServiceProvider = serviceProvider;
@@ -63,7 +66,6 @@ public async Task StartAsync()
.WithOutput(_outputStream)
.WithServices(serviceCollection =>
serviceCollection
- .AddLogging()
.AddOptions()
.AddPsesDebugServices(ServiceProvider, this))
// TODO: Consider replacing all WithHandler with AddSingleton
@@ -115,9 +117,11 @@ public async Task StartAsync()
response.SupportsHitConditionalBreakpoints = true;
response.SupportsLogPoints = true;
response.SupportsSetVariable = true;
+ response.SupportsDelayedStackTraceLoading = true;
return Task.CompletedTask;
- });
+ })
+ ;
}).ConfigureAwait(false);
}
@@ -130,7 +134,6 @@ public void Dispose()
_debugAdapterServer?.Dispose();
_inputStream.Dispose();
_outputStream.Dispose();
- _loggerFactory.Dispose();
_serverStopped.SetResult(true);
// TODO: If the debugger has stopped, should we clear the breakpoints?
}
diff --git a/src/PowerShellEditorServices/Server/PsesLanguageServer.cs b/src/PowerShellEditorServices/Server/PsesLanguageServer.cs
index 74319e828..042e4e8fa 100644
--- a/src/PowerShellEditorServices/Server/PsesLanguageServer.cs
+++ b/src/PowerShellEditorServices/Server/PsesLanguageServer.cs
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
+using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
@@ -8,15 +9,18 @@
using Microsoft.Extensions.Logging;
using Microsoft.PowerShell.EditorServices.Handlers;
using Microsoft.PowerShell.EditorServices.Hosting;
+using Microsoft.PowerShell.EditorServices.Logging;
using Microsoft.PowerShell.EditorServices.Services;
using Microsoft.PowerShell.EditorServices.Services.Extension;
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Host;
-using Microsoft.PowerShell.EditorServices.Services.Template;
using Newtonsoft.Json.Linq;
using OmniSharp.Extensions.JsonRpc;
+using OmniSharp.Extensions.LanguageServer.Protocol.General;
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
using OmniSharp.Extensions.LanguageServer.Server;
-using Serilog;
+
+// See EditorServicesServerFactory.cs for the explanation of this alias.
+using HostLogger = System.IObservable<(int logLevel, string message)>;
namespace Microsoft.PowerShell.EditorServices.Server
{
@@ -25,7 +29,7 @@ namespace Microsoft.PowerShell.EditorServices.Server
///
internal class PsesLanguageServer
{
- internal ILoggerFactory LoggerFactory { get; }
+ internal HostLogger HostLogger { get; }
internal ILanguageServer LanguageServer { get; private set; }
private readonly LogLevel _minimumLogLevel;
private readonly Stream _inputStream;
@@ -33,6 +37,7 @@ internal class PsesLanguageServer
private readonly HostStartupInfo _hostDetails;
private readonly TaskCompletionSource _serverStart;
private PsesInternalHost _psesHost;
+ private IDisposable hostLoggerSubscription;
///
/// Create a new language server instance.
@@ -42,18 +47,18 @@ internal class PsesLanguageServer
/// cref="EditorServicesServerFactory.CreateLanguageServer"/>. It is essentially a
/// singleton. The factory hides the logger.
///
- /// Factory to create loggers with.
+ /// The host logger to hand off for monitoring.
/// Protocol transport input stream.
/// Protocol transport output stream.
/// Host configuration to instantiate the server and services
/// with.
public PsesLanguageServer(
- ILoggerFactory factory,
+ HostLogger hostLogger,
Stream inputStream,
Stream outputStream,
HostStartupInfo hostStartupInfo)
{
- LoggerFactory = factory;
+ HostLogger = hostLogger;
_minimumLogLevel = (LogLevel)hostStartupInfo.LogLevel;
_inputStream = inputStream;
_outputStream = outputStream;
@@ -70,9 +75,7 @@ public PsesLanguageServer(
/// cref="PsesServiceCollectionExtensions.AddPsesLanguageServices"/>.
///
/// A task that completes when the server is ready and listening.
-#pragma warning disable CA1506 // Coupling complexity we don't care about
public async Task StartAsync()
-#pragma warning restore CA1506
{
LanguageServer = await OmniSharp.Extensions.LanguageServer.Server.LanguageServer.From(options =>
{
@@ -85,10 +88,11 @@ public async Task StartAsync()
serviceCollection.AddPsesLanguageServices(_hostDetails);
})
.ConfigureLogging(builder => builder
- .AddSerilog(Log.Logger) // TODO: Set dispose to true?
- .AddLanguageProtocolLogging()
+ .ClearProviders()
+ .AddPsesLanguageServerLogging()
.SetMinimumLevel(_minimumLogLevel))
// TODO: Consider replacing all WithHandler with AddSingleton
+ .WithConfigurationSection("powershell.rename")
.WithHandler()
.WithHandler()
.WithHandler()
@@ -114,7 +118,6 @@ public async Task StartAsync()
.WithHandler()
.WithHandler()
.WithHandler()
- .WithHandler()
.WithHandler()
.WithHandler()
.WithHandler()
@@ -122,12 +125,19 @@ public async Task StartAsync()
.WithHandler()
.WithHandler()
.WithHandler()
+ .WithHandler()
+ .WithHandler()
// NOTE: The OnInitialize delegate gets run when we first receive the
// _Initialize_ request:
// https://microsoft.github.io/language-server-protocol/specifications/specification-current/#initialize
.OnInitialize(
(languageServer, initializeParams, cancellationToken) =>
{
+ // Wire up the HostLogger to the LanguageServer's logger once we are initialized, so that any messages still logged to the HostLogger get sent across the LSP channel. There is no more logging to disk at this point.
+ hostLoggerSubscription = HostLogger.Subscribe(new HostLoggerAdapter(
+ languageServer.Services.GetService>()
+ ));
+
// Set the workspace path from the parameters.
WorkspaceService workspaceService = languageServer.Services.GetService();
if (initializeParams.WorkspaceFolders is not null)
@@ -153,15 +163,18 @@ public async Task StartAsync()
InitialWorkingDirectory = initializationOptions?.GetValue("initialWorkingDirectory")?.Value()
?? workspaceService.WorkspaceFolders.FirstOrDefault()?.Uri.GetFileSystemPath()
?? Directory.GetCurrentDirectory(),
- ShellIntegrationEnabled = initializationOptions?.GetValue("shellIntegrationEnabled")?.Value()
- ?? false
+ // If a shell integration script path is provided, that implies the feature is enabled.
+ ShellIntegrationScript = initializationOptions?.GetValue("shellIntegrationScript")?.Value()
+ ?? "",
};
workspaceService.InitialWorkingDirectory = hostStartOptions.InitialWorkingDirectory;
_psesHost = languageServer.Services.GetService();
return _psesHost.TryStartAsync(hostStartOptions, cancellationToken);
- });
+ }
+ )
+ .OnShutdown(_ => hostLoggerSubscription.Dispose());
}).ConfigureAwait(false);
_serverStart.SetResult(true);
diff --git a/src/PowerShellEditorServices/Server/PsesServiceCollectionExtensions.cs b/src/PowerShellEditorServices/Server/PsesServiceCollectionExtensions.cs
index 3c02510b9..5a75ce448 100644
--- a/src/PowerShellEditorServices/Server/PsesServiceCollectionExtensions.cs
+++ b/src/PowerShellEditorServices/Server/PsesServiceCollectionExtensions.cs
@@ -10,13 +10,13 @@
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Debugging;
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Host;
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Runspace;
-using Microsoft.PowerShell.EditorServices.Services.Template;
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
namespace Microsoft.PowerShell.EditorServices.Server
{
internal static class PsesServiceCollectionExtensions
{
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD110:Observe result of async calls", Justification = "Using lazy initialization.")]
public static IServiceCollection AddPsesLanguageServices(
this IServiceCollection collection,
HostStartupInfo hostStartupInfo)
@@ -33,7 +33,6 @@ public static IServiceCollection AddPsesLanguageServices(
.AddSingleton()
.AddSingleton(
(provider) => provider.GetService().DebugContext)
- .AddSingleton()
.AddSingleton()
.AddSingleton()
.AddSingleton((provider) =>
@@ -48,12 +47,11 @@ public static IServiceCollection AddPsesLanguageServices(
// is ready, it will be available. NOTE: We cannot await this because it
// uses a lazy initialization to avoid a race with the dependency injection
// framework, see the EditorObject class for that!
-#pragma warning disable VSTHRD110
extensionService.InitializeAsync();
-#pragma warning restore VSTHRD110
return extensionService;
})
- .AddSingleton();
+ .AddSingleton()
+ .AddSingleton();
}
public static IServiceCollection AddPsesDebugServices(
diff --git a/src/PowerShellEditorServices/Services/Analysis/AnalysisService.cs b/src/PowerShellEditorServices/Services/Analysis/AnalysisService.cs
index f6b25c5f7..f346cb6c9 100644
--- a/src/PowerShellEditorServices/Services/Analysis/AnalysisService.cs
+++ b/src/PowerShellEditorServices/Services/Analysis/AnalysisService.cs
@@ -322,7 +322,7 @@ private bool TryFindSettingsFile(out string settingsFilePath)
return false;
}
- settingsFilePath = _workspaceService?.ResolveWorkspacePath(configuredPath);
+ settingsFilePath = _workspaceService?.FindFileInWorkspace(configuredPath);
if (settingsFilePath is null
|| !File.Exists(settingsFilePath))
@@ -332,6 +332,8 @@ private bool TryFindSettingsFile(out string settingsFilePath)
return false;
}
+ _logger.LogInformation($"Found PSSA settings file at '{settingsFilePath}'");
+
return true;
}
diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/BreakpointService.cs b/src/PowerShellEditorServices/Services/DebugAdapter/BreakpointService.cs
index 748e21c6d..6d7e0c31a 100644
--- a/src/PowerShellEditorServices/Services/DebugAdapter/BreakpointService.cs
+++ b/src/PowerShellEditorServices/Services/DebugAdapter/BreakpointService.cs
@@ -18,6 +18,83 @@ namespace Microsoft.PowerShell.EditorServices.Services
{
internal class BreakpointService
{
+ ///
+ /// Code used on WinPS 5.1 to set breakpoints without Script path validation.
+ /// It uses reflection because the APIs were not public until 7.0 but just in
+ /// case something changes it has a fallback to Set-PSBreakpoint.
+ ///
+ private const string _setPSBreakpointLegacy = @"
+ [CmdletBinding(DefaultParameterSetName = 'Line')]
+ param (
+ [Parameter()]
+ [ScriptBlock]
+ $Action,
+
+ [Parameter(ParameterSetName = 'Command')]
+ [Parameter(ParameterSetName = 'Line', Mandatory = $true)]
+ [string]
+ $Script,
+
+ [Parameter(ParameterSetName = 'Line')]
+ [int]
+ $Line,
+
+ [Parameter(ParameterSetName = 'Line')]
+ [int]
+ $Column,
+
+ [Parameter(ParameterSetName = 'Command', Mandatory = $true)]
+ [string]
+ $Command
+ )
+
+ if ($Script) {
+ # If using Set-PSBreakpoint we need to escape any wildcard patterns.
+ $PSBoundParameters['Script'] = [WildcardPattern]::Escape($Script)
+ }
+ else {
+ # WinPS must use null for the Script if unset.
+ $Script = [NullString]::Value
+ }
+
+ if ($PSCmdlet.ParameterSetName -eq 'Command') {
+ $cmdCtor = [System.Management.Automation.CommandBreakpoint].GetConstructor(
+ [System.Reflection.BindingFlags]'NonPublic, Public, Instance',
+ $null,
+ [type[]]@([string], [System.Management.Automation.WildcardPattern], [string], [ScriptBlock]),
+ $null)
+
+ if (-not $cmdCtor) {
+ Microsoft.PowerShell.Utility\Set-PSBreakpoint @PSBoundParameters
+ return
+ }
+
+ $pattern = [System.Management.Automation.WildcardPattern]::Get(
+ $Command,
+ [System.Management.Automation.WildcardOptions]'Compiled, IgnoreCase')
+ $b = $cmdCtor.Invoke(@($Script, $pattern, $Command, $Action))
+ }
+ else {
+ $lineCtor = [System.Management.Automation.LineBreakpoint].GetConstructor(
+ [System.Reflection.BindingFlags]'NonPublic, Public, Instance',
+ $null,
+ [type[]]@([string], [int], [int], [ScriptBlock]),
+ $null)
+
+ if (-not $lineCtor) {
+ Microsoft.PowerShell.Utility\Set-PSBreakpoint @PSBoundParameters
+ return
+ }
+
+ $b = $lineCtor.Invoke(@($Script, $Line, $Column, $Action))
+ }
+
+ [Runspace]::DefaultRunspace.Debugger.SetBreakpoints(
+ [System.Management.Automation.Breakpoint[]]@($b))
+
+ $b
+ ";
+
private readonly ILogger _logger;
private readonly IInternalPowerShellExecutionService _executionService;
private readonly PsesInternalHost _editorServicesHost;
@@ -57,7 +134,7 @@ public async Task> GetBreakpointsAsync()
.ConfigureAwait(false);
}
- public async Task> SetBreakpointsAsync(string escapedScriptPath, IReadOnlyList breakpoints)
+ public async Task> SetBreakpointsAsync(IReadOnlyList breakpoints)
{
if (BreakpointApiUtils.SupportsBreakpointApis(_editorServicesHost.CurrentRunspace))
{
@@ -114,9 +191,11 @@ public async Task> SetBreakpointsAsync(string e
psCommand.AddStatement();
}
+ // Don't use Set-PSBreakpoint as that will try and validate the Script
+ // path which may or may not exist.
psCommand
- .AddCommand(@"Microsoft.PowerShell.Utility\Set-PSBreakpoint")
- .AddParameter("Script", escapedScriptPath)
+ .AddScript(_setPSBreakpointLegacy, useLocalScope: true)
+ .AddParameter("Script", breakpoint.MappedSource ?? breakpoint.Source)
.AddParameter("Line", breakpoint.LineNumber);
// Check if the user has specified the column number for the breakpoint.
@@ -140,7 +219,16 @@ public async Task> SetBreakpointsAsync(string e
IEnumerable setBreakpoints = await _executionService
.ExecutePSCommandAsync(psCommand, CancellationToken.None)
.ConfigureAwait(false);
- configuredBreakpoints.AddRange(setBreakpoints.Select((breakpoint) => BreakpointDetails.Create(breakpoint)));
+
+ int bpIdx = 0;
+ foreach (Breakpoint setBp in setBreakpoints)
+ {
+ BreakpointDetails setBreakpoint = BreakpointDetails.Create(
+ setBp,
+ sourceBreakpoint: breakpoints[bpIdx]);
+ configuredBreakpoints.Add(setBreakpoint);
+ bpIdx++;
+ }
}
return configuredBreakpoints;
}
@@ -184,7 +272,7 @@ public async Task> SetCommandBreakpoints
}
psCommand
- .AddCommand(@"Microsoft.PowerShell.Utility\Set-PSBreakpoint")
+ .AddScript(_setPSBreakpointLegacy, useLocalScope: true)
.AddParameter("Command", breakpoint.Name);
// Check if this is a "conditional" line breakpoint.
diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/DebugService.cs b/src/PowerShellEditorServices/Services/DebugAdapter/DebugService.cs
index 90faceda4..a32cd48da 100644
--- a/src/PowerShellEditorServices/Services/DebugAdapter/DebugService.cs
+++ b/src/PowerShellEditorServices/Services/DebugAdapter/DebugService.cs
@@ -6,8 +6,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;
-using System.Management.Automation.Language;
-using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
@@ -17,7 +15,6 @@
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Execution;
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Host;
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Utility;
-using Microsoft.PowerShell.EditorServices.Services.TextDocument;
using Microsoft.PowerShell.EditorServices.Utility;
namespace Microsoft.PowerShell.EditorServices.Services
@@ -31,6 +28,7 @@ internal class DebugService
#region Fields
internal const string PsesGlobalVariableNamePrefix = "__psEditorServices_";
+ internal const string PsesGlobalVariableDebugServerName = $"{PsesGlobalVariableNamePrefix}DebugServer";
private const string TemporaryScriptFileName = "Script Listing.ps1";
private readonly ILogger _logger;
@@ -50,7 +48,6 @@ internal class DebugService
private VariableContainerDetails scriptScopeVariables;
private VariableContainerDetails localScopeVariables;
private StackFrameDetails[] stackFrameDetails;
- private readonly PropertyInfo invocationTypeScriptPositionProperty;
private readonly SemaphoreSlim debugInfoHandle = AsyncUtils.CreateSimpleLockingSemaphore();
#endregion
@@ -75,6 +72,11 @@ internal class DebugService
///
public DebuggerStoppedEventArgs CurrentDebuggerStoppedEventArgs { get; private set; }
+ ///
+ /// Returns a task that completes when script frames and variables have completed population
+ ///
+ public Task StackFramesAndVariablesFetched { get; private set; }
+
///
/// Tracks whether we are running Debug-Runspace in an out-of-process runspace.
///
@@ -84,6 +86,11 @@ public bool IsDebuggingRemoteRunspace
set => _debugContext.IsDebuggingRemoteRunspace = value;
}
+ ///
+ /// Gets or sets an array of path mappings for the current debug session.
+ ///
+ public PathMapping[] PathMappings { get; set; } = [];
+
#endregion
#region Constructors
@@ -111,12 +118,6 @@ public DebugService(
_debugContext.DebuggerResuming += OnDebuggerResuming;
_debugContext.BreakpointUpdated += OnBreakpointUpdated;
_remoteFileManager = remoteFileManager;
-
- invocationTypeScriptPositionProperty =
- typeof(InvocationInfo)
- .GetProperty(
- "ScriptPosition",
- BindingFlags.NonPublic | BindingFlags.Instance);
}
#endregion
@@ -126,22 +127,22 @@ public DebugService(
///
/// Sets the list of line breakpoints for the current debugging session.
///
- /// The ScriptFile in which breakpoints will be set.
+ /// The path in which breakpoints will be set.
/// BreakpointDetails for each breakpoint that will be set.
/// If true, causes all existing breakpoints to be cleared before setting new ones.
+ /// If true, skips the remote file manager mapping of the script path.
/// An awaitable Task that will provide details about the breakpoints that were set.
public async Task> SetLineBreakpointsAsync(
- ScriptFile scriptFile,
+ string scriptPath,
IReadOnlyList breakpoints,
- bool clearExisting = true)
+ bool clearExisting = true,
+ bool skipRemoteMapping = false)
{
DscBreakpointCapability dscBreakpoints = await _debugContext.GetDscBreakpointCapabilityAsync().ConfigureAwait(false);
- string scriptPath = scriptFile.FilePath;
-
_psesHost.Runspace.ThrowCancelledIfUnusable();
// Make sure we're using the remote script path
- if (_psesHost.CurrentRunspace.IsOnRemoteMachine && _remoteFileManager is not null)
+ if (!skipRemoteMapping && _psesHost.CurrentRunspace.IsOnRemoteMachine && _remoteFileManager is not null)
{
if (!_remoteFileManager.IsUnderRemoteTempPath(scriptPath))
{
@@ -165,10 +166,10 @@ public async Task> SetLineBreakpointsAsync(
{
if (clearExisting)
{
- await _breakpointService.RemoveAllBreakpointsAsync(scriptFile.FilePath).ConfigureAwait(false);
+ await _breakpointService.RemoveAllBreakpointsAsync(scriptPath).ConfigureAwait(false);
}
- return await _breakpointService.SetBreakpointsAsync(escapedScriptPath, breakpoints).ConfigureAwait(false);
+ return await _breakpointService.SetBreakpointsAsync(breakpoints).ConfigureAwait(false);
}
return await dscBreakpoints
@@ -606,6 +607,49 @@ public VariableScope[] GetVariableScopes(int stackFrameId)
};
}
+ internal bool TryGetMappedLocalPath(string remotePath, out string localPath)
+ {
+ foreach (PathMapping mapping in PathMappings)
+ {
+ if (string.IsNullOrWhiteSpace(mapping.LocalRoot) || string.IsNullOrWhiteSpace(mapping.RemoteRoot))
+ {
+ // If either path mapping is null, we can't map the path.
+ continue;
+ }
+
+ if (remotePath.StartsWith(mapping.RemoteRoot, StringComparison.OrdinalIgnoreCase))
+ {
+ localPath = mapping.LocalRoot + remotePath.Substring(mapping.RemoteRoot.Length);
+ return true;
+ }
+ }
+
+ localPath = null;
+ return false;
+ }
+
+ internal bool TryGetMappedRemotePath(string localPath, out string remotePath)
+ {
+ foreach (PathMapping mapping in PathMappings)
+ {
+ if (string.IsNullOrWhiteSpace(mapping.LocalRoot) || string.IsNullOrWhiteSpace(mapping.RemoteRoot))
+ {
+ // If either path mapping is null, we can't map the path.
+ continue;
+ }
+
+ if (localPath.StartsWith(mapping.LocalRoot, StringComparison.OrdinalIgnoreCase))
+ {
+ // If the local path starts with the local path mapping, we can replace it with the remote path.
+ remotePath = mapping.RemoteRoot + localPath.Substring(mapping.LocalRoot.Length);
+ return true;
+ }
+ }
+
+ remotePath = null;
+ return false;
+ }
+
#endregion
#region Private Methods
@@ -876,14 +920,19 @@ private async Task FetchStackFramesAsync(string scriptNameOverride)
StackFrameDetails stackFrameDetailsEntry = StackFrameDetails.Create(callStackFrame, autoVariables, commandVariables);
string stackFrameScriptPath = stackFrameDetailsEntry.ScriptPath;
- if (scriptNameOverride is not null
- && string.Equals(stackFrameScriptPath, StackFrameDetails.NoFileScriptPath))
+ bool isNoScriptPath = string.Equals(stackFrameScriptPath, StackFrameDetails.NoFileScriptPath);
+ if (scriptNameOverride is not null && isNoScriptPath)
{
stackFrameDetailsEntry.ScriptPath = scriptNameOverride;
}
+ else if (TryGetMappedLocalPath(stackFrameScriptPath, out string localMappedPath)
+ && !isNoScriptPath)
+ {
+ stackFrameDetailsEntry.ScriptPath = localMappedPath;
+ }
else if (_psesHost.CurrentRunspace.IsOnRemoteMachine
&& _remoteFileManager is not null
- && !string.Equals(stackFrameScriptPath, StackFrameDetails.NoFileScriptPath))
+ && !isNoScriptPath)
{
stackFrameDetailsEntry.ScriptPath =
_remoteFileManager.GetMappedPath(stackFrameScriptPath, _psesHost.CurrentRunspace);
@@ -923,6 +972,7 @@ private static string TrimScriptListingLine(PSObject scriptLineObj, ref int pref
///
public event EventHandler DebuggerStopped;
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD100:Avoid async void methods", Justification = "It has to be async.")]
internal async void OnDebuggerStopAsync(object sender, DebuggerStopEventArgs e)
{
try
@@ -980,12 +1030,16 @@ await _executionService.ExecutePSCommandAsync(
}
}
- // Get call stack and variables.
- await FetchStackFramesAndVariablesAsync(noScriptName ? localScriptPath : null).ConfigureAwait(false);
+ // Begin call stack and variables fetch. We don't need to block here.
+ StackFramesAndVariablesFetched = FetchStackFramesAndVariablesAsync(noScriptName ? localScriptPath : null);
+ if (!noScriptName && TryGetMappedLocalPath(e.InvocationInfo.ScriptName, out string mappedLocalPath))
+ {
+ localScriptPath = mappedLocalPath;
+ }
// If this is a remote connection and the debugger stopped at a line
// in a script file, get the file contents
- if (_psesHost.CurrentRunspace.IsOnRemoteMachine
+ else if (_psesHost.CurrentRunspace.IsOnRemoteMachine
&& _remoteFileManager is not null
&& !noScriptName)
{
@@ -995,53 +1049,6 @@ await _remoteFileManager.FetchRemoteFileAsync(
_psesHost.CurrentRunspace).ConfigureAwait(false);
}
- if (stackFrameDetails.Length > 0)
- {
- // Augment the top stack frame with details from the stop event
- if (invocationTypeScriptPositionProperty.GetValue(e.InvocationInfo) is IScriptExtent scriptExtent)
- {
- StackFrameDetails targetFrame = stackFrameDetails[0];
-
- // Certain context changes (like stepping into the default value expression
- // of a parameter) do not create a call stack frame. In order to represent
- // this context change we create a fake call stack frame.
- if (!string.IsNullOrEmpty(scriptExtent.File)
- && !PathUtils.IsPathEqual(scriptExtent.File, targetFrame.ScriptPath))
- {
- await debugInfoHandle.WaitAsync().ConfigureAwait(false);
- try
- {
- targetFrame = new StackFrameDetails
- {
- ScriptPath = scriptExtent.File,
- // Just use the last frame's variables since we don't have a
- // good way to get real values.
- AutoVariables = targetFrame.AutoVariables,
- CommandVariables = targetFrame.CommandVariables,
- // Ideally we'd get a real value here but since there's no real
- // call stack frame for this, we'd need to replicate a lot of
- // engine code.
- FunctionName = "",
- };
-
- StackFrameDetails[] newFrames = new StackFrameDetails[stackFrameDetails.Length + 1];
- newFrames[0] = targetFrame;
- stackFrameDetails.CopyTo(newFrames, 1);
- stackFrameDetails = newFrames;
- }
- finally
- {
- debugInfoHandle.Release();
- }
- }
-
- targetFrame.StartLineNumber = scriptExtent.StartLineNumber;
- targetFrame.EndLineNumber = scriptExtent.EndLineNumber;
- targetFrame.StartColumnNumber = scriptExtent.StartColumnNumber;
- targetFrame.EndColumnNumber = scriptExtent.EndColumnNumber;
- }
- }
-
CurrentDebuggerStoppedEventArgs =
new DebuggerStoppedEventArgs(
e,
@@ -1083,8 +1090,12 @@ private void OnBreakpointUpdated(object sender, BreakpointUpdatedEventArgs e)
{
// TODO: This could be either a path or a script block!
string scriptPath = lineBreakpoint.Script;
- if (_psesHost.CurrentRunspace.IsOnRemoteMachine
- && _remoteFileManager is not null)
+ if (TryGetMappedLocalPath(scriptPath, out string mappedLocalPath))
+ {
+ scriptPath = mappedLocalPath;
+ }
+ else if (_psesHost.CurrentRunspace.IsOnRemoteMachine
+ && _remoteFileManager is not null)
{
string mappedPath = _remoteFileManager.GetMappedPath(scriptPath, _psesHost.CurrentRunspace);
diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/DebugStateService.cs b/src/PowerShellEditorServices/Services/DebugAdapter/DebugStateService.cs
index f1bf3199e..9736b3e85 100644
--- a/src/PowerShellEditorServices/Services/DebugAdapter/DebugStateService.cs
+++ b/src/PowerShellEditorServices/Services/DebugAdapter/DebugStateService.cs
@@ -34,6 +34,8 @@ internal class DebugStateService
internal bool IsUsingTempIntegratedConsole { get; set; }
+ internal string ExecuteMode { get; set; }
+
// This gets set at the end of the Launch/Attach handler which set debug state.
internal TaskCompletionSource ServerStarted { get; set; }
diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointApiUtils.cs b/src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointApiUtils.cs
index 7884fbda5..ebb0646d2 100644
--- a/src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointApiUtils.cs
+++ b/src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointApiUtils.cs
@@ -136,7 +136,7 @@ public static Breakpoint SetBreakpoint(Debugger debugger, BreakpointDetailsBase
{
BreakpointDetails lineBreakpoint => SetLineBreakpointDelegate(
debugger,
- lineBreakpoint.Source,
+ lineBreakpoint.MappedSource ?? lineBreakpoint.Source,
lineBreakpoint.LineNumber,
lineBreakpoint.ColumnNumber ?? 0,
actionScriptBlock,
diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointDetails.cs b/src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointDetails.cs
index 0a1c268b9..4177b3816 100644
--- a/src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointDetails.cs
+++ b/src/PowerShellEditorServices/Services/DebugAdapter/Debugging/BreakpointDetails.cs
@@ -24,6 +24,11 @@ internal sealed class BreakpointDetails : BreakpointDetailsBase
///
public string Source { get; private set; }
+ ///
+ /// Gets the source where the breakpoint is mapped to, will be null if no mapping exists. Used only for debug purposes.
+ ///
+ public string MappedSource { get; private set; }
+
///
/// Gets the line number at which the breakpoint is set.
///
@@ -50,6 +55,7 @@ private BreakpointDetails()
///
///
///
+ ///
///
internal static BreakpointDetails Create(
string source,
@@ -57,7 +63,8 @@ internal static BreakpointDetails Create(
int? column = null,
string condition = null,
string hitCondition = null,
- string logMessage = null)
+ string logMessage = null,
+ string mappedSource = null)
{
Validate.IsNotNullOrEmptyString(nameof(source), source);
@@ -69,7 +76,8 @@ internal static BreakpointDetails Create(
ColumnNumber = column,
Condition = condition,
HitCondition = hitCondition,
- LogMessage = logMessage
+ LogMessage = logMessage,
+ MappedSource = mappedSource
};
}
@@ -79,10 +87,12 @@ internal static BreakpointDetails Create(
///
/// The Breakpoint instance from which details will be taken.
/// The BreakpointUpdateType to determine if the breakpoint is verified.
+ /// /// The breakpoint source from the debug client, if any.
/// A new instance of the BreakpointDetails class.
internal static BreakpointDetails Create(
Breakpoint breakpoint,
- BreakpointUpdateType updateType = BreakpointUpdateType.Set)
+ BreakpointUpdateType updateType = BreakpointUpdateType.Set,
+ BreakpointDetails sourceBreakpoint = null)
{
Validate.IsNotNull(nameof(breakpoint), breakpoint);
@@ -96,10 +106,11 @@ internal static BreakpointDetails Create(
{
Id = breakpoint.Id,
Verified = updateType != BreakpointUpdateType.Disabled,
- Source = lineBreakpoint.Script,
+ Source = sourceBreakpoint?.MappedSource is not null ? sourceBreakpoint.Source : lineBreakpoint.Script,
LineNumber = lineBreakpoint.Line,
ColumnNumber = lineBreakpoint.Column,
- Condition = lineBreakpoint.Action?.ToString()
+ Condition = lineBreakpoint.Action?.ToString(),
+ MappedSource = sourceBreakpoint?.MappedSource,
};
if (lineBreakpoint.Column > 0)
diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/BreakpointHandlers.cs b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/BreakpointHandlers.cs
index 4c99ff747..1c26c48de 100644
--- a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/BreakpointHandlers.cs
+++ b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/BreakpointHandlers.cs
@@ -11,7 +11,6 @@
using Microsoft.PowerShell.EditorServices.Logging;
using Microsoft.PowerShell.EditorServices.Services;
using Microsoft.PowerShell.EditorServices.Services.DebugAdapter;
-using Microsoft.PowerShell.EditorServices.Services.PowerShell.Runspace;
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
using Microsoft.PowerShell.EditorServices.Utility;
using OmniSharp.Extensions.DebugAdapter.Protocol.Models;
@@ -31,20 +30,17 @@ internal class BreakpointHandlers : ISetFunctionBreakpointsHandler, ISetBreakpoi
private readonly DebugService _debugService;
private readonly DebugStateService _debugStateService;
private readonly WorkspaceService _workspaceService;
- private readonly IRunspaceContext _runspaceContext;
public BreakpointHandlers(
ILoggerFactory loggerFactory,
DebugService debugService,
DebugStateService debugStateService,
- WorkspaceService workspaceService,
- IRunspaceContext runspaceContext)
+ WorkspaceService workspaceService)
{
_logger = loggerFactory.CreateLogger();
_debugService = debugService;
_debugStateService = debugStateService;
_workspaceService = workspaceService;
- _runspaceContext = runspaceContext;
}
public async Task Handle(SetBreakpointsArguments request, CancellationToken cancellationToken)
@@ -83,6 +79,11 @@ public async Task Handle(SetBreakpointsArguments request
}
// At this point, the source file has been verified as a PowerShell script.
+ string mappedSource = null;
+ if (_debugService.TryGetMappedRemotePath(scriptFile.FilePath, out string remoteMappedPath))
+ {
+ mappedSource = remoteMappedPath;
+ }
IReadOnlyList breakpointDetails = request.Breakpoints
.Select((srcBreakpoint) => BreakpointDetails.Create(
scriptFile.FilePath,
@@ -90,7 +91,8 @@ public async Task Handle(SetBreakpointsArguments request
srcBreakpoint.Column,
srcBreakpoint.Condition,
srcBreakpoint.HitCondition,
- srcBreakpoint.LogMessage)).ToList();
+ srcBreakpoint.LogMessage,
+ mappedSource: mappedSource)).ToList();
// If this is a "run without debugging (Ctrl+F5)" session ignore requests to set breakpoints.
IReadOnlyList updatedBreakpointDetails = breakpointDetails;
@@ -102,8 +104,9 @@ public async Task Handle(SetBreakpointsArguments request
{
updatedBreakpointDetails =
await _debugService.SetLineBreakpointsAsync(
- scriptFile,
- breakpointDetails).ConfigureAwait(false);
+ mappedSource ?? scriptFile.FilePath,
+ breakpointDetails,
+ skipRemoteMapping: mappedSource is not null).ConfigureAwait(false);
}
catch (Exception e)
{
@@ -182,12 +185,11 @@ public Task Handle(SetExceptionBreakpointsArgum
Task.FromResult(new SetExceptionBreakpointsResponse());
- private bool IsFileSupportedForBreakpoints(string requestedPath, ScriptFile resolvedScriptFile)
+ private static bool IsFileSupportedForBreakpoints(string requestedPath, ScriptFile resolvedScriptFile)
{
- // PowerShell 7 and above support breakpoints in untitled files
if (ScriptFile.IsUntitledPath(requestedPath))
{
- return BreakpointApiUtils.SupportsBreakpointApis(_runspaceContext.CurrentRunspace);
+ return true;
}
if (string.IsNullOrEmpty(resolvedScriptFile?.FilePath))
diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/ConfigurationDoneHandler.cs b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/ConfigurationDoneHandler.cs
index df8165319..146bbeae0 100644
--- a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/ConfigurationDoneHandler.cs
+++ b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/ConfigurationDoneHandler.cs
@@ -7,11 +7,9 @@
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.PowerShell.EditorServices.Services;
-using Microsoft.PowerShell.EditorServices.Services.DebugAdapter;
using Microsoft.PowerShell.EditorServices.Services.PowerShell;
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Debugging;
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Execution;
-using Microsoft.PowerShell.EditorServices.Services.PowerShell.Runspace;
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
using Microsoft.PowerShell.EditorServices.Utility;
using OmniSharp.Extensions.DebugAdapter.Protocol.Events;
@@ -44,7 +42,6 @@ internal class ConfigurationDoneHandler : IConfigurationDoneHandler
private readonly IInternalPowerShellExecutionService _executionService;
private readonly WorkspaceService _workspaceService;
private readonly IPowerShellDebugContext _debugContext;
- private readonly IRunspaceContext _runspaceContext;
// TODO: Decrease these arguments since they're a bunch of interfaces that can be simplified
// (i.e., `IRunspaceContext` should just be available on `IPowerShellExecutionService`).
@@ -56,8 +53,7 @@ public ConfigurationDoneHandler(
DebugEventHandlerService debugEventHandlerService,
IInternalPowerShellExecutionService executionService,
WorkspaceService workspaceService,
- IPowerShellDebugContext debugContext,
- IRunspaceContext runspaceContext)
+ IPowerShellDebugContext debugContext)
{
_logger = loggerFactory.CreateLogger();
_debugAdapterServer = debugAdapterServer;
@@ -67,7 +63,6 @@ public ConfigurationDoneHandler(
_executionService = executionService;
_workspaceService = workspaceService;
_debugContext = debugContext;
- _runspaceContext = runspaceContext;
}
public Task Handle(ConfigurationDoneArguments request, CancellationToken cancellationToken)
@@ -110,20 +105,20 @@ internal async Task LaunchScriptAsync(string scriptToLaunch)
PSCommand command;
if (System.IO.File.Exists(scriptToLaunch))
{
- // For a saved file we just execute its path (after escaping it).
+ // For a saved file we just execute its path (after escaping it), with the configured operator
+ // (which can't be called that because it's a reserved keyword in C#).
+ string executeMode = _debugStateService?.ExecuteMode == "Call" ? "&" : ".";
command = PSCommandHelpers.BuildDotSourceCommandWithArguments(
- PSCommandHelpers.EscapeScriptFilePath(scriptToLaunch), _debugStateService?.Arguments);
+ PSCommandHelpers.EscapeScriptFilePath(scriptToLaunch), _debugStateService?.Arguments, executeMode);
}
else // It's a URI to an untitled script, or a raw script.
{
bool isScriptFile = _workspaceService.TryGetFile(scriptToLaunch, out ScriptFile untitledScript);
- if (isScriptFile && BreakpointApiUtils.SupportsBreakpointApis(_runspaceContext.CurrentRunspace))
+ if (isScriptFile)
{
// Parse untitled files with their `Untitled:` URI as the filename which will
// cache the URI and contents within the PowerShell parser. By doing this, we
- // light up the ability to debug untitled files with line breakpoints. This is
- // only possible with PowerShell 7's new breakpoint APIs since the old API,
- // Set-PSBreakpoint, validates that the given path points to a real file.
+ // light up the ability to debug untitled files with line breakpoints.
ScriptBlockAst ast = Parser.ParseInput(
untitledScript.Contents,
untitledScript.DocumentUri.ToString(),
diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/DisconnectHandler.cs b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/DisconnectHandler.cs
index fef2b107c..b042f912e 100644
--- a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/DisconnectHandler.cs
+++ b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/DisconnectHandler.cs
@@ -50,13 +50,23 @@ public async Task Handle(DisconnectArguments request, Cancel
// We should instead ensure that the debugger is in some valid state, lock it and then tear things down
_debugEventHandlerService.UnregisterEventHandlers();
+ _debugService.PathMappings = [];
if (!_debugStateService.ExecutionCompleted)
{
_debugStateService.ExecutionCompleted = true;
_debugService.Abort();
- if (_debugStateService.IsInteractiveDebugSession && _debugStateService.IsAttachSession)
+ if (!_debugStateService.IsAttachSession && !_debugStateService.IsUsingTempIntegratedConsole)
+ {
+ await _executionService.ExecutePSCommandAsync(
+ new PSCommand().AddCommand("Remove-Variable")
+ .AddParameter("Name", DebugService.PsesGlobalVariableDebugServerName)
+ .AddParameter("Force", true),
+ cancellationToken).ConfigureAwait(false);
+ }
+
+ if (_debugStateService.IsInteractiveDebugSession && _debugStateService.IsRemoteAttach)
{
// Pop the sessions
if (_runspaceContext.CurrentRunspace.RunspaceOrigin == RunspaceOrigin.EnteredProcess)
diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/LaunchAndAttachHandler.cs b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/LaunchAndAttachHandler.cs
index 700c154b9..200dcc316 100644
--- a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/LaunchAndAttachHandler.cs
+++ b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/LaunchAndAttachHandler.cs
@@ -65,11 +65,22 @@ internal record PsesLaunchRequestArguments : LaunchRequestArguments
///
public string[] RuntimeArgs { get; set; }
+ ///
+ /// Gets or sets the script execution mode, either "DotSource" or "Call".
+ ///
+ public string ExecuteMode { get; set; }
+
///
/// Gets or sets optional environment variables to pass to the debuggee. The string valued
/// properties of the 'environmentVariables' are used as key/value pairs.
///
public Dictionary Env { get; set; }
+
+ ///
+ /// Gets or sets the path mappings for the debugging session. This is
+ /// only used when the current runspace is remote.
+ ///
+ public PathMapping[] PathMappings { get; set; } = [];
}
internal record PsesAttachRequestArguments : AttachRequestArguments
@@ -83,6 +94,11 @@ internal record PsesAttachRequestArguments : AttachRequestArguments
public string RunspaceName { get; set; }
public string CustomPipeName { get; set; }
+
+ ///
+ /// Gets or sets the path mappings for the remote debugging session.
+ ///
+ public PathMapping[] PathMappings { get; set; } = [];
}
internal class LaunchAndAttachHandler : ILaunchHandler, IAttachHandler, IOnDebugAdapterServerStarted
@@ -123,6 +139,20 @@ public LaunchAndAttachHandler(
}
public async Task Handle(PsesLaunchRequestArguments request, CancellationToken cancellationToken)
+ {
+ _debugService.PathMappings = request.PathMappings;
+ try
+ {
+ return await HandleImpl(request, cancellationToken).ConfigureAwait(false);
+ }
+ catch
+ {
+ _debugService.PathMappings = [];
+ throw;
+ }
+ }
+
+ public async Task HandleImpl(PsesLaunchRequestArguments request, CancellationToken cancellationToken)
{
// The debugger has officially started. We use this to later check if we should stop it.
((PsesInternalHost)_executionService).DebugContext.IsActive = true;
@@ -173,6 +203,23 @@ public async Task Handle(PsesLaunchRequestArguments request, Can
}
_logger.LogTrace("Working dir " + (string.IsNullOrEmpty(workingDir) ? "not set." : $"set to '{workingDir}'"));
+
+ if (!request.CreateTemporaryIntegratedConsole)
+ {
+ // Start-DebugAttachSession attaches in a new temp console
+ // so we cannot set this var if already running in that
+ // console.
+ PSCommand setVariableCmd = new PSCommand().AddCommand("Set-Variable")
+ .AddParameter("Name", DebugService.PsesGlobalVariableDebugServerName)
+ .AddParameter("Value", _debugAdapterServer)
+ .AddParameter("Description", "DO NOT USE: for internal use only.")
+ .AddParameter("Scope", "Global")
+ .AddParameter("Option", "ReadOnly");
+
+ await _executionService.ExecutePSCommandAsync(
+ setVariableCmd,
+ cancellationToken).ConfigureAwait(false);
+ }
}
// Prepare arguments to the script - if specified
@@ -183,27 +230,10 @@ public async Task Handle(PsesLaunchRequestArguments request, Can
// Store the launch parameters so that they can be used later
_debugStateService.NoDebug = request.NoDebug;
- _debugStateService.ScriptToLaunch = request.Script;
+ _debugStateService.ScriptToLaunch = GetLaunchScript(request);
_debugStateService.Arguments = request.Args;
_debugStateService.IsUsingTempIntegratedConsole = request.CreateTemporaryIntegratedConsole;
-
- if (request.CreateTemporaryIntegratedConsole
- && !string.IsNullOrEmpty(request.Script)
- && ScriptFile.IsUntitledPath(request.Script))
- {
- throw new RpcErrorException(0, null, "Running an Untitled file in a temporary Extension Terminal is currently not supported!");
- }
-
- // If the current session is remote, map the script path to the remote
- // machine if necessary
- if (_debugStateService.ScriptToLaunch != null
- && _runspaceContext.CurrentRunspace.IsOnRemoteMachine)
- {
- _debugStateService.ScriptToLaunch =
- _remoteFileManagerService.GetMappedPath(
- _debugStateService.ScriptToLaunch,
- _runspaceContext.CurrentRunspace);
- }
+ _debugStateService.ExecuteMode = request.ExecuteMode;
// If no script is being launched, mark this as an interactive
// debugging session
@@ -227,11 +257,13 @@ public async Task Handle(PsesAttachRequestArguments request, Can
_debugService.IsDebuggingRemoteRunspace = true;
try
{
+ _debugService.PathMappings = request.PathMappings;
return await HandleImpl(request, cancellationToken).ConfigureAwait(false);
}
catch
{
_debugService.IsDebuggingRemoteRunspace = false;
+ _debugService.PathMappings = [];
throw;
}
}
@@ -295,7 +327,6 @@ void RunspaceChangedHandler(object s, RunspaceChangedEventArgs _)
throw new RpcErrorException(0, null, "Invalid configuration with no process ID nor custom pipe name!");
}
-
// Execute the Debug-Runspace command but don't await it because it
// will block the debug adapter initialization process. The
// InitializedEvent will be sent as soon as the RunspaceChanged
@@ -322,7 +353,6 @@ void RunspaceChangedHandler(object s, RunspaceChangedEventArgs _)
if (request.RunspaceId < 1)
{
-
throw new RpcErrorException(0, null, "A positive integer must be specified for the RunspaceId!");
}
@@ -440,6 +470,7 @@ public async Task OnStarted(IDebugAdapterServer server, CancellationToken cancel
// be sent to the client.
await _debugStateService.ServerStarted.Task.ConfigureAwait(false);
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD003:Avoid awaiting foreign Tasks", Justification = "It's a wrapper.")]
private async Task OnExecutionCompletedAsync(Task executeTask)
{
bool isRunspaceClosed = false;
@@ -464,6 +495,7 @@ private async Task OnExecutionCompletedAsync(Task executeTask)
_debugEventHandlerService.UnregisterEventHandlers();
_debugService.IsDebuggingRemoteRunspace = false;
+ _debugService.PathMappings = [];
if (!isRunspaceClosed && _debugStateService.IsAttachSession)
{
@@ -493,5 +525,36 @@ await _executionService.ExecutePSCommandAsync(
_debugService.IsClientAttached = false;
_debugAdapterServer.SendNotification(EventNames.Terminated);
}
+
+ private string GetLaunchScript(PsesLaunchRequestArguments request)
+ {
+ string scriptToLaunch = request.Script;
+ if (request.CreateTemporaryIntegratedConsole
+ && !string.IsNullOrEmpty(scriptToLaunch)
+ && ScriptFile.IsUntitledPath(scriptToLaunch))
+ {
+ throw new RpcErrorException(0, null, "Running an Untitled file in a temporary Extension Terminal is currently not supported!");
+ }
+
+ // If the current session is remote, map the script path to the remote
+ // machine if necessary
+ if (scriptToLaunch is not null && _runspaceContext.CurrentRunspace.IsOnRemoteMachine)
+ {
+ if (_debugService.TryGetMappedRemotePath(scriptToLaunch, out string remoteMappedPath))
+ {
+ scriptToLaunch = remoteMappedPath;
+ }
+ else
+ {
+ // If the script is not mapped, we will map it to the remote path
+ // using the RemoteFileManagerService.
+ scriptToLaunch = _remoteFileManagerService.GetMappedPath(
+ scriptToLaunch,
+ _runspaceContext.CurrentRunspace);
+ }
+ }
+
+ return scriptToLaunch;
+ }
}
}
diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/ScopesHandler.cs b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/ScopesHandler.cs
index 04adf185e..daa3d8e60 100644
--- a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/ScopesHandler.cs
+++ b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/ScopesHandler.cs
@@ -18,16 +18,27 @@ internal class ScopesHandler : IScopesHandler
public ScopesHandler(DebugService debugService) => _debugService = debugService;
+ ///
+ /// Retrieves the variable scopes (containers) for the currently selected stack frame. Variables details are fetched via a separate request.
+ ///
public Task Handle(ScopesArguments request, CancellationToken cancellationToken)
{
- VariableScope[] variableScopes =
- _debugService.GetVariableScopes(
- (int)request.FrameId);
+ // HACK: The StackTraceHandler injects an artificial label frame as the first frame as a performance optimization, so when scopes are requested by the client, we need to adjust the frame index accordingly to match the underlying PowerShell frame, so when the client clicks on the label (or hit the default breakpoint), they get variables populated from the top of the PowerShell stackframe. If the client dives deeper, we need to reflect that as well (though 90% of debug users don't actually investigate this)
+ // VSCode Frame 0 (Label) -> PowerShell StackFrame 0 (for convenience)
+ // VSCode Frame 1 (First Real PS Frame) -> Also PowerShell StackFrame 0
+ // VSCode Frame 2 -> PowerShell StackFrame 1
+ // VSCode Frame 3 -> PowerShell StackFrame 2
+ // etc.
+ int powershellFrameId = request.FrameId == 0 ? 0 : (int)request.FrameId - 1;
+
+ VariableScope[] variableScopes = _debugService.GetVariableScopes(powershellFrameId);
return Task.FromResult(new ScopesResponse
{
- Scopes = new Container(variableScopes
- .Select(LspDebugUtils.CreateScope))
+ Scopes = new Container(
+ variableScopes
+ .Select(LspDebugUtils.CreateScope)
+ )
});
}
}
diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/StackTraceHandler.cs b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/StackTraceHandler.cs
index f53e094e7..735d672d1 100644
--- a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/StackTraceHandler.cs
+++ b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/StackTraceHandler.cs
@@ -1,64 +1,136 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
+#nullable enable
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using System.Management.Automation;
using Microsoft.PowerShell.EditorServices.Services;
-using Microsoft.PowerShell.EditorServices.Services.DebugAdapter;
-using Microsoft.PowerShell.EditorServices.Utility;
using OmniSharp.Extensions.DebugAdapter.Protocol.Models;
using OmniSharp.Extensions.DebugAdapter.Protocol.Requests;
+using Microsoft.PowerShell.EditorServices.Services.DebugAdapter;
+using System.Linq;
+using OmniSharp.Extensions.JsonRpc;
+
+namespace Microsoft.PowerShell.EditorServices.Handlers;
-namespace Microsoft.PowerShell.EditorServices.Handlers
+internal class StackTraceHandler(DebugService debugService) : IStackTraceHandler
{
- internal class StackTraceHandler : IStackTraceHandler
+ ///
+ /// Because we don't know the size of the stacktrace beforehand, we will tell the client that there are more frames available, this is effectively a paging size, as the client should request this many frames after the first one.
+ ///
+ private const int INITIAL_PAGE_SIZE = 20;
+
+ public async Task Handle(StackTraceArguments request, CancellationToken cancellationToken)
{
- private readonly DebugService _debugService;
+ if (!debugService.IsDebuggerStopped)
+ {
+ throw new RpcErrorException(0, null!, "Stacktrace was requested while we are not stopped at a breakpoint. This is a violation of the DAP protocol, and is probably a bug.");
+ }
+
+ // Adapting to int to let us use LINQ, realistically if you have a stacktrace larger than this that the client is requesting, you have bigger problems...
+ int skip = Convert.ToInt32(request.StartFrame ?? 0);
+ int take = Convert.ToInt32(request.Levels ?? 0);
- public StackTraceHandler(DebugService debugService) => _debugService = debugService;
+ // We generate a label for the breakpoint and can return that immediately if the client is supporting DelayedStackTraceLoading.
+ InvocationInfo invocationInfo = debugService.CurrentDebuggerStoppedEventArgs?.OriginalEvent?.InvocationInfo
+ ?? throw new RpcErrorException(0, null!, "InvocationInfo was not available on CurrentDebuggerStoppedEvent args. This is a bug and you should report it.");
- public async Task Handle(StackTraceArguments request, CancellationToken cancellationToken)
+ string? scriptNameOverride = null;
+ if (debugService.TryGetMappedLocalPath(invocationInfo.ScriptName, out string mappedLocalPath))
{
- StackFrameDetails[] stackFrameDetails = await _debugService.GetStackFramesAsync(cancellationToken).ConfigureAwait(false);
+ scriptNameOverride = mappedLocalPath;
+ }
+ StackFrame breakpointLabel = CreateBreakpointLabel(invocationInfo, scriptNameOverride: scriptNameOverride);
- // Handle a rare race condition where the adapter requests stack frames before they've
- // begun building.
- if (stackFrameDetails is null)
- {
- return new StackTraceResponse
- {
- StackFrames = Array.Empty(),
- TotalFrames = 0
- };
- }
-
- List newStackFrames = new();
-
- long startFrameIndex = request.StartFrame ?? 0;
- long maxFrameCount = stackFrameDetails.Length;
-
- // If the number of requested levels == 0 (or null), that means get all stack frames
- // after the specified startFrame index. Otherwise get all the stack frames.
- long requestedFrameCount = request.Levels ?? 0;
- if (requestedFrameCount > 0)
+ if (skip == 0 && take == 1) // This indicates the client is doing an initial fetch, so we want to return quickly to unblock the UI and wait on the remaining stack frames for the subsequent requests.
+ {
+ return new StackTraceResponse()
{
- maxFrameCount = Math.Min(maxFrameCount, startFrameIndex + requestedFrameCount);
- }
+ StackFrames = new StackFrame[] { breakpointLabel },
+ TotalFrames = INITIAL_PAGE_SIZE //Indicate to the client that there are more frames available
+ };
+ }
- for (long i = startFrameIndex; i < maxFrameCount; i++)
- {
- // Create the new StackFrame object with an ID that can
- // be referenced back to the current list of stack frames
- newStackFrames.Add(LspDebugUtils.CreateStackFrame(stackFrameDetails[i], id: i));
- }
+ // Wait until the stack frames and variables have been fetched.
+ await debugService.StackFramesAndVariablesFetched.ConfigureAwait(false);
+ StackFrameDetails[] stackFrameDetails = await debugService.GetStackFramesAsync(cancellationToken)
+ .ConfigureAwait(false);
+
+ // Handle a rare race condition where the adapter requests stack frames before they've
+ // begun building.
+ if (stackFrameDetails is null)
+ {
return new StackTraceResponse
{
- StackFrames = newStackFrames,
- TotalFrames = newStackFrames.Count
+ StackFrames = Array.Empty(),
+ TotalFrames = 0
+ };
+ }
+
+ List newStackFrames = new();
+ if (skip == 0)
+ {
+ newStackFrames.Add(breakpointLabel);
+ }
+
+ newStackFrames.AddRange(
+ stackFrameDetails
+ .Skip(skip != 0 ? skip - 1 : skip)
+ .Take(take != 0 ? take - 1 : take)
+ .Select((frame, index) => CreateStackFrame(frame, index + 1))
+ );
+
+ return new StackTraceResponse
+ {
+ StackFrames = newStackFrames,
+ TotalFrames = newStackFrames.Count
+ };
+ }
+
+ public static StackFrame CreateStackFrame(StackFrameDetails stackFrame, long id)
+ {
+ SourcePresentationHint sourcePresentationHint =
+ stackFrame.IsExternalCode ? SourcePresentationHint.Deemphasize : SourcePresentationHint.Normal;
+
+ // When debugging an interactive session, the ScriptPath is which is not a valid source file.
+ // We need to make sure the user can't open the file associated with this stack frame.
+ // It will generate a VSCode error in this case.
+ Source? source = null;
+ if (!stackFrame.ScriptPath.Contains(""))
+ {
+ source = new Source
+ {
+ Path = stackFrame.ScriptPath,
+ PresentationHint = sourcePresentationHint
};
}
+
+ return new StackFrame
+ {
+ Id = id,
+ Name = (source is not null) ? stackFrame.FunctionName : "Interactive Session",
+ Line = (source is not null) ? stackFrame.StartLineNumber : 0,
+ EndLine = stackFrame.EndLineNumber,
+ Column = (source is not null) ? stackFrame.StartColumnNumber : 0,
+ EndColumn = stackFrame.EndColumnNumber,
+ Source = source
+ };
}
+
+ public static StackFrame CreateBreakpointLabel(InvocationInfo invocationInfo, int id = 0, string? scriptNameOverride = null) => new()
+ {
+ Name = "",
+ Id = id,
+ Source = new()
+ {
+ Path = scriptNameOverride ?? invocationInfo.ScriptName
+ },
+ Line = invocationInfo.ScriptLineNumber,
+ Column = invocationInfo.OffsetInLine,
+ PresentationHint = StackFramePresentationHint.Label
+ };
}
diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/VariablesHandler.cs b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/VariablesHandler.cs
index 58fb4d5ef..55c5f85ff 100644
--- a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/VariablesHandler.cs
+++ b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/VariablesHandler.cs
@@ -34,10 +34,12 @@ public async Task Handle(VariablesArguments request, Cancella
.ToArray()
};
}
+ #pragma warning disable RCS1075
catch (Exception)
{
// TODO: This shouldn't be so broad
}
+ #pragma warning restore RCS1075
return variablesResponse;
}
diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/PathMapping.cs b/src/PowerShellEditorServices/Services/DebugAdapter/PathMapping.cs
new file mode 100644
index 000000000..6bf6a6ad9
--- /dev/null
+++ b/src/PowerShellEditorServices/Services/DebugAdapter/PathMapping.cs
@@ -0,0 +1,24 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#nullable enable
+
+namespace Microsoft.PowerShell.EditorServices.Services;
+
+///
+/// Used for attach requests to map a local and remote path together.
+///
+internal record PathMapping
+{
+ ///
+ /// Gets or sets the local root of this mapping entry.
+ ///
+ public string? LocalRoot { get; set; }
+
+ ///
+ /// Gets or sets the remote root of this mapping entry.
+ ///
+ public string? RemoteRoot { get; set; }
+}
+
+#nullable disable
diff --git a/src/PowerShellEditorServices/Services/Extension/EditorOperationsService.cs b/src/PowerShellEditorServices/Services/Extension/EditorOperationsService.cs
index 607d38720..9c3e0c4ff 100644
--- a/src/PowerShellEditorServices/Services/Extension/EditorOperationsService.cs
+++ b/src/PowerShellEditorServices/Services/Extension/EditorOperationsService.cs
@@ -198,6 +198,14 @@ public async Task SaveFileAsync(string currentPath, string newSavePath)
public string[] GetWorkspacePaths() => _workspaceService.WorkspacePaths.ToArray();
+ public WorkspaceOpenDocument[] GetWorkspaceOpenDocuments()
+ => [..
+ _workspaceService
+ .GetOpenedFiles()
+ .Where(static scriptFile => scriptFile.IsOpen)
+ .Select(static scriptFile => new WorkspaceOpenDocument(scriptFile.FilePath, !scriptFile.IsInMemory))
+ ];
+
public string GetWorkspaceRelativePath(ScriptFile scriptFile) => _workspaceService.GetRelativePath(scriptFile);
public async Task ShowInformationMessageAsync(string message)
diff --git a/src/PowerShellEditorServices/Services/PowerShell/Console/LegacyReadLine.cs b/src/PowerShellEditorServices/Services/PowerShell/Console/LegacyReadLine.cs
index 3c5e7a1d2..28d29baa1 100644
--- a/src/PowerShellEditorServices/Services/PowerShell/Console/LegacyReadLine.cs
+++ b/src/PowerShellEditorServices/Services/PowerShell/Console/LegacyReadLine.cs
@@ -35,9 +35,7 @@ public LegacyReadLine(
_onIdleAction = onIdleAction;
}
-#pragma warning disable CA1502 // Cyclomatic complexity we don't care about
public override string ReadLine(CancellationToken cancellationToken)
-#pragma warning restore CA1502
{
string inputBeforeCompletion = null;
string inputAfterCompletion = null;
@@ -394,6 +392,7 @@ protected override ConsoleKeyInfo ReadKey(CancellationToken cancellationToken)
}
}
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "This is a legacy implementation.")]
private ConsoleKeyInfo ReadKeyWithIdleSupport(CancellationToken cancellationToken)
{
// We run the readkey function on another thread so we can run an idle handler
diff --git a/src/PowerShellEditorServices/Services/PowerShell/Debugging/DscBreakpointCapability.cs b/src/PowerShellEditorServices/Services/PowerShell/Debugging/DscBreakpointCapability.cs
index 763094be4..344b798f7 100644
--- a/src/PowerShellEditorServices/Services/PowerShell/Debugging/DscBreakpointCapability.cs
+++ b/src/PowerShellEditorServices/Services/PowerShell/Debugging/DscBreakpointCapability.cs
@@ -91,10 +91,12 @@ public static async Task GetDscCapabilityAsync(
.AddCommand(@"Microsoft.PowerShell.Core\Import-Module")
.AddParameter("Name", "PSDesiredStateConfiguration")
.AddParameter("PassThru")
- .AddParameter("ErrorAction", ActionPreference.Ignore);
+ .AddParameter("ErrorAction", ActionPreference.Ignore)
+ .AddCommand(@"Microsoft.PowerShell.Utility\Select-Object")
+ .AddParameter("ExpandProperty", "Name");
- IReadOnlyList dscModule =
- await executionService.ExecutePSCommandAsync(
+ IReadOnlyList dscModule =
+ await executionService.ExecutePSCommandAsync(
psCommand,
CancellationToken.None,
new PowerShellExecutionOptions { ThrowOnError = false })
diff --git a/src/PowerShellEditorServices/Services/PowerShell/Handlers/HandlerErrorException.cs b/src/PowerShellEditorServices/Services/PowerShell/Handlers/HandlerErrorException.cs
new file mode 100644
index 000000000..af6cda2ec
--- /dev/null
+++ b/src/PowerShellEditorServices/Services/PowerShell/Handlers/HandlerErrorException.cs
@@ -0,0 +1,24 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using OmniSharp.Extensions.JsonRpc;
+using OmniSharp.Extensions.LanguageServer.Protocol.Models;
+
+namespace Microsoft.PowerShell.EditorServices.Handlers;
+
+///
+/// A convenience exception for handlers to throw when a request fails for a normal reason,
+/// and to communicate that reason to the user without a full internal stacktrace.
+///
+/// The message describing the reason for the request failure.
+/// Additional details to be logged regarding the failure. It should be serializable to JSON.
+/// The severity level of the message. This is only shown in internal logging.
+internal class HandlerErrorException
+(
+ string message,
+ object logDetails = null,
+ MessageType severity = MessageType.Error
+) : RpcErrorException(0, logDetails!, message)
+{
+ internal MessageType Severity { get; } = severity;
+}
diff --git a/src/PowerShellEditorServices/Services/PowerShell/Host/HostStartOptions.cs b/src/PowerShellEditorServices/Services/PowerShell/Host/HostStartOptions.cs
index f483b76b4..7de16fddf 100644
--- a/src/PowerShellEditorServices/Services/PowerShell/Host/HostStartOptions.cs
+++ b/src/PowerShellEditorServices/Services/PowerShell/Host/HostStartOptions.cs
@@ -9,6 +9,6 @@ internal struct HostStartOptions
public string InitialWorkingDirectory { get; set; }
- public bool ShellIntegrationEnabled { get; set; }
+ public string ShellIntegrationScript { get; set; }
}
}
diff --git a/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs b/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs
index c921de81b..48ba1c27c 100644
--- a/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs
+++ b/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs
@@ -29,9 +29,7 @@ namespace Microsoft.PowerShell.EditorServices.Services.PowerShell.Host
using Microsoft.PowerShell.EditorServices.Server;
using OmniSharp.Extensions.DebugAdapter.Protocol.Server;
-#pragma warning disable CA1506 // Coupling complexity we don't care about
internal class PsesInternalHost : PSHost, IHostSupportsInteractiveSession, IRunspaceContext, IInternalPowerShellExecutionService
-#pragma warning restore CA1506
{
internal const string DefaultPrompt = "> ";
@@ -308,23 +306,44 @@ public async Task TryStartAsync(HostStartOptions startOptions, Cancellatio
_logger.LogDebug("InitialWorkingDirectory set!");
}
+ _logger.LogDebug("Setting profile variable...");
+ await SetProfileVariableAsync(cancellationToken).ConfigureAwait(false);
+ _logger.LogDebug("Profile variable set!");
+
if (startOptions.LoadProfiles)
{
_logger.LogDebug("Loading profiles...");
await LoadHostProfilesAsync(cancellationToken).ConfigureAwait(false);
_logger.LogDebug("Profiles loaded!");
}
+ else
+ {
+ _logger.LogDebug("Profile loading skipped per configuration!");
+ }
- if (startOptions.ShellIntegrationEnabled)
+ if (!string.IsNullOrEmpty(startOptions.ShellIntegrationScript))
{
- _logger.LogDebug("Enabling shell integration...");
+ _logger.LogDebug("Enabling Terminal Shell Integration...");
_shellIntegrationEnabled = true;
- await EnableShellIntegrationAsync(cancellationToken).ConfigureAwait(false);
+ string sourceMethod = startOptions.ShellIntegrationScript.EndsWith(".ps1") ? "." : "Import-Module";
+ // TODO: Make the __psEditorServices prefix shared (it's used elsewhere too).
+ string setupShellIntegration = $$"""
+ # Setup Terminal Shell Integration.
+
+ # Define a fake PSConsoleHostReadLine so the integration script's wrapper
+ # can execute it to get the user's input.
+ $global:__psEditorServices_userInput = "";
+ function global:PSConsoleHostReadLine { $global:__psEditorServices_userInput }
+
+ # Execute the provided shell integration script.
+ try { {{sourceMethod}} '{{startOptions.ShellIntegrationScript}}' } catch {}
+ """;
+ await EnableShellIntegrationAsync(setupShellIntegration, cancellationToken).ConfigureAwait(false);
_logger.LogDebug("Shell integration enabled!");
}
else
{
- _logger.LogDebug("Shell integration not enabled!");
+ _logger.LogDebug("Terminal Shell Integration not enabled!");
}
await _started.Task.ConfigureAwait(false);
@@ -495,6 +514,7 @@ public Task ExecuteDelegateAsync(
new SynchronousDelegateTask(_logger, representation, executionOptions, action, cancellationToken));
}
+ // TODO: One day fix these so the cancellation token is last.
public Task> ExecutePSCommandAsync(
PSCommand psCommand,
CancellationToken cancellationToken,
@@ -571,219 +591,44 @@ internal void DisableTranscribeOnly()
}
}
+ internal Task SetProfileVariableAsync(CancellationToken cancellationToken)
+ {
+ // If the CurrentUserCurrentHost profile is null then we cannot create the profile variable
+ if (_hostInfo.ProfilePaths.CurrentUserCurrentHost is null)
+ {
+ return Task.CompletedTask;
+ }
+
+ // NOTE: This is a special task run on startup!
+ return ExecuteDelegateAsync(
+ "SetProfileVariable",
+ executionOptions: null,
+ (pwsh, _) => pwsh.SetProfileVariable(_hostInfo.ProfilePaths),
+ cancellationToken);
+ }
+
internal Task LoadHostProfilesAsync(CancellationToken cancellationToken)
{
+ // If the CurrentUserCurrentHost profile is null then we cannot instantiate
+ if (_hostInfo.ProfilePaths.CurrentUserCurrentHost is null)
+ {
+ return Task.CompletedTask;
+ }
+
// NOTE: This is a special task run on startup!
return ExecuteDelegateAsync(
"LoadProfiles",
executionOptions: null,
- (pwsh, _) => pwsh.LoadProfiles(_hostInfo.ProfilePaths),
+ (pwsh, _) => pwsh.LoadProfileScripts(_hostInfo.ProfilePaths),
cancellationToken);
}
- private Task EnableShellIntegrationAsync(CancellationToken cancellationToken)
+ private Task EnableShellIntegrationAsync(string shellIntegrationScript, CancellationToken cancellationToken)
{
- // Imported on 01/03/24 from
- // https://github.com/microsoft/vscode/blob/main/src/vs/workbench/contrib/terminal/browser/media/shellIntegration.ps1
- // with quotes escaped, `__VSCodeOriginalPSConsoleHostReadLine` removed (as it's done
- // in our own ReadLine function), and `[Console]::Write` replaced with `Write-Host`.
- const string shellIntegrationScript = @"
-# Prevent installing more than once per session
-if (Test-Path variable:global:__VSCodeOriginalPrompt) {
- return;
-}
-
-# Disable shell integration when the language mode is restricted
-if ($ExecutionContext.SessionState.LanguageMode -ne ""FullLanguage"") {
- return;
-}
-
-$Global:__VSCodeOriginalPrompt = $function:Prompt
-
-$Global:__LastHistoryId = -1
-
-# Store the nonce in script scope and unset the global
-$Nonce = $env:VSCODE_NONCE
-$env:VSCODE_NONCE = $null
-
-if ($env:VSCODE_ENV_REPLACE) {
- $Split = $env:VSCODE_ENV_REPLACE.Split("":"")
- foreach ($Item in $Split) {
- $Inner = $Item.Split('=')
- [Environment]::SetEnvironmentVariable($Inner[0], $Inner[1].Replace('\x3a', ':'))
- }
- $env:VSCODE_ENV_REPLACE = $null
-}
-if ($env:VSCODE_ENV_PREPEND) {
- $Split = $env:VSCODE_ENV_PREPEND.Split("":"")
- foreach ($Item in $Split) {
- $Inner = $Item.Split('=')
- [Environment]::SetEnvironmentVariable($Inner[0], $Inner[1].Replace('\x3a', ':') + [Environment]::GetEnvironmentVariable($Inner[0]))
- }
- $env:VSCODE_ENV_PREPEND = $null
-}
-if ($env:VSCODE_ENV_APPEND) {
- $Split = $env:VSCODE_ENV_APPEND.Split("":"")
- foreach ($Item in $Split) {
- $Inner = $Item.Split('=')
- [Environment]::SetEnvironmentVariable($Inner[0], [Environment]::GetEnvironmentVariable($Inner[0]) + $Inner[1].Replace('\x3a', ':'))
- }
- $env:VSCODE_ENV_APPEND = $null
-}
-
-function Global:__VSCode-Escape-Value([string]$value) {
- # NOTE: In PowerShell v6.1+, this can be written `$value -replace '…', { … }` instead of `[regex]::Replace`.
- # Replace any non-alphanumeric characters.
- [regex]::Replace($value, '[\\\n;]', { param($match)
- # Encode the (ascii) matches as `\x`
- -Join (
- [System.Text.Encoding]::UTF8.GetBytes($match.Value) | ForEach-Object { '\x{0:x2}' -f $_ }
- )
- })
-}
-
-function Global:Prompt() {
- $FakeCode = [int]!$global:?
- # NOTE: We disable strict mode for the scope of this function because it unhelpfully throws an
- # error when $LastHistoryEntry is null, and is not otherwise useful.
- Set-StrictMode -Off
- $LastHistoryEntry = Get-History -Count 1
- # Skip finishing the command if the first command has not yet started
- if ($Global:__LastHistoryId -ne -1) {
- if ($LastHistoryEntry.Id -eq $Global:__LastHistoryId) {
- # Don't provide a command line or exit code if there was no history entry (eg. ctrl+c, enter on no command)
- $Result = ""$([char]0x1b)]633;E`a""
- $Result += ""$([char]0x1b)]633;D`a""
- }
- else {
- # Command finished command line
- # OSC 633 ; E ; ; ST
- $Result = ""$([char]0x1b)]633;E;""
- # Sanitize the command line to ensure it can get transferred to the terminal and can be parsed
- # correctly. This isn't entirely safe but good for most cases, it's important for the Pt parameter
- # to only be composed of _printable_ characters as per the spec.
- if ($LastHistoryEntry.CommandLine) {
- $CommandLine = $LastHistoryEntry.CommandLine
- }
- else {
- $CommandLine = """"
- }
- $Result += $(__VSCode-Escape-Value $CommandLine)
- $Result += "";$Nonce""
- $Result += ""`a""
- # Command finished exit code
- # OSC 633 ; D [; ] ST
- $Result += ""$([char]0x1b)]633;D;$FakeCode`a""
- }
- }
- # Prompt started
- # OSC 633 ; A ST
- $Result += ""$([char]0x1b)]633;A`a""
- # Current working directory
- # OSC 633 ; = ST
- $Result += if ($pwd.Provider.Name -eq 'FileSystem') { ""$([char]0x1b)]633;P;Cwd=$(__VSCode-Escape-Value $pwd.ProviderPath)`a"" }
- # Before running the original prompt, put $? back to what it was:
- if ($FakeCode -ne 0) {
- Write-Error ""failure"" -ea ignore
- }
- # Run the original prompt
- $Result += $Global:__VSCodeOriginalPrompt.Invoke()
- # Write command started
- $Result += ""$([char]0x1b)]633;B`a""
- $Global:__LastHistoryId = $LastHistoryEntry.Id
- return $Result
-}
-
-# Set IsWindows property
-if ($PSVersionTable.PSVersion -lt ""6.0"") {
- # Windows PowerShell is only available on Windows
- Write-Host -NoNewLine ""$([char]0x1b)]633;P;IsWindows=$true`a""
-}
-else {
- Write-Host -NoNewLine ""$([char]0x1b)]633;P;IsWindows=$IsWindows`a""
-}
-
-# Set always on key handlers which map to default VS Code keybindings
-function Set-MappedKeyHandler {
- param ([string[]] $Chord, [string[]]$Sequence)
- try {
- $Handler = Get-PSReadLineKeyHandler -Chord $Chord | Select-Object -First 1
- }
- catch [System.Management.Automation.ParameterBindingException] {
- # PowerShell 5.1 ships with PSReadLine 2.0.0 which does not have -Chord,
- # so we check what's bound and filter it.
- $Handler = Get-PSReadLineKeyHandler -Bound | Where-Object -FilterScript { $_.Key -eq $Chord } | Select-Object -First 1
- }
- if ($Handler) {
- Set-PSReadLineKeyHandler -Chord $Sequence -Function $Handler.Function
- }
-}
-
-$Global:__VSCodeHaltCompletions = $false
-function Set-MappedKeyHandlers {
- Set-MappedKeyHandler -Chord Ctrl+Spacebar -Sequence 'F12,a'
- Set-MappedKeyHandler -Chord Alt+Spacebar -Sequence 'F12,b'
- Set-MappedKeyHandler -Chord Shift+Enter -Sequence 'F12,c'
- Set-MappedKeyHandler -Chord Shift+End -Sequence 'F12,d'
-
- # Conditionally enable suggestions
- if ($env:VSCODE_SUGGEST -eq '1') {
- Remove-Item Env:VSCODE_SUGGEST
-
- # VS Code send completions request (may override Ctrl+Spacebar)
- Set-PSReadLineKeyHandler -Chord 'F12,e' -ScriptBlock {
- Send-Completions
- }
-
- # Suggest trigger characters
- Set-PSReadLineKeyHandler -Chord ""-"" -ScriptBlock {
- [Microsoft.PowerShell.PSConsoleReadLine]::Insert(""-"")
- if (!$Global:__VSCodeHaltCompletions) {
- Send-Completions
- }
- }
-
- Set-PSReadLineKeyHandler -Chord 'F12,y' -ScriptBlock {
- $Global:__VSCodeHaltCompletions = $true
- }
-
- Set-PSReadLineKeyHandler -Chord 'F12,z' -ScriptBlock {
- $Global:__VSCodeHaltCompletions = $false
- }
- }
-}
-
-function Send-Completions {
- $commandLine = """"
- $cursorIndex = 0
- # TODO: Since fuzzy matching exists, should completions be provided only for character after the
- # last space and then filter on the client side? That would let you trigger ctrl+space
- # anywhere on a word and have full completions available
- [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$commandLine, [ref]$cursorIndex)
- $completionPrefix = $commandLine
-
- # Get completions
- $result = ""`e]633;Completions""
- if ($completionPrefix.Length -gt 0) {
- # Get and send completions
- $completions = TabExpansion2 -inputScript $completionPrefix -cursorColumn $cursorIndex
- if ($null -ne $completions.CompletionMatches) {
- $result += "";$($completions.ReplacementIndex);$($completions.ReplacementLength);$($cursorIndex);""
- $result += $completions.CompletionMatches | ConvertTo-Json -Compress
- }
- }
- $result += ""`a""
-
- Write-Host -NoNewLine $result
-}
-
-# Register key handlers if PSReadLine is available
-if (Get-Module -Name PSReadLine) {
- Set-MappedKeyHandlers
-}
- ";
-
- return ExecutePSCommandAsync(new PSCommand().AddScript(shellIntegrationScript), cancellationToken);
+ return ExecutePSCommandAsync(
+ new PSCommand().AddScript(shellIntegrationScript),
+ cancellationToken,
+ new PowerShellExecutionOptions { AddToHistory = false, ThrowOnError = false });
}
public Task SetInitialWorkingDirectoryAsync(string path, CancellationToken cancellationToken)
@@ -997,8 +842,9 @@ private void RunTopLevelExecutionLoop()
{
// Make sure we execute any startup tasks first. These should be, in order:
// 1. Delegate to register psEditor variable
- // 2. LoadProfiles delegate
- // 3. Delegate to import PSEditModule
+ // 2. SetProfileVariable delegate
+ // 3. Optional LoadProfiles delegate
+ // 4. Delegate to import PSEditModule
while (_taskQueue.TryTake(out ISynchronousTask task))
{
task.ExecuteSynchronously(CancellationToken.None);
@@ -1262,16 +1108,34 @@ private void InvokeInput(string input, CancellationToken cancellationToken)
try
{
- // For VS Code's shell integration feature, this replaces their
- // PSConsoleHostReadLine function wrapper, as that global function is not available
- // to users of PSES, since we already wrap ReadLine ourselves.
+ // For the terminal shell integration feature, we call PSConsoleHostReadLine specially as it's been wrapped.
+ // Normally it would not be available (since we wrap ReadLine ourselves),
+ // but in this case we've made the original just emit the user's input so that the wrapper works as intended.
if (_shellIntegrationEnabled)
{
- System.Console.Write("\x1b]633;C\a");
+ // Save the user's input to our special global variable so PSConsoleHostReadLine can read it.
+ InvokePSCommand(
+ new PSCommand().AddScript("$global:__psEditorServices_userInput = $args[0]").AddArgument(input),
+ new PowerShellExecutionOptions { ThrowOnError = false, WriteOutputToHost = false },
+ cancellationToken);
+
+ // Invoke the PSConsoleHostReadLine wrapper. We don't write the output because it
+ // returns the command line (user input) which would then be duplicate noise. Fortunately
+ // it writes the shell integration sequences directly using [Console]::Write.
+ InvokePSCommand(
+ new PSCommand().AddScript("PSConsoleHostReadLine"),
+ new PowerShellExecutionOptions { ThrowOnError = false, WriteOutputToHost = false },
+ cancellationToken);
+
+ // Reset our global variable.
+ InvokePSCommand(
+ new PSCommand().AddScript("$global:__psEditorServices_userInput = \"\""),
+ new PowerShellExecutionOptions { ThrowOnError = false, WriteOutputToHost = false },
+ cancellationToken);
}
InvokePSCommand(
- new PSCommand().AddScript(input, useLocalScope: false),
+ new PSCommand().AddScript(input),
new PowerShellExecutionOptions
{
AddToHistory = true,
diff --git a/src/PowerShellEditorServices/Services/PowerShell/Refactoring/Exceptions.cs b/src/PowerShellEditorServices/Services/PowerShell/Refactoring/Exceptions.cs
new file mode 100644
index 000000000..c286963a6
--- /dev/null
+++ b/src/PowerShellEditorServices/Services/PowerShell/Refactoring/Exceptions.cs
@@ -0,0 +1,40 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+namespace Microsoft.PowerShell.EditorServices.Refactoring
+{
+ internal class TargetSymbolNotFoundException : Exception
+ {
+ public TargetSymbolNotFoundException()
+ {
+ }
+
+ public TargetSymbolNotFoundException(string message)
+ : base(message)
+ {
+ }
+
+ public TargetSymbolNotFoundException(string message, Exception inner)
+ : base(message, inner)
+ {
+ }
+ }
+
+ internal class FunctionDefinitionNotFoundException : Exception
+ {
+ public FunctionDefinitionNotFoundException()
+ {
+ }
+
+ public FunctionDefinitionNotFoundException(string message)
+ : base(message)
+ {
+ }
+
+ public FunctionDefinitionNotFoundException(string message, Exception inner)
+ : base(message, inner)
+ {
+ }
+ }
+}
diff --git a/src/PowerShellEditorServices/Services/PowerShell/Utility/PowerShellExtensions.cs b/src/PowerShellEditorServices/Services/PowerShell/Utility/PowerShellExtensions.cs
index f7ef51ab9..f24ae98bc 100644
--- a/src/PowerShellEditorServices/Services/PowerShell/Utility/PowerShellExtensions.cs
+++ b/src/PowerShellEditorServices/Services/PowerShell/Utility/PowerShellExtensions.cs
@@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-
+#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
@@ -69,7 +69,7 @@ and not PSInvocationState.Failed
pwsh.InvocationStateChanged += handler;
}
- public static Collection InvokeAndClear(this PowerShell pwsh, PSInvocationSettings invocationSettings = null)
+ public static Collection InvokeAndClear(this PowerShell pwsh, PSInvocationSettings? invocationSettings = null)
{
try
{
@@ -81,7 +81,7 @@ public static Collection InvokeAndClear(this PowerShell pwsh,
}
}
- public static void InvokeAndClear(this PowerShell pwsh, PSInvocationSettings invocationSettings = null)
+ public static void InvokeAndClear(this PowerShell pwsh, PSInvocationSettings? invocationSettings = null)
{
try
{
@@ -93,13 +93,13 @@ public static void InvokeAndClear(this PowerShell pwsh, PSInvocationSettings inv
}
}
- public static Collection InvokeCommand(this PowerShell pwsh, PSCommand psCommand, PSInvocationSettings invocationSettings = null)
+ public static Collection InvokeCommand(this PowerShell pwsh, PSCommand psCommand, PSInvocationSettings? invocationSettings = null)
{
pwsh.Commands = psCommand;
return pwsh.InvokeAndClear(invocationSettings);
}
- public static void InvokeCommand(this PowerShell pwsh, PSCommand psCommand, PSInvocationSettings invocationSettings = null)
+ public static void InvokeCommand(this PowerShell pwsh, PSCommand psCommand, PSInvocationSettings? invocationSettings = null)
{
pwsh.Commands = psCommand;
pwsh.InvokeAndClear(invocationSettings);
@@ -193,7 +193,7 @@ public static void SetCorrectExecutionPolicy(this PowerShell pwsh, ILogger logge
}
}
- public static void LoadProfiles(this PowerShell pwsh, ProfilePathInfo profilePaths)
+ public static void SetProfileVariable(this PowerShell pwsh, ProfilePathInfo profilePaths)
{
// Per the documentation, "the `$PROFILE` variable stores the path to the 'Current User,
// Current Host' profile. The other profiles are saved in note properties of the
@@ -202,15 +202,24 @@ public static void LoadProfiles(this PowerShell pwsh, ProfilePathInfo profilePat
// https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_profiles?view=powershell-7.1#the-profile-variable
PSObject profileVariable = PSObject.AsPSObject(profilePaths.CurrentUserCurrentHost);
+ profileVariable.Members.Add(new PSNoteProperty(nameof(profilePaths.AllUsersAllHosts), profilePaths.AllUsersAllHosts));
+ profileVariable.Members.Add(new PSNoteProperty(nameof(profilePaths.AllUsersCurrentHost), profilePaths.AllUsersCurrentHost));
+ profileVariable.Members.Add(new PSNoteProperty(nameof(profilePaths.CurrentUserAllHosts), profilePaths.CurrentUserAllHosts));
+ profileVariable.Members.Add(new PSNoteProperty(nameof(profilePaths.CurrentUserCurrentHost), profilePaths.CurrentUserCurrentHost));
+
+ pwsh.Runspace.SessionStateProxy.SetVariable("PROFILE", profileVariable);
+ }
+
+ public static void LoadProfileScripts(this PowerShell pwsh, ProfilePathInfo profilePaths)
+ {
+ PSObject profileVariable = PSObject.AsPSObject(profilePaths.CurrentUserCurrentHost);
+
PSCommand psCommand = new PSCommand()
.AddProfileLoadIfExists(profileVariable, nameof(profilePaths.AllUsersAllHosts), profilePaths.AllUsersAllHosts)
.AddProfileLoadIfExists(profileVariable, nameof(profilePaths.AllUsersCurrentHost), profilePaths.AllUsersCurrentHost)
.AddProfileLoadIfExists(profileVariable, nameof(profilePaths.CurrentUserAllHosts), profilePaths.CurrentUserAllHosts)
.AddProfileLoadIfExists(profileVariable, nameof(profilePaths.CurrentUserCurrentHost), profilePaths.CurrentUserCurrentHost);
- // NOTE: This must be set before the profiles are loaded.
- pwsh.Runspace.SessionStateProxy.SetVariable("PROFILE", profileVariable);
-
// NOTE: Because it's possible there are no profiles defined, we might have an empty
// command. Since this is being executed directly, we can't rely on `ThrowOnError =
// false` to avoid an exception here. Instead, we must just not execute it.
@@ -253,7 +262,7 @@ private static StringBuilder AddErrorString(this StringBuilder sb, ErrorRecord e
.AppendLine("Exception:")
.Append(" ").Append(error.Exception.ToString() ?? "");
- Exception innerException = error.Exception?.InnerException;
+ Exception? innerException = error.Exception?.InnerException;
while (innerException != null)
{
sb.AppendLine("InnerException:")
diff --git a/src/PowerShellEditorServices/Services/Template/Handlers/ITemplateHandlers.cs b/src/PowerShellEditorServices/Services/Template/Handlers/ITemplateHandlers.cs
deleted file mode 100644
index 88ae40789..000000000
--- a/src/PowerShellEditorServices/Services/Template/Handlers/ITemplateHandlers.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using MediatR;
-using OmniSharp.Extensions.JsonRpc;
-
-namespace Microsoft.PowerShell.EditorServices.Services.Template
-{
- [Serial]
- [Method("powerShell/getProjectTemplates", Direction.ClientToServer)]
- internal interface IGetProjectTemplatesHandler : IJsonRpcRequestHandler { }
-
- [Serial]
- [Method("powerShell/newProjectFromTemplate", Direction.ClientToServer)]
- internal interface INewProjectFromTemplateHandler : IJsonRpcRequestHandler { }
-
- internal class GetProjectTemplatesRequest : IRequest
- {
- public bool IncludeInstalledModules { get; set; }
- }
-
- internal class GetProjectTemplatesResponse
- {
- public bool NeedsModuleInstall { get; set; }
-
- public TemplateDetails[] Templates { get; set; }
- }
-
- ///
- /// Provides details about a file or project template.
- ///
- internal class TemplateDetails
- {
- ///
- /// Gets or sets the title of the template.
- ///
- public string Title { get; set; }
-
- ///
- /// Gets or sets the author of the template.
- ///
- public string Author { get; set; }
-
- ///
- /// Gets or sets the version of the template.
- ///
- public string Version { get; set; }
-
- ///
- /// Gets or sets the description of the template.
- ///
- public string Description { get; set; }
-
- ///
- /// Gets or sets the template's comma-delimited string of tags.
- ///
- public string Tags { get; set; }
-
- ///
- /// Gets or sets the template's folder path.
- ///
- public string TemplatePath { get; set; }
- }
-
- internal class NewProjectFromTemplateRequest : IRequest
- {
- public string DestinationPath { get; set; }
-
- public string TemplatePath { get; set; }
- }
-
- internal class NewProjectFromTemplateResponse
- {
- public bool CreationSuccessful { get; set; }
- }
-}
diff --git a/src/PowerShellEditorServices/Services/Template/Handlers/TemplateHandlers.cs b/src/PowerShellEditorServices/Services/Template/Handlers/TemplateHandlers.cs
deleted file mode 100644
index 685fda762..000000000
--- a/src/PowerShellEditorServices/Services/Template/Handlers/TemplateHandlers.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.Extensions.Logging;
-using Microsoft.PowerShell.EditorServices.Logging;
-
-namespace Microsoft.PowerShell.EditorServices.Services.Template
-{
- internal class TemplateHandlers : IGetProjectTemplatesHandler, INewProjectFromTemplateHandler
- {
- private readonly ILogger _logger;
- private readonly TemplateService _templateService;
-
- public TemplateHandlers(
- ILoggerFactory factory,
- TemplateService templateService)
- {
- _logger = factory.CreateLogger();
- _templateService = templateService;
- }
-
- public async Task Handle(GetProjectTemplatesRequest request, CancellationToken cancellationToken)
- {
- bool plasterInstalled = await _templateService.ImportPlasterIfInstalledAsync().ConfigureAwait(false);
-
- if (plasterInstalled)
- {
- TemplateDetails[] availableTemplates =
- await _templateService.GetAvailableTemplatesAsync(
- request.IncludeInstalledModules).ConfigureAwait(false);
-
- return new GetProjectTemplatesResponse
- {
- Templates = availableTemplates
- };
- }
-
- return new GetProjectTemplatesResponse
- {
- NeedsModuleInstall = true,
- Templates = Array.Empty()
- };
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Want to log any exception")]
- public async Task Handle(NewProjectFromTemplateRequest request, CancellationToken cancellationToken)
- {
- bool creationSuccessful;
- try
- {
- await _templateService.CreateFromTemplateAsync(request.TemplatePath, request.DestinationPath).ConfigureAwait(false);
- creationSuccessful = true;
- }
- catch (Exception e)
- {
- // We don't really care if this worked or not but we report status.
- _logger.LogException("New plaster template failed.", e);
- creationSuccessful = false;
- }
-
- return new NewProjectFromTemplateResponse
- {
- CreationSuccessful = creationSuccessful
- };
- }
- }
-}
diff --git a/src/PowerShellEditorServices/Services/Template/TemplateService.cs b/src/PowerShellEditorServices/Services/Template/TemplateService.cs
deleted file mode 100644
index e7295ec8c..000000000
--- a/src/PowerShellEditorServices/Services/Template/TemplateService.cs
+++ /dev/null
@@ -1,206 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using Microsoft.Extensions.Logging;
-using Microsoft.PowerShell.EditorServices.Services.PowerShell;
-using Microsoft.PowerShell.EditorServices.Services.PowerShell.Execution;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Management.Automation;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace Microsoft.PowerShell.EditorServices.Services.Template
-{
- ///
- /// Provides a service for listing PowerShell project templates and creating
- /// new projects from those templates. This service leverages the Plaster
- /// module for creating projects from templates.
- ///
- internal class TemplateService
- {
- #region Private Fields
-
- private readonly ILogger _logger;
- private bool isPlasterLoaded;
- private bool? isPlasterInstalled;
- private readonly IInternalPowerShellExecutionService _executionService;
-
- #endregion
-
- #region Constructors
-
- ///
- /// Creates a new instance of the TemplateService class.
- ///
- /// The PowerShellContext to use for this service.
- /// An ILoggerFactory implementation used for writing log messages.
- public TemplateService(IInternalPowerShellExecutionService executionService, ILoggerFactory factory)
- {
- _logger = factory.CreateLogger();
- _executionService = executionService;
- }
-
- #endregion
-
- #region Public Methods
-
- ///
- /// Checks if Plaster is installed on the user's machine.
- ///
- /// A Task that can be awaited until the check is complete. The result will be true if Plaster is installed.
- public async Task ImportPlasterIfInstalledAsync()
- {
- if (!isPlasterInstalled.HasValue)
- {
- PSCommand psCommand = new();
-
- psCommand
- .AddCommand("Get-Module")
- .AddParameter("ListAvailable")
- .AddParameter("Name", "Plaster");
-
- psCommand
- .AddCommand("Sort-Object")
- .AddParameter("Descending")
- .AddParameter("Property", "Version");
-
- psCommand
- .AddCommand("Select-Object")
- .AddParameter("First", 1);
-
- _logger.LogTrace("Checking if Plaster is installed...");
-
- IReadOnlyList moduleObject =
- await _executionService.ExecutePSCommandAsync(
- psCommand,
- CancellationToken.None,
- new PowerShellExecutionOptions { ThrowOnError = false })
- .ConfigureAwait(false);
-
- isPlasterInstalled = moduleObject.Count > 0;
- _logger.LogTrace("Plaster installed: " + isPlasterInstalled.Value);
-
- // Attempt to load plaster
- if (isPlasterInstalled.Value && !isPlasterLoaded)
- {
- _logger.LogTrace("Loading Plaster...");
-
- psCommand = new PSCommand();
- psCommand
- .AddCommand(@"Microsoft.PowerShell.Core\Import-Module")
- .AddParameter("ModuleInfo", (PSModuleInfo)moduleObject[0].ImmediateBaseObject)
- .AddParameter("PassThru")
- .AddParameter("ErrorAction", ActionPreference.Ignore);
-
- IReadOnlyList plasterModule =
- await _executionService.ExecutePSCommandAsync(
- psCommand,
- CancellationToken.None,
- new PowerShellExecutionOptions { ThrowOnError = false })
- .ConfigureAwait(false);
-
- isPlasterLoaded = plasterModule.Count > 0;
- _logger.LogTrace("Plaster loaded: " + isPlasterLoaded);
- }
- }
-
- return isPlasterInstalled.Value;
- }
-
- ///
- /// Gets the available file or project templates on the user's
- /// machine.
- ///
- ///
- /// If true, searches the user's installed PowerShell modules for
- /// included templates.
- ///
- /// A Task which can be awaited for the TemplateDetails list to be returned.
- public async Task GetAvailableTemplatesAsync(
- bool includeInstalledModules)
- {
- if (!isPlasterLoaded)
- {
- throw new InvalidOperationException("Plaster is not loaded, templates cannot be accessed.");
- }
-
- PSCommand psCommand = new();
- psCommand.AddCommand("Get-PlasterTemplate");
-
- if (includeInstalledModules)
- {
- psCommand.AddParameter("IncludeModules");
- }
-
- IReadOnlyList templateObjects = await _executionService.ExecutePSCommandAsync(
- psCommand,
- CancellationToken.None).ConfigureAwait(false);
-
- _logger.LogTrace($"Found {templateObjects.Count} Plaster templates");
-
- return
- templateObjects
- .Select(CreateTemplateDetails)
- .ToArray();
- }
-
- ///
- /// Creates a new file or project from a specified template and
- /// places it in the destination path. This ultimately calls
- /// Invoke-Plaster in PowerShell.
- ///
- /// The folder path containing the template.
- /// The folder path where the files will be created.
- /// A boolean-returning Task which communicates success or failure.
- public async Task CreateFromTemplateAsync(
- string templatePath,
- string destinationPath)
- {
- _logger.LogTrace(
- $"Invoking Plaster...\n\n TemplatePath: {templatePath}\n DestinationPath: {destinationPath}");
-
- PSCommand command = new PSCommand()
- .AddCommand("Invoke-Plaster")
- .AddParameter("TemplatePath", templatePath)
- .AddParameter("DestinationPath", destinationPath);
-
- // This command is interactive so it requires the foreground.
- await _executionService.ExecutePSCommandAsync(
- command,
- CancellationToken.None,
- new PowerShellExecutionOptions
- {
- RequiresForeground = true,
- WriteOutputToHost = true,
- ThrowOnError = false
- }).ConfigureAwait(false);
-
- // If any errors were written out, creation was not successful
- return true;
- }
-
- #endregion
-
- #region Private Methods
-
- private static TemplateDetails CreateTemplateDetails(PSObject psObject)
- {
- return new TemplateDetails
- {
- Title = psObject.Members["Title"].Value as string,
- Author = psObject.Members["Author"].Value as string,
- Version = psObject.Members["Version"].Value.ToString(),
- Description = psObject.Members["Description"].Value as string,
- TemplatePath = psObject.Members["TemplatePath"].Value as string,
- Tags =
- psObject.Members["Tags"].Value is object[] tags
- ? string.Join(", ", tags)
- : string.Empty
- };
- }
-
- #endregion
- }
-}
diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs
index 29e36ce25..8dbb8f798 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs
@@ -327,15 +327,15 @@ CompletionResultType.ProviderItem or CompletionResultType.ProviderContainer
Data = item.Detail,
Detail = SupportsMarkdown ? null : item.Detail,
},
- CompletionResultType.ParameterName => TryExtractType(detail, out string type)
- ? item with { Kind = CompletionItemKind.Variable, Detail = type }
+ CompletionResultType.ParameterName => TryExtractType(detail, item.Label, out string type, out string documentation)
+ ? item with { Kind = CompletionItemKind.Variable, Detail = type, Documentation = documentation }
// The comparison operators (-eq, -not, -gt, etc) unfortunately come across as
// ParameterName types but they don't have a type associated to them, so we can
// deduce it is an operator.
: item with { Kind = CompletionItemKind.Operator },
CompletionResultType.ParameterValue => item with { Kind = CompletionItemKind.Value },
- CompletionResultType.Variable => TryExtractType(detail, out string type)
- ? item with { Kind = CompletionItemKind.Variable, Detail = type }
+ CompletionResultType.Variable => TryExtractType(detail, "$" + item.Label, out string type, out string documentation)
+ ? item with { Kind = CompletionItemKind.Variable, Detail = type, Documentation = documentation }
: item with { Kind = CompletionItemKind.Variable },
CompletionResultType.Namespace => item with { Kind = CompletionItemKind.Module },
CompletionResultType.Type => detail.StartsWith("Class ", StringComparison.CurrentCulture)
@@ -366,7 +366,7 @@ private CompletionItem CreateProviderItemCompletion(
if (textToBeReplaced.IndexOf(PSScriptRootVariable, StringComparison.OrdinalIgnoreCase) is int variableIndex and not -1
&& System.IO.Path.GetDirectoryName(scriptFile.FilePath) is string scriptFolder and not ""
&& completionText.IndexOf(scriptFolder, StringComparison.OrdinalIgnoreCase) is int pathIndex and not -1
- && !scriptFile.IsInMemory)
+ && !scriptFile.IsUntitled)
{
completionText = completionText
.Remove(pathIndex, scriptFolder.Length)
@@ -450,16 +450,45 @@ private static string GetTypeFilterText(string textToBeReplaced, string completi
/// type names in [] to be consistent with PowerShell syntax and how the debugger displays
/// type names.
///
- ///
- ///
+ /// The tooltip text to parse
+ /// The extracted type string, if found
+ /// The remaining text after the type, if any
+ /// The label to check for in the documentation prefix
/// Whether or not the type was found.
- private static bool TryExtractType(string toolTipText, out string type)
+ internal static bool TryExtractType(string toolTipText, string label, out string type, out string documentation)
{
MatchCollection matches = s_typeRegex.Matches(toolTipText);
type = string.Empty;
+ documentation = null; //We use null instead of String.Empty to indicate no documentation was found.
+
if ((matches.Count > 0) && (matches[0].Groups.Count > 1))
{
type = matches[0].Groups[1].Value;
+
+ // Extract the description as everything after the type
+ if (matches[0].Length < toolTipText.Length)
+ {
+ documentation = toolTipText.Substring(matches[0].Length).Trim();
+
+ if (documentation is not null)
+ {
+ // If the substring is the same as the label, documentation should remain blank
+ if (documentation.Equals(label, StringComparison.OrdinalIgnoreCase))
+ {
+ documentation = null;
+ }
+ // If the documentation starts with "label - ", remove this prefix
+ else if (documentation.StartsWith(label + " - ", StringComparison.OrdinalIgnoreCase))
+ {
+ documentation = documentation.Substring((label + " - ").Length).Trim();
+ }
+ }
+ if (string.IsNullOrWhiteSpace(documentation))
+ {
+ documentation = null;
+ }
+ }
+
return true;
}
return false;
diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DidChangeWatchedFilesHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DidChangeWatchedFilesHandler.cs
index edbe9b0ad..aa4c0a969 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/DidChangeWatchedFilesHandler.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/DidChangeWatchedFilesHandler.cs
@@ -41,6 +41,7 @@ public DidChangeWatchedFilesHandler(
public DidChangeWatchedFilesRegistrationOptions GetRegistrationOptions(
DidChangeWatchedFilesCapability capability,
ClientCapabilities clientCapabilities)
+#pragma warning disable CS8601 // Possible null reference assignment (it's from the library).
=> new()
{
Watchers = new[]
@@ -52,6 +53,7 @@ public DidChangeWatchedFilesRegistrationOptions GetRegistrationOptions(
},
},
};
+#pragma warning restore CS8601 // Possible null reference assignment.
public Task Handle(DidChangeWatchedFilesParams request, CancellationToken cancellationToken)
{
diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/FormattingHandlers.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/FormattingHandlers.cs
index 64ccb3156..bf5f99d0f 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/FormattingHandlers.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/FormattingHandlers.cs
@@ -90,7 +90,7 @@ public override async Task Handle(DocumentFormattingParams re
return s_emptyTextEditContainer;
}
- return new TextEditContainer(new TextEdit
+ return new TextEditContainer(new OmniSharp.Extensions.LanguageServer.Protocol.Models.TextEdit
{
NewText = formattedScript,
Range = editRange
@@ -184,7 +184,7 @@ public override async Task Handle(DocumentRangeFormattingPara
return s_emptyTextEditContainer;
}
- return new TextEditContainer(new TextEdit
+ return new TextEditContainer(new OmniSharp.Extensions.LanguageServer.Protocol.Models.TextEdit
{
NewText = formattedScript,
Range = editRange
diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/PsesSemanticTokensHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/PsesSemanticTokensHandler.cs
index e5e69e60f..494843bb5 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/PsesSemanticTokensHandler.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/PsesSemanticTokensHandler.cs
@@ -108,6 +108,11 @@ private static SemanticTokenType MapSemanticTokenType(Token token)
return SemanticTokenType.Operator;
}
+ if ((token.TokenFlags & TokenFlags.AttributeName) != 0)
+ {
+ return SemanticTokenType.Decorator;
+ }
+
if ((token.TokenFlags & TokenFlags.TypeName) != 0)
{
return SemanticTokenType.Type;
@@ -142,8 +147,8 @@ private static SemanticTokenType MapSemanticTokenType(Token token)
case TokenKind.Number:
return SemanticTokenType.Number;
- case TokenKind.Generic:
- return SemanticTokenType.Function;
+ case TokenKind.Label:
+ return SemanticTokenType.Label;
}
return null;
diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/RenameHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/RenameHandler.cs
new file mode 100644
index 000000000..83e2b5ea1
--- /dev/null
+++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/RenameHandler.cs
@@ -0,0 +1,41 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#nullable enable
+
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.PowerShell.EditorServices.Services;
+
+using OmniSharp.Extensions.LanguageServer.Protocol.Document;
+using OmniSharp.Extensions.LanguageServer.Protocol.Models;
+using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
+
+namespace Microsoft.PowerShell.EditorServices.Handlers;
+
+///
+/// A handler for textDocument/prepareRename
+///
+internal class PrepareRenameHandler
+(
+ RenameService renameService
+) : IPrepareRenameHandler
+{
+ public RenameRegistrationOptions GetRegistrationOptions(RenameCapability capability, ClientCapabilities clientCapabilities) => capability.PrepareSupport ? new() { PrepareProvider = true } : new();
+
+ public async Task Handle(PrepareRenameParams request, CancellationToken cancellationToken)
+ => await renameService.PrepareRenameSymbol(request, cancellationToken).ConfigureAwait(false);
+}
+
+///
+/// A handler for textDocument/rename
+///
+internal class RenameHandler(
+ RenameService renameService
+) : IRenameHandler
+{
+ // RenameOptions may only be specified if the client states that it supports prepareSupport in its initial initialize request.
+ public RenameRegistrationOptions GetRegistrationOptions(RenameCapability capability, ClientCapabilities clientCapabilities) => capability.PrepareSupport ? new() { PrepareProvider = true } : new();
+
+ public async Task Handle(RenameParams request, CancellationToken cancellationToken)
+ => await renameService.RenameSymbol(request, cancellationToken).ConfigureAwait(false);
+}
diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs
index a02e7b884..ba2e9242b 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/TextDocumentHandler.cs
@@ -111,10 +111,11 @@ public override Task Handle(DidCloseTextDocumentParams notification, Cance
{
fileToClose.IsOpen = false;
- // If the file watcher is supported, only close in-memory files when this
+ // If the file watcher is supported, only close non-file-backed documents when this
// notification is triggered. This lets us keep workspace files open so we can scan
// for references. When a file is deleted, the file watcher will close the file.
- if (!_isFileWatcherSupported || fileToClose.IsInMemory)
+ bool isBackedByFile = !fileToClose.IsUntitled;
+ if (!_isFileWatcherSupported || !isBackedByFile)
{
_workspaceService.CloseFile(fileToClose);
}
@@ -132,6 +133,9 @@ public override async Task Handle(DidSaveTextDocumentParams notification,
if (savedFile != null)
{
+ // On a save, untitled files will remain in memory, so this won't change for those
+ savedFile.IsInMemory = savedFile.IsUntitled;
+
if (_remoteFileManagerService.IsUnderRemoteTempPath(savedFile.FilePath))
{
await _remoteFileManagerService.SaveRemoteFileAsync(savedFile.FilePath).ConfigureAwait(false);
diff --git a/src/PowerShellEditorServices/Services/TextDocument/RenameService.cs b/src/PowerShellEditorServices/Services/TextDocument/RenameService.cs
new file mode 100644
index 000000000..74802cf40
--- /dev/null
+++ b/src/PowerShellEditorServices/Services/TextDocument/RenameService.cs
@@ -0,0 +1,617 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#nullable enable
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Management.Automation.Language;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Configuration;
+using Microsoft.PowerShell.EditorServices.Handlers;
+using Microsoft.PowerShell.EditorServices.Language;
+using Microsoft.PowerShell.EditorServices.Refactoring;
+using Microsoft.PowerShell.EditorServices.Services.TextDocument;
+using OmniSharp.Extensions.LanguageServer.Protocol;
+using OmniSharp.Extensions.LanguageServer.Protocol.Models;
+using OmniSharp.Extensions.LanguageServer.Protocol.Server;
+
+namespace Microsoft.PowerShell.EditorServices.Services;
+
+///
+/// Used with Configuration Bind to sync the settings to what is set on the client.
+///
+internal class RenameServiceOptions
+{
+ public bool createParameterAlias { get; set; }
+ public bool acceptDisclaimer { get; set; }
+}
+
+internal interface IRenameService
+{
+ ///
+ /// Implementation of textDocument/prepareRename
+ ///
+ internal Task PrepareRenameSymbol(PrepareRenameParams prepareRenameParams, CancellationToken cancellationToken);
+
+ ///
+ /// Implementation of textDocument/rename
+ ///
+ internal Task RenameSymbol(RenameParams renameParams, CancellationToken cancellationToken);
+}
+
+///
+/// Providers service for renaming supported symbols such as functions and variables.
+///
+internal class RenameService(
+ WorkspaceService workspaceService,
+ ILanguageServerFacade lsp,
+ ILanguageServerConfiguration config
+) : IRenameService
+{
+ internal bool DisclaimerAcceptedForSession; //This is exposed to allow testing non-interactively
+ private bool DisclaimerDeclinedForSession;
+ private const string ConfigSection = "powershell.rename";
+
+ public async Task PrepareRenameSymbol(PrepareRenameParams request, CancellationToken cancellationToken)
+ {
+ RenameParams renameRequest = new()
+ {
+ NewName = "PREPARE_RENAME_UNUSED", //A placeholder just to gather edits
+ Position = request.Position,
+ TextDocument = request.TextDocument
+ };
+
+ // TODO: As a performance optimization, should we cache these results and just fetch them on the actual rename, and move the bulk to an implementation method? Seems pretty fast right now but may slow down on large documents. Need to add a large document test example.
+ WorkspaceEdit? renameResponse = await RenameSymbol(renameRequest, cancellationToken).ConfigureAwait(false);
+
+ // Since LSP 3.16 we can simply basically return a DefaultBehavior true or null to signal to the client that the position is valid for rename and it should use its default selection criteria (which is probably the language semantic highlighting or grammar). For the current scope of the rename provider, this should be fine, but we have the option to supply the specific range in the future for special cases.
+ RangeOrPlaceholderRange renameSupported = new(new RenameDefaultBehavior() { DefaultBehavior = true });
+
+ return (renameResponse?.Changes?[request.TextDocument.Uri].ToArray().Length > 0)
+ ? renameSupported
+ : null;
+ }
+
+ public async Task RenameSymbol(RenameParams request, CancellationToken cancellationToken)
+ {
+ // We want scoped settings because a workspace setting might be relevant here.
+ RenameServiceOptions options = await GetScopedSettings(request.TextDocument.Uri, cancellationToken).ConfigureAwait(false);
+
+ if (!await AcceptRenameDisclaimer(options.acceptDisclaimer, cancellationToken).ConfigureAwait(false)) { return null; }
+
+ ScriptFile scriptFile = workspaceService.GetFile(request.TextDocument.Uri);
+ ScriptPositionAdapter position = request.Position;
+
+ Ast? tokenToRename = FindRenamableSymbol(scriptFile, position);
+ if (tokenToRename is null) { return null; }
+
+ TextEdit[] changes = tokenToRename switch
+ {
+ FunctionDefinitionAst
+ or CommandAst
+ => RenameFunction(tokenToRename, scriptFile.ScriptAst, request),
+
+ VariableExpressionAst
+ or CommandParameterAst
+ or StringConstantExpressionAst
+ => RenameVariable(tokenToRename, scriptFile.ScriptAst, request, options.createParameterAlias),
+
+ _ => throw new InvalidOperationException("This should not happen as PrepareRename should have already checked for viability. File an issue if you see this.")
+ };
+
+ return new WorkspaceEdit
+ {
+ Changes = new Dictionary>
+ {
+ [request.TextDocument.Uri] = changes
+ }
+ };
+ }
+
+ private static TextEdit[] RenameFunction(Ast target, Ast scriptAst, RenameParams renameParams)
+ {
+ RenameFunctionVisitor visitor = new(target, renameParams.NewName);
+ return visitor.VisitAndGetEdits(scriptAst);
+ }
+
+ private static TextEdit[] RenameVariable(Ast symbol, Ast scriptAst, RenameParams requestParams, bool createParameterAlias)
+ {
+ RenameVariableVisitor visitor = new(
+ symbol, requestParams.NewName, createParameterAlias: createParameterAlias
+ );
+ return visitor.VisitAndGetEdits(scriptAst);
+ }
+
+ ///
+ /// Finds the most specific renamable symbol at the given position
+ ///
+ /// Ast of the token or null if no renamable symbol was found
+ internal static Ast? FindRenamableSymbol(ScriptFile scriptFile, IScriptPosition position)
+ {
+ List renameableAstTypes = [
+ // Functions
+ typeof(FunctionDefinitionAst),
+ typeof(CommandAst),
+
+ // Variables
+ typeof(VariableExpressionAst),
+ typeof(CommandParameterAst),
+ typeof(StringConstantExpressionAst)
+ ];
+ Ast? ast = scriptFile.ScriptAst.FindClosest(position, renameableAstTypes.ToArray());
+
+ if (ast is StringConstantExpressionAst stringAst)
+ {
+ // Only splat string parameters should be considered for evaluation.
+ if (stringAst.FindSplatParameterReference() is not null) { return stringAst; }
+ // Otherwise redo the search without stringConstant, so the most specific is a command, etc.
+ renameableAstTypes.Remove(typeof(StringConstantExpressionAst));
+ ast = scriptFile.ScriptAst.FindClosest(position, renameableAstTypes.ToArray());
+ }
+
+ // Performance optimizations
+
+ // Only the function name is valid for rename, not other components
+ if (ast is FunctionDefinitionAst funcDefAst)
+ {
+ if (!funcDefAst.GetFunctionNameExtent().Contains(position))
+ {
+ return null;
+ }
+ }
+
+ // Only the command name (function call) portion is renamable
+ if (ast is CommandAst command)
+ {
+ if (command.CommandElements[0] is not StringConstantExpressionAst name)
+ {
+ return null;
+ }
+
+ if (!new ScriptExtentAdapter(name.Extent).Contains(position))
+ {
+ return null;
+ }
+ }
+
+ return ast;
+ }
+
+ ///
+ /// Prompts the user to accept the rename disclaimer.
+ ///
+ /// true if accepted, false if rejected
+ private async Task AcceptRenameDisclaimer(bool acceptDisclaimerOption, CancellationToken cancellationToken)
+ {
+ const string disclaimerDeclinedMessage = "PowerShell rename has been disabled for this session as the disclaimer message was declined. Please restart the extension if you wish to use rename and accept the disclaimer.";
+
+ if (DisclaimerDeclinedForSession) { throw new HandlerErrorException(disclaimerDeclinedMessage); }
+ if (acceptDisclaimerOption || DisclaimerAcceptedForSession) { return true; }
+
+ const string renameDisclaimer = "PowerShell rename functionality is only supported in a limited set of circumstances. [Please review the notice](https://aka.ms/powershell-rename-disclaimer) and accept the limitations and risks.";
+ const string acceptAnswer = "I Accept";
+ const string declineAnswer = "Decline";
+
+ ShowMessageRequestParams reqParams = new()
+ {
+ Type = MessageType.Warning,
+ Message = renameDisclaimer,
+ Actions = new MessageActionItem[] {
+ new() { Title = acceptAnswer },
+ new() { Title = declineAnswer }
+ }
+ };
+
+ MessageActionItem? result = await lsp.SendRequest(reqParams, cancellationToken).ConfigureAwait(false);
+
+ // null happens if the user closes the dialog rather than making a selection.
+ if (result is null || result.Title == declineAnswer)
+ {
+ const string renameDisabledNotice = "PowerShell Rename functionality will be disabled for this session and you will not be prompted again until restart.";
+
+ ShowMessageParams msgParams = new()
+ {
+ Message = renameDisabledNotice,
+ Type = MessageType.Info
+ };
+ lsp.SendNotification(msgParams);
+ DisclaimerDeclinedForSession = true;
+ throw new HandlerErrorException(disclaimerDeclinedMessage);
+ }
+ if (result.Title == acceptAnswer)
+ {
+ // Unfortunately the LSP spec has no spec for the server to change a client setting, so we have a suboptimal experience to tell the user to change the setting rather than doing it for them without implementing custom client behavior.
+ const string acceptDisclaimerNotice = "PowerShell rename functionality has been enabled for this session. To avoid this prompt in the future, set the powershell.rename.acceptDisclaimer to true in your settings.";
+ ShowMessageParams msgParams = new()
+ {
+ Message = acceptDisclaimerNotice,
+ Type = MessageType.Info
+ };
+ lsp.SendNotification(msgParams);
+
+ DisclaimerAcceptedForSession = true;
+ return DisclaimerAcceptedForSession;
+ }
+
+ throw new InvalidOperationException("Unknown Disclaimer Response received. This is a bug and you should report it.");
+ }
+
+ private async Task GetScopedSettings(DocumentUri uri, CancellationToken cancellationToken = default)
+ {
+ IScopedConfiguration scopedConfig = await config.GetScopedConfiguration(uri, cancellationToken).ConfigureAwait(false);
+ return scopedConfig.GetSection(ConfigSection).Get() ?? new RenameServiceOptions();
+ }
+}
+
+internal abstract class RenameVisitorBase : AstVisitor
+{
+ internal List Edits { get; } = new();
+ internal Ast? CurrentDocument { get; set; }
+
+ ///
+ /// A convenience method to get text edits from a specified AST.
+ ///
+ internal virtual TextEdit[] VisitAndGetEdits(Ast ast)
+ {
+ ast.Visit(this);
+ return Edits.ToArray();
+ }
+}
+
+///
+/// A visitor that generates a list of TextEdits to a TextDocument to rename a PowerShell function
+/// You should use a new instance for each rename operation.
+/// Skipverify can be used as a performance optimization when you are sure you are in scope.
+///
+internal class RenameFunctionVisitor(Ast target, string newName, bool skipVerify = false) : RenameVisitorBase
+{
+ private FunctionDefinitionAst? FunctionToRename;
+
+ // Wire up our visitor to the relevant AST types we are potentially renaming
+ public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst ast) => Visit(ast);
+ public override AstVisitAction VisitCommand(CommandAst ast) => Visit(ast);
+
+ internal AstVisitAction Visit(Ast ast)
+ {
+ // If this is our first run, we need to verify we are in scope and gather our rename operation info
+ if (!skipVerify && CurrentDocument is null)
+ {
+ CurrentDocument = ast.GetHighestParent();
+ if (CurrentDocument.Find(ast => ast == target, true) is null)
+ {
+ throw new TargetSymbolNotFoundException("The target this visitor would rename is not present in the AST. This is a bug and you should file an issue");
+ }
+
+ FunctionToRename = target switch
+ {
+ FunctionDefinitionAst f => f,
+ CommandAst command => CurrentDocument.FindFunctionDefinition(command)
+ ?? throw new HandlerErrorException("The command to rename does not have a function definition. Renaming a function is only supported when the function is defined within an accessible scope"),
+ _ => throw new Exception($"Unsupported AST type {target.GetType()} encountered")
+ };
+ };
+
+ if (CurrentDocument != ast.GetHighestParent())
+ {
+ throw new TargetSymbolNotFoundException("The visitor should not be reused to rename a different document. It should be created new for each rename operation. This is a bug and you should file an issue");
+ }
+
+ if (ShouldRename(ast))
+ {
+ Edits.Add(GetRenameFunctionEdit(ast));
+ }
+ return AstVisitAction.Continue;
+
+ // TODO: Is there a way we can know we are fully outside where the function might be referenced, and if so, call a AstVisitAction Abort as a perf optimization?
+ }
+
+ internal bool ShouldRename(Ast candidate)
+ {
+ // Rename our original function definition. There may be duplicate definitions of the same name
+ if (candidate is FunctionDefinitionAst funcDef)
+ {
+ return funcDef == FunctionToRename;
+ }
+
+ // Should only be CommandAst (function calls) from this point forward in the visit.
+ if (candidate is not CommandAst command)
+ {
+ throw new InvalidOperationException($"ShouldRename for a function had an Unexpected Ast Type {candidate.GetType()}. This is a bug and you should file an issue.");
+ }
+
+ if (CurrentDocument is null)
+ {
+ throw new InvalidOperationException("CurrentDoc should always be set by now from first Visit. This is a bug and you should file an issue.");
+ }
+
+ // Match up the command to its function definition
+ return CurrentDocument.FindFunctionDefinition(command) == FunctionToRename;
+ }
+
+ private TextEdit GetRenameFunctionEdit(Ast candidate)
+ {
+ if (candidate is FunctionDefinitionAst funcDef)
+ {
+ if (funcDef != FunctionToRename)
+ {
+ throw new InvalidOperationException("GetRenameFunctionEdit was called on an Ast that was not the target. This is a bug and you should file an issue.");
+ }
+
+ if (!IsValidFunctionName(newName))
+ {
+ throw new HandlerErrorException($"{newName} is not a valid function name.");
+ }
+
+ ScriptExtentAdapter functionNameExtent = funcDef.GetFunctionNameExtent();
+
+ return new TextEdit()
+ {
+ NewText = newName,
+ Range = functionNameExtent
+ };
+ }
+
+ // Should be CommandAst past this point.
+ if (candidate is not CommandAst command)
+ {
+ throw new InvalidOperationException($"Expected a command but got {candidate.GetType()}");
+ }
+
+ if (command.CommandElements[0] is not StringConstantExpressionAst funcName)
+ {
+ throw new InvalidOperationException("Command element should always have a string expression as its first item. This is a bug and you should report it.");
+ }
+
+ return new TextEdit()
+ {
+ NewText = newName,
+ Range = new ScriptExtentAdapter(funcName.Extent)
+ };
+ }
+
+ internal static bool IsValidFunctionName(string name)
+ {
+ // Allows us to supply function:varname or varname and get a proper result
+ string candidate = "function " + name.TrimStart('$').TrimStart('-') + " {}";
+ Ast ast = Parser.ParseInput(candidate, out _, out ParseError[] errors);
+ if (errors.Length > 0)
+ {
+ return false;
+ }
+
+ return (ast.Find(a => a is FunctionDefinitionAst, false) as FunctionDefinitionAst)?
+ .Name is not null;
+ }
+}
+
+internal class RenameVariableVisitor(Ast target, string newName, bool skipVerify = false, bool createParameterAlias = false) : RenameVisitorBase
+{
+ // Used to store the original definition of the variable to use as a reference.
+ internal Ast? VariableDefinition;
+
+ // Validate and cleanup the newName definition. User may have left off the $
+ private readonly string NewName = newName.TrimStart('$').TrimStart('-');
+
+ // Wire up our visitor to the relevant AST types we are potentially renaming
+ public override AstVisitAction VisitVariableExpression(VariableExpressionAst ast) => Visit(ast);
+ public override AstVisitAction VisitCommandParameter(CommandParameterAst ast) => Visit(ast);
+ public override AstVisitAction VisitStringConstantExpression(StringConstantExpressionAst ast) => Visit(ast);
+
+ internal AstVisitAction Visit(Ast ast)
+ {
+ // If this is our first visit, we need to initialize and verify the scope, otherwise verify we are still on the same document.
+ if ((!skipVerify && CurrentDocument is null) || VariableDefinition is null)
+ {
+ CurrentDocument = ast.GetHighestParent();
+ if (CurrentDocument.Find(ast => ast == target, true) is null)
+ {
+ throw new TargetSymbolNotFoundException("The target this visitor would rename is not present in the AST. This is a bug and you should file an issue");
+ }
+
+ // Get the original assignment of our variable, this makes finding rename targets easier in subsequent visits as well as allows us to short-circuit quickly.
+ VariableDefinition = target.GetTopVariableAssignment();
+ if (VariableDefinition is null)
+ {
+ throw new HandlerErrorException("The variable element to rename does not have a definition. Renaming an element is only supported when the variable element is defined within an accessible scope");
+ }
+ }
+ else if (CurrentDocument != ast.GetHighestParent())
+ {
+ throw new TargetSymbolNotFoundException("The visitor should not be reused to rename a different document. It should be created new for each rename operation. This is a bug and you should file an issue");
+ }
+
+ if (ShouldRename(ast))
+ {
+ if (
+ createParameterAlias
+ && ast == VariableDefinition
+ && VariableDefinition is not null and VariableExpressionAst varDefAst
+ && varDefAst.Parent is ParameterAst paramAst
+ )
+ {
+ Edits.Add(new TextEdit
+ {
+ NewText = $"[Alias('{varDefAst.VariablePath.UserPath}')]",
+ Range = new Range()
+ {
+ Start = new ScriptPositionAdapter(paramAst.Extent.StartScriptPosition),
+ End = new ScriptPositionAdapter(paramAst.Extent.StartScriptPosition)
+ }
+ });
+ }
+
+ Edits.Add(GetRenameVariableEdit(ast));
+ }
+
+ return AstVisitAction.Continue;
+ }
+
+ private bool ShouldRename(Ast candidate)
+ {
+ if (VariableDefinition is null)
+ {
+ throw new InvalidOperationException("VariableDefinition should always be set by now from first Visit. This is a bug and you should file an issue.");
+ }
+
+ if (candidate == VariableDefinition) { return true; }
+ // Performance optimization
+ if (VariableDefinition.IsAfter(candidate)) { return false; }
+
+ if (candidate.GetTopVariableAssignment() == VariableDefinition) { return true; }
+
+ return false;
+ }
+
+ private TextEdit GetRenameVariableEdit(Ast ast)
+ {
+ return ast switch
+ {
+ VariableExpressionAst var => !IsValidVariableName(NewName)
+ ? throw new HandlerErrorException($"${NewName} is not a valid variable name.")
+ : new TextEdit
+ {
+ NewText = '$' + NewName,
+ Range = new ScriptExtentAdapter(var.Extent)
+ },
+ StringConstantExpressionAst stringAst => !IsValidVariableName(NewName)
+ ? throw new HandlerErrorException($"{NewName} is not a valid variable name.")
+ : new TextEdit
+ {
+ NewText = NewName,
+ Range = new ScriptExtentAdapter(stringAst.Extent)
+ },
+ CommandParameterAst param => !IsValidCommandParameterName(NewName)
+ ? throw new HandlerErrorException($"-{NewName} is not a valid command parameter name.")
+ : new TextEdit
+ {
+ NewText = '-' + NewName,
+ Range = new ScriptExtentAdapter(param.Extent)
+ },
+ _ => throw new InvalidOperationException($"GetRenameVariableEdit was called on an Ast that was not the target. This is a bug and you should file an issue.")
+ };
+ }
+
+ internal static bool IsValidVariableName(string name)
+ {
+ // Allows us to supply $varname or varname and get a proper result
+ string candidate = '$' + name.TrimStart('$').TrimStart('-');
+ Parser.ParseInput(candidate, out Token[] tokens, out _);
+ return tokens.Length is 2
+ && tokens[0].Kind == TokenKind.Variable
+ && tokens[1].Kind == TokenKind.EndOfInput;
+ }
+
+ internal static bool IsValidCommandParameterName(string name)
+ {
+ // Allows us to supply -varname or varname and get a proper result
+ string candidate = "Command -" + name.TrimStart('$').TrimStart('-');
+ Parser.ParseInput(candidate, out Token[] tokens, out _);
+ return tokens.Length == 3
+ && tokens[0].Kind == TokenKind.Command
+ && tokens[1].Kind == TokenKind.Parameter
+ && tokens[2].Kind == TokenKind.EndOfInput;
+ }
+}
+
+///
+/// Represents a position in a script file that adapts and implicitly converts based on context. PowerShell script lines/columns start at 1, but LSP textdocument lines/columns start at 0. The default line/column constructor is 1-based.
+///
+internal record ScriptPositionAdapter(IScriptPosition position) : IScriptPosition, IComparable, IComparable, IComparable
+{
+ public int Line => position.LineNumber;
+ public int LineNumber => position.LineNumber;
+ public int Column => position.ColumnNumber;
+ public int ColumnNumber => position.ColumnNumber;
+ public int Character => position.ColumnNumber;
+
+ public string File => position.File;
+ string IScriptPosition.Line => position.Line;
+ public int Offset => position.Offset;
+
+ public ScriptPositionAdapter(int Line, int Column) : this(new ScriptPosition(null, Line, Column, null)) { }
+ public ScriptPositionAdapter(ScriptPosition position) : this((IScriptPosition)position) { }
+
+ public ScriptPositionAdapter(Position position) : this(position.Line + 1, position.Character + 1) { }
+
+ public static implicit operator ScriptPositionAdapter(Position position) => new(position);
+ public static implicit operator Position(ScriptPositionAdapter scriptPosition) => new(
+ scriptPosition.position.LineNumber - 1, scriptPosition.position.ColumnNumber - 1
+ );
+
+ public static implicit operator ScriptPositionAdapter(ScriptPosition position) => new(position);
+ public static implicit operator ScriptPosition(ScriptPositionAdapter position) =>
+ position.position is ScriptPosition scriptPosition
+ ? scriptPosition
+ : new ScriptPosition(
+ position.position.File,
+ position.position.LineNumber,
+ position.position.ColumnNumber,
+ position.position.Line
+ );
+
+ internal ScriptPositionAdapter Delta(int LineAdjust, int ColumnAdjust) => new(
+ position.LineNumber + LineAdjust,
+ position.ColumnNumber + ColumnAdjust
+ );
+
+ public int CompareTo(ScriptPositionAdapter other)
+ {
+ if (position.LineNumber == other.position.LineNumber)
+ {
+ return position.ColumnNumber.CompareTo(other.position.ColumnNumber);
+ }
+ return position.LineNumber.CompareTo(other.position.LineNumber);
+ }
+ public int CompareTo(Position other) => CompareTo((ScriptPositionAdapter)other);
+ public int CompareTo(ScriptPosition other) => CompareTo((ScriptPositionAdapter)other);
+
+ // Required for interface implementation but not used.
+ public string GetFullScript() => throw new NotImplementedException();
+}
+
+///
+/// Represents a range in a script file that adapts and implicitly converts based on context. PowerShell script lines/columns start at 1, but LSP textdocument lines/columns start at 0. The default ScriptExtent constructor is 1-based
+///
+///
+internal record ScriptExtentAdapter(IScriptExtent extent) : IScriptExtent
+{
+ internal ScriptPositionAdapter Start = new(extent.StartScriptPosition);
+ internal ScriptPositionAdapter End = new(extent.EndScriptPosition);
+
+ public static implicit operator ScriptExtentAdapter(ScriptExtent extent) => new(extent);
+
+ public static implicit operator ScriptExtentAdapter(Range range) => new(new ScriptExtent(
+ // Will get shifted to 1-based
+ new ScriptPositionAdapter(range.Start),
+ new ScriptPositionAdapter(range.End)
+ ));
+ public static implicit operator Range(ScriptExtentAdapter adapter) => new()
+ {
+ // Will get shifted to 0-based
+ Start = adapter.Start,
+ End = adapter.End
+ };
+
+ public static implicit operator ScriptExtent(ScriptExtentAdapter adapter) =>
+ adapter.extent is ScriptExtent scriptExtent
+ ? scriptExtent
+ : new ScriptExtent(adapter.Start, adapter.End);
+
+ public static implicit operator RangeOrPlaceholderRange(ScriptExtentAdapter adapter) => new((Range)adapter)
+ {
+ DefaultBehavior = new() { DefaultBehavior = false }
+ };
+
+ public IScriptPosition StartScriptPosition => Start;
+ public IScriptPosition EndScriptPosition => End;
+ public int EndColumnNumber => End.ColumnNumber;
+ public int EndLineNumber => End.LineNumber;
+ public int StartOffset => extent.StartOffset;
+ public int EndOffset => extent.EndOffset;
+ public string File => extent.File;
+ public int StartColumnNumber => extent.StartColumnNumber;
+ public int StartLineNumber => extent.StartLineNumber;
+ public string Text => extent.Text;
+}
diff --git a/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs b/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs
index fb6772d2b..9cff31d41 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/ScriptFile.cs
@@ -51,9 +51,15 @@ internal sealed class ScriptFile
///
/// Gets a boolean that determines whether this file is
- /// in-memory or not (either unsaved or non-file content).
+ /// in-memory or not (either unsaved or non-file content) aka "dirty"
///
- public bool IsInMemory { get; }
+ public bool IsInMemory { get; internal set; }
+
+ ///
+ /// Gets a value indicating whether the document URI is not a file:// URI
+ /// (for example, an untitled: URI).
+ ///
+ public bool IsUntitled => !DocumentUri.ToUri().IsFile;
///
/// Gets a string containing the full contents of the file.
@@ -105,6 +111,9 @@ public Token[] ScriptTokens
internal ReferenceTable References { get; }
+ ///
+ /// Indicates whether the file is currently open in the editor. PSES may open files for analysis that aren't actually visible in the editor.
+ ///
internal bool IsOpen { get; set; }
#endregion
@@ -127,11 +136,15 @@ internal ScriptFile(
// so that other operations know it's untitled/in-memory
// and don't think that it's a relative path
// on the file system.
- IsInMemory = !docUri.ToUri().IsFile;
+ DocumentUri = docUri;
+
+ // Initial state of document. Untitled files are in memory by definition, otherwise files start non-dirty on a filesystem
+ IsInMemory = IsUntitled;
+
FilePath = IsInMemory
? docUri.ToString()
: docUri.GetFileSystemPath();
- DocumentUri = docUri;
+
IsAnalysisEnabled = true;
this.powerShellVersion = powerShellVersion;
@@ -365,6 +378,9 @@ public void ApplyChange(FileChange fileChange)
// Parse the script again to be up-to-date
ParseFileContents();
References.TagAsChanged();
+
+ // Flag the script as modified
+ IsInMemory = true;
}
///
diff --git a/src/PowerShellEditorServices/Services/TextDocument/TokenOperations.cs b/src/PowerShellEditorServices/Services/TextDocument/TokenOperations.cs
index 6a6f789ff..9ed65db20 100644
--- a/src/PowerShellEditorServices/Services/TextDocument/TokenOperations.cs
+++ b/src/PowerShellEditorServices/Services/TextDocument/TokenOperations.cs
@@ -25,9 +25,7 @@ internal static class TokenOperations
///
/// Extracts all of the unique foldable regions in a script given the list tokens
///
-#pragma warning disable CA1502 // Cyclomatic complexity we don't care about
internal static FoldingReferenceList FoldableReferences(Token[] tokens)
-#pragma warning restore CA1502
{
FoldingReferenceList refList = new();
diff --git a/src/PowerShellEditorServices/Services/Workspace/Handlers/ConfigurationHandler.cs b/src/PowerShellEditorServices/Services/Workspace/Handlers/ConfigurationHandler.cs
index a7f36aab1..2cfb57cd4 100644
--- a/src/PowerShellEditorServices/Services/Workspace/Handlers/ConfigurationHandler.cs
+++ b/src/PowerShellEditorServices/Services/Workspace/Handlers/ConfigurationHandler.cs
@@ -100,7 +100,6 @@ public override async Task Handle(DidChangeConfigurationParams request, Ca
return await Unit.Task.ConfigureAwait(false);
}
-
public event EventHandler ConfigurationUpdated;
}
}
diff --git a/src/PowerShellEditorServices/Services/Workspace/LanguageServerSettings.cs b/src/PowerShellEditorServices/Services/Workspace/LanguageServerSettings.cs
index e417d7b92..d310903ae 100644
--- a/src/PowerShellEditorServices/Services/Workspace/LanguageServerSettings.cs
+++ b/src/PowerShellEditorServices/Services/Workspace/LanguageServerSettings.cs
@@ -207,6 +207,7 @@ public CodeFormattingSettings(CodeFormattingSettings codeFormattingSettings)
public bool WhitespaceInsideBrace { get; set; }
public bool IgnoreOneLineBlock { get; set; }
public bool AlignPropertyValuePairs { get; set; }
+ public bool AlignEnumMemberValues { get; set; }
public bool UseCorrectCasing { get; set; }
///
@@ -298,7 +299,8 @@ private Hashtable GetCustomPSSASettingsHashtable(int tabSize, bool insertSpaces)
"PSAlignAssignmentStatement",
new Hashtable {
{ "Enable", true },
- { "CheckHashtable", AlignPropertyValuePairs }
+ { "CheckHashtable", AlignPropertyValuePairs },
+ { "CheckEnums", AlignEnumMemberValues },
}
},
{
diff --git a/src/PowerShellEditorServices/Services/Workspace/RemoteFileManagerService.cs b/src/PowerShellEditorServices/Services/Workspace/RemoteFileManagerService.cs
index a3e46f4f1..961338023 100644
--- a/src/PowerShellEditorServices/Services/Workspace/RemoteFileManagerService.cs
+++ b/src/PowerShellEditorServices/Services/Workspace/RemoteFileManagerService.cs
@@ -252,6 +252,7 @@ function New-EditorFile {
///
/// The IEditorOperations instance to use for opening/closing files in the editor.
///
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD110:Observe result of async calls", Justification = "Intentionally fire and forget.")]
public RemoteFileManagerService(
ILoggerFactory factory,
IRunspaceContext runspaceContext,
@@ -275,7 +276,6 @@ public RemoteFileManagerService(
// Delete existing temporary file cache path if it already exists
TryDeleteTemporaryPath();
- // TODO: Do this somewhere other than the constructor and make it async
// Register the psedit function in the current runspace
RegisterPSEditFunctionAsync().HandleErrorsAsync(logger);
}
@@ -519,6 +519,8 @@ private RemotePathMappings GetPathMappings(IRunspaceInfo runspaceInfo)
return remotePathMappings;
}
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "Supporting synchronous API.")]
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD110:Observe result of async calls", Justification = "Intentionally fire and forget.")]
private void HandleRunspaceChanged(object sender, RunspaceChangedEventArgs e)
{
if (e.ChangeAction == RunspaceChangeAction.Enter)
@@ -572,6 +574,7 @@ private static bool ShouldTearDownRemoteFiles(RunspaceChangedEventArgs runspaceC
StringComparison.CurrentCultureIgnoreCase);
}
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD100:Avoid async void methods", Justification = "It has to be async.")]
private async void HandlePSEventReceivedAsync(object sender, PSEventArgs args)
{
if (!string.Equals(RemoteSessionOpenFile, args.SourceIdentifier, StringComparison.CurrentCultureIgnoreCase))
diff --git a/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs b/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs
index 941fcf736..9b721387a 100644
--- a/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs
+++ b/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs
@@ -302,7 +302,14 @@ public void CloseFile(ScriptFile scriptFile)
Validate.IsNotNull(nameof(scriptFile), scriptFile);
string keyName = GetFileKey(scriptFile.DocumentUri);
- workspaceFiles.TryRemove(keyName, out ScriptFile _);
+ if (workspaceFiles.TryRemove(keyName, out ScriptFile _))
+ {
+ logger.LogDebug("Closed file: " + scriptFile.DocumentUri);
+ }
+ else
+ {
+ logger.LogWarning("Tried to close file that was not open: " + scriptFile.DocumentUri);
+ }
}
///
@@ -312,7 +319,7 @@ public void CloseFile(ScriptFile scriptFile)
public string GetRelativePath(ScriptFile scriptFile)
{
Uri fileUri = scriptFile.DocumentUri.ToUri();
- if (!scriptFile.IsInMemory)
+ if (!scriptFile.IsUntitled)
{
// Support calculating out-of-workspace relative paths in the common case of a
// single workspace folder. Otherwise try to get the matching folder.
@@ -335,6 +342,35 @@ public string GetRelativePath(ScriptFile scriptFile)
return fileUri.ToString();
}
+ ///
+ /// Finds a file in the first workspace folder where it exists, if possible.
+ /// Used as a backwards-compatible way to find files in the workspace.
+ ///
+ ///
+ /// Best possible path.
+ public string FindFileInWorkspace(string filePath)
+ {
+ // If the file path is already an absolute path, just return it.
+ if (Path.IsPathRooted(filePath))
+ {
+ return filePath;
+ }
+
+ // If the file path is relative, try to find it in the workspace folders.
+ foreach (WorkspaceFolder workspaceFolder in WorkspaceFolders)
+ {
+ string folderPath = workspaceFolder.Uri.GetFileSystemPath();
+ string combinedPath = Path.Combine(folderPath, filePath);
+ if (File.Exists(combinedPath))
+ {
+ return combinedPath;
+ }
+ }
+
+ // If the file path is not found in the workspace folders, return the original path.
+ return filePath;
+ }
+
///
/// Enumerate all the PowerShell (ps1, psm1, psd1) files in the workspace in a recursive manner, using default values.
///
@@ -409,57 +445,6 @@ internal static string ReadFileContents(DocumentUri uri)
return reader.ReadToEnd();
}
- internal string ResolveWorkspacePath(string path) => ResolveRelativeScriptPath(InitialWorkingDirectory, path);
-
- internal string ResolveRelativeScriptPath(string baseFilePath, string relativePath)
- {
- // TODO: Sometimes the `baseFilePath` (even when its `WorkspacePath`) is null.
- string combinedPath = null;
- Exception resolveException = null;
-
- try
- {
- // If the path is already absolute there's no need to resolve it relatively
- // to the baseFilePath.
- if (Path.IsPathRooted(relativePath))
- {
- return relativePath;
- }
-
- // Get the directory of the original script file, combine it
- // with the given path and then resolve the absolute file path.
- combinedPath =
- Path.GetFullPath(
- Path.Combine(
- baseFilePath,
- relativePath));
- }
- catch (NotSupportedException e)
- {
- // Occurs if the path is incorrectly formatted for any reason. One
- // instance where this occurred is when a user had curly double-quote
- // characters in their source instead of normal double-quotes.
- resolveException = e;
- }
- catch (ArgumentException e)
- {
- // Occurs if the path contains invalid characters, specifically those
- // listed in System.IO.Path.InvalidPathChars.
- resolveException = e;
- }
-
- if (resolveException != null)
- {
- logger.LogError(
- "Could not resolve relative script path\r\n" +
- $" baseFilePath = {baseFilePath}\r\n " +
- $" relativePath = {relativePath}\r\n\r\n" +
- $"{resolveException}");
- }
-
- return combinedPath;
- }
-
///
/// Returns a normalized string for a given documentUri to be used as key name.
/// Case-sensitive uri on Linux and lowercase for other platforms.
diff --git a/src/PowerShellEditorServices/Utility/AstExtensions.cs b/src/PowerShellEditorServices/Utility/AstExtensions.cs
new file mode 100644
index 000000000..49e39f696
--- /dev/null
+++ b/src/PowerShellEditorServices/Utility/AstExtensions.cs
@@ -0,0 +1,696 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#nullable enable
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Management.Automation.Language;
+using Microsoft.PowerShell.EditorServices.Services;
+
+namespace Microsoft.PowerShell.EditorServices.Language;
+
+// NOTE: A lot of this is reimplementation of https://github.com/PowerShell/PowerShell/blob/2d5d702273060b416aea9601e939ff63bb5679c9/src/System.Management.Automation/engine/parser/Position.cs which is internal and sealed.
+
+internal static class AstExtensions
+{
+ private const int IS_BEFORE = -1;
+ private const int IS_AFTER = 1;
+ private const int IS_EQUAL = 0;
+ internal static int CompareTo(this IScriptPosition position, IScriptPosition other)
+ {
+ if (position.LineNumber < other.LineNumber)
+ {
+ return IS_BEFORE;
+ }
+ else if (position.LineNumber > other.LineNumber)
+ {
+ return IS_AFTER;
+ }
+ else //Lines are equal
+ {
+ if (position.ColumnNumber < other.ColumnNumber)
+ {
+ return IS_BEFORE;
+ }
+ else if (position.ColumnNumber > other.ColumnNumber)
+ {
+ return IS_AFTER;
+ }
+ else //Columns are equal
+ {
+ return IS_EQUAL;
+ }
+ }
+ }
+
+ internal static bool IsEqual(this IScriptPosition position, IScriptPosition other)
+ => position.CompareTo(other) == IS_EQUAL;
+
+ internal static bool IsBefore(this IScriptPosition position, IScriptPosition other)
+ => position.CompareTo(other) == IS_BEFORE;
+
+ internal static bool IsAfter(this IScriptPosition position, IScriptPosition other)
+ => position.CompareTo(other) == IS_AFTER;
+
+ internal static bool Contains(this IScriptExtent extent, IScriptPosition position)
+ => extent.StartScriptPosition.IsEqual(position)
+ || extent.EndScriptPosition.IsEqual(position)
+ || (extent.StartScriptPosition.IsBefore(position) && extent.EndScriptPosition.IsAfter(position));
+
+ internal static bool Contains(this IScriptExtent extent, IScriptExtent other)
+ => extent.Contains(other.StartScriptPosition) && extent.Contains(other.EndScriptPosition);
+
+ internal static bool StartsBefore(this IScriptExtent extent, IScriptExtent other)
+ => extent.StartScriptPosition.IsBefore(other.StartScriptPosition);
+
+ internal static bool StartsBefore(this IScriptExtent extent, IScriptPosition other)
+ => extent.StartScriptPosition.IsBefore(other);
+
+ internal static bool StartsAfter(this IScriptExtent extent, IScriptExtent other)
+ => extent.StartScriptPosition.IsAfter(other.StartScriptPosition);
+
+ internal static bool StartsAfter(this IScriptExtent extent, IScriptPosition other)
+ => extent.StartScriptPosition.IsAfter(other);
+
+ internal static bool IsBefore(this IScriptExtent extent, IScriptExtent other)
+ => !other.Contains(extent)
+ && !extent.Contains(other)
+ && extent.StartScriptPosition.IsBefore(other.StartScriptPosition);
+
+ internal static bool IsAfter(this IScriptExtent extent, IScriptExtent other)
+ => !other.Contains(extent)
+ && !extent.Contains(other)
+ && extent.StartScriptPosition.IsAfter(other.StartScriptPosition);
+
+ internal static bool Contains(this Ast ast, Ast other)
+ => ast.Extent.Contains(other.Extent);
+
+ internal static bool Contains(this Ast ast, IScriptPosition position)
+ => ast.Extent.Contains(position);
+
+ internal static bool Contains(this Ast ast, IScriptExtent position)
+ => ast.Extent.Contains(position);
+
+ internal static bool IsBefore(this Ast ast, Ast other)
+ => ast.Extent.IsBefore(other.Extent);
+
+ internal static bool IsAfter(this Ast ast, Ast other)
+ => ast.Extent.IsAfter(other.Extent);
+
+ internal static bool StartsBefore(this Ast ast, Ast other)
+ => ast.Extent.StartsBefore(other.Extent);
+
+ internal static bool StartsBefore(this Ast ast, IScriptExtent other)
+ => ast.Extent.StartsBefore(other);
+
+ internal static bool StartsBefore(this Ast ast, IScriptPosition other)
+ => ast.Extent.StartsBefore(other);
+
+ internal static bool StartsAfter(this Ast ast, Ast other)
+ => ast.Extent.StartsAfter(other.Extent);
+
+ internal static bool StartsAfter(this Ast ast, IScriptExtent other)
+ => ast.Extent.StartsAfter(other);
+
+ internal static bool StartsAfter(this Ast ast, IScriptPosition other)
+ => ast.Extent.StartsAfter(other);
+
+ ///
+ /// Finds the outermost Ast that starts before the target and matches the predicate within the scope.
+ /// Returns null if none found. Useful for finding definitions of variable/function references.
+ ///
+ /// The target Ast to search from
+ /// The predicate to match the Ast against
+ /// If true, the search will continue until the topmost scope boundary is found.
+ /// Searches scriptblocks within the parent at each level. This can be helpful to find "side" scopes but affects performance
+ internal static Ast? FindStartsBefore(this Ast target, Func predicate, bool crossScopeBoundaries = false, bool searchNestedScriptBlocks = false)
+ {
+ Ast? scope = target.GetScopeBoundary();
+ do
+ {
+ Ast? result = scope?.Find(ast =>
+ ast.StartsBefore(target)
+ && predicate(ast)
+ , searchNestedScriptBlocks);
+
+ if (result is not null)
+ {
+ return result;
+ }
+
+ scope = scope?.GetScopeBoundary();
+ } while (crossScopeBoundaries && scope is not null);
+
+ return null;
+ }
+
+ internal static T? FindStartsBefore(this Ast target, Func predicate, bool crossScopeBoundaries = false, bool searchNestedScriptBlocks = false) where T : Ast
+ => target.FindStartsBefore
+ (
+ ast => ast is T type && predicate(type), crossScopeBoundaries, searchNestedScriptBlocks
+ ) as T;
+
+ ///
+ /// Finds all AST items that start before the target and match the predicate within the scope. Items are returned in order from closest to furthest. Returns an empty list if none found. Useful for finding definitions of variable/function references
+ ///
+ internal static IEnumerable FindAllStartsBefore(this Ast target, Func predicate, bool crossScopeBoundaries = false)
+ {
+ Ast? scope = target.GetScopeBoundary();
+ do
+ {
+ IEnumerable results = scope?.FindAll(ast => ast.StartsBefore(target) && predicate(ast)
+ , searchNestedScriptBlocks: false) ?? [];
+
+ foreach (Ast result in results.Reverse())
+ {
+ yield return result;
+ }
+ scope = scope?.GetScopeBoundary();
+ } while (crossScopeBoundaries && scope is not null);
+ }
+
+ internal static Ast? FindStartsAfter(this Ast target, Func predicate, bool searchNestedScriptBlocks = false)
+ => target.Parent?.Find(ast => ast.StartsAfter(target) && predicate(ast), searchNestedScriptBlocks);
+
+ internal static IEnumerable FindAllStartsAfter(this Ast target, Func predicate, bool searchNestedScriptBlocks = false)
+ => target.Parent?.FindAll(ast => ast.StartsAfter(target) && predicate(ast), searchNestedScriptBlocks) ?? [];
+
+ ///
+ /// Finds the most specific Ast at the given script position, or returns null if none found.
+ /// For example, if the position is on a variable expression within a function definition,
+ /// the variable will be returned even if the function definition is found first, unless variable definitions are not in the list of allowed types
+ ///
+ internal static Ast? FindClosest(this Ast ast, IScriptPosition position, Type[]? allowedTypes)
+ {
+ // Short circuit quickly if the position is not in the provided ast, no need to traverse if not
+ if (!ast.Contains(position)) { return null; }
+
+ Ast? mostSpecificAst = null;
+ Ast? currentAst = ast;
+ do
+ {
+ currentAst = currentAst.Find(thisAst =>
+ {
+ // Always starts with the current item, we can skip it
+ if (thisAst == mostSpecificAst) { return false; }
+
+ if (allowedTypes is not null && !allowedTypes.Contains(thisAst.GetType())) { return false; }
+
+ if (thisAst.Contains(position))
+ {
+ mostSpecificAst = thisAst;
+ return true; //Restart the search within the more specific AST
+ }
+
+ return false;
+ }, true);
+ } while (currentAst is not null);
+
+ return mostSpecificAst;
+ }
+
+ public static bool TryFindFunctionDefinition(this Ast ast, CommandAst command, out FunctionDefinitionAst? functionDefinition)
+ {
+ functionDefinition = ast.FindFunctionDefinition(command);
+ return functionDefinition is not null;
+ }
+
+ public static FunctionDefinitionAst? FindFunctionDefinition(this Ast ast, CommandAst command)
+ {
+ if (!ast.Contains(command)) { return null; } // Short circuit if the command is not in the ast
+
+ string? name = command.GetCommandName()?.ToLower();
+ if (name is null) { return null; }
+
+ // NOTE: There should only be one match most of the time, the only other cases is when a function is defined multiple times (bad practice). If there are multiple definitions, the candidate "closest" to the command, which would be the last one found, is the appropriate one
+ return command.FindAllStartsBefore(ast =>
+ {
+ if (ast is not FunctionDefinitionAst funcDef) { return false; }
+
+ if (!funcDef.Name.Equals(name, StringComparison.CurrentCultureIgnoreCase)) { return false; }
+
+ // If the function is recursive (calls itself), its parent is a match unless a more specific in-scope function definition comes next (this is a "bad practice" edge case)
+ if (command.HasParent(funcDef)) { return true; }
+
+ return command.HasParent(funcDef.Parent); // The command is in the same scope as the function definition
+ }, true).FirstOrDefault() as FunctionDefinitionAst;
+ }
+
+ public static string GetUnqualifiedName(this VariableExpressionAst ast)
+ => ast.VariablePath.IsUnqualified
+ ? ast.VariablePath.ToString()
+ : ast.VariablePath.ToString().Split(':').Last();
+
+ public static Ast GetHighestParent(this Ast ast)
+ => ast.Parent is null ? ast : ast.Parent.GetHighestParent();
+
+ public static Ast GetHighestParent(this Ast ast, params Type[] type)
+ => FindParents(ast, type).LastOrDefault() ?? ast;
+
+ ///
+ /// Gets the closest parent that matches the specified type or null if none found.
+ ///
+ public static T? FindParent(this Ast ast) where T : Ast
+ => ast.FindParent(typeof(T)) as T;
+
+ ///
+ /// Gets the closest parent that matches the specified type or null if none found.
+ ///
+ public static Ast? FindParent(this Ast ast, params Type[] types)
+ => FindParents(ast, types).FirstOrDefault();
+
+ ///
+ /// Returns an enumerable of parents, in order of closest to furthest, that match the specified types.
+ ///
+ public static IEnumerable FindParents(this Ast ast, params Type[] types)
+ {
+ Ast? parent = ast.Parent;
+ while (parent is not null)
+ {
+ if (types.Contains(parent.GetType()))
+ {
+ yield return parent;
+ }
+ parent = parent.Parent;
+ }
+ }
+
+ ///
+ /// Gets the closest scope boundary of the ast.
+ ///
+ public static Ast? GetScopeBoundary(this Ast ast)
+ => ast.FindParent
+ (
+ typeof(ScriptBlockAst),
+ typeof(FunctionDefinitionAst),
+ typeof(ForEachStatementAst),
+ typeof(ForStatementAst)
+ );
+
+ public static VariableExpressionAst? FindClosestParameterInFunction(this Ast target, string functionName, string parameterName)
+ {
+ Ast? scope = target.GetScopeBoundary();
+ while (scope is not null)
+ {
+ FunctionDefinitionAst? funcDef = scope.FindAll
+ (
+ ast =>
+ {
+ if (ast is not FunctionDefinitionAst funcDef
+ || !funcDef.StartsBefore(target)
+ || !funcDef.Name.Equals(functionName, StringComparison.CurrentCultureIgnoreCase))
+ {
+ return false;
+ }
+
+ IReadOnlyList? parameters = funcDef.Parameters ?? funcDef.Body?.ParamBlock?.Parameters;
+ if (parameters is null || parameters.Count == 0)
+ {
+ return false;
+ }
+
+ return parameters.SingleOrDefault(
+ param => param.Name.GetUnqualifiedName().Equals(parameterName, StringComparison.CurrentCultureIgnoreCase)
+ ) is not null;
+ }
+ , false
+ ).LastOrDefault() as FunctionDefinitionAst;
+
+ if (funcDef is not null)
+ {
+ IReadOnlyList? parameters = funcDef.Parameters ?? funcDef.Body?.ParamBlock?.Parameters;
+ if (parameters is null || parameters.Count == 0)
+ {
+ return null;
+ }
+
+ return parameters
+ .SingleOrDefault
+ (
+ param => param.Name.GetUnqualifiedName().Equals(parameterName, StringComparison.CurrentCultureIgnoreCase)
+ )?.Name; // Should not be null at this point
+ }
+
+ scope = scope.GetScopeBoundary();
+ }
+ return null;
+ }
+
+ ///
+ /// Returns true if the Expression is part of a variable assignment
+ ///
+ public static bool IsVariableAssignment(this VariableExpressionAst var)
+ => var.Parent is AssignmentStatementAst or ParameterAst;
+
+ public static bool IsOperatorAssignment(this VariableExpressionAst var)
+ {
+ if (var.Parent is AssignmentStatementAst assignast)
+ {
+ return assignast.Operator != TokenKind.Equals;
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ ///
+ /// Returns true if the Ast is a potential variable reference
+ ///
+ public static bool IsPotentialVariableReference(this Ast ast)
+ => ast is VariableExpressionAst or CommandParameterAst or StringConstantExpressionAst;
+
+ ///
+ /// Determines if a variable assignment is a scoped variable assignment, meaning that it can be considered the top assignment within the current scope. This does not include Variable assignments within the body of a scope which may or may not be the top only if one of these do not exist above it in the same scope.
+ ///
+ public static bool IsScopedVariableAssignment(this VariableExpressionAst var)
+ {
+ // foreach ($x in $y) { }
+ if (var.Parent is ForEachStatementAst forEachAst && forEachAst.Variable == var)
+ {
+ return true;
+ }
+
+ // for ($x = 1; $x -lt 10; $x++) { }
+ if (var.Parent is ForStatementAst forAst && forAst.Initializer is AssignmentStatementAst assignAst && assignAst.Left == var)
+ {
+ return true;
+ }
+
+ // param($x = 1)
+ if (var.Parent is ParameterAst paramAst && paramAst.Name == var)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// For a given string constant, determine if it is a splat, and there is at least one splat reference. If so, return the location of the splat assignment.
+ ///
+ public static VariableExpressionAst? FindSplatParameterReference(this StringConstantExpressionAst stringConstantAst)
+ {
+ if (stringConstantAst.Parent is not HashtableAst hashtableAst) { return null; }
+ if (hashtableAst.Parent is not CommandExpressionAst commandAst) { return null; }
+ if (commandAst.Parent is not AssignmentStatementAst assignmentAst) { return null; }
+ if (assignmentAst.Left is not VariableExpressionAst leftAssignVarAst) { return null; }
+ return assignmentAst.FindStartsAfter(ast =>
+ ast is VariableExpressionAst var
+ && var.Splatted
+ && var.GetUnqualifiedName().Equals(leftAssignVarAst.GetUnqualifiedName(), StringComparison.CurrentCultureIgnoreCase)
+ , true) as VariableExpressionAst;
+ }
+
+ ///
+ /// For a given splat reference, find its source splat assignment. If the reference is not a splat, an exception will be thrown. If no assignment is found, null will be returned.
+ ///
+ public static StringConstantExpressionAst? FindSplatAssignmentReference(this VariableExpressionAst varAst)
+ {
+ if (!varAst.Splatted) { throw new InvalidOperationException("The provided variable reference is not a splat and cannot be used with FindSplatVariableAssignment"); }
+
+ return varAst.FindStartsBefore(ast =>
+ ast is StringConstantExpressionAst stringAst
+ && stringAst.Value == varAst.GetUnqualifiedName()
+ && stringAst.FindSplatParameterReference() == varAst,
+ crossScopeBoundaries: true) as StringConstantExpressionAst;
+ }
+
+ ///
+ /// Returns the function a parameter is defined in. Returns null if it is an anonymous function such as a scriptblock
+ ///
+ public static bool TryGetFunction(this ParameterAst ast, out FunctionDefinitionAst? function)
+ {
+ if (ast.Parent is FunctionDefinitionAst funcDef) { function = funcDef; return true; }
+ if (ast.Parent.Parent is FunctionDefinitionAst paramBlockFuncDef) { function = paramBlockFuncDef; return true; }
+ function = null;
+ return false;
+ }
+
+ ///
+ /// Finds the highest variable expression within a variable assignment within the current scope of the provided variable reference. Returns the original object if it is the highest assignment or null if no assignment was found. It is assumed the reference is part of a larger Ast.
+ ///
+ /// A variable reference that is either a VariableExpression or a StringConstantExpression (splatting reference)
+ public static Ast? GetTopVariableAssignment(this Ast reference)
+ {
+ if (!reference.IsPotentialVariableReference())
+ {
+ throw new NotSupportedException("The provided reference is not a variable reference type.");
+ }
+
+ // Splats are special, we will treat them as a top variable assignment and search both above for a parameter assignment and below for a splat reference, but we don't require a command definition within the same scope for the splat.
+ if (reference is StringConstantExpressionAst stringConstant)
+ {
+ VariableExpressionAst? splat = stringConstant.FindSplatParameterReference();
+ if (splat is null) { return null; }
+ // Find the function associated with the splat parameter reference
+ string? commandName = (splat.Parent as CommandAst)?.GetCommandName().ToLower();
+ if (commandName is null) { return null; }
+ VariableExpressionAst? splatParamReference = splat.FindClosestParameterInFunction(commandName, stringConstant.Value);
+
+ if (splatParamReference is not null)
+ {
+ return splatParamReference;
+ }
+ }
+
+ // If nothing found, search parent scopes for a variable assignment until we hit the top of the document
+ string name = reference switch
+ {
+ VariableExpressionAst varExpression => varExpression.GetUnqualifiedName(),
+ CommandParameterAst param => param.ParameterName,
+ StringConstantExpressionAst stringConstantExpressionAst => stringConstantExpressionAst.Value,
+ _ => throw new NotSupportedException("The provided reference is not a variable reference type.")
+ };
+ VariableExpressionAst? varAssignment = null;
+ Ast? scope = reference;
+
+ while (scope is not null)
+ {
+ // Check if the reference is a parameter in the current scope. This saves us from having to do a nested search later on.
+ IEnumerable? parameters = scope switch
+ {
+ // Covers both function test() { param($x) } and function param($x)
+ FunctionDefinitionAst f => f.Body?.ParamBlock?.Parameters ?? f.Parameters,
+ ScriptBlockAst s => s.ParamBlock?.Parameters,
+ _ => null
+ };
+ ParameterAst? matchParam = parameters?.SingleOrDefault(
+ param => param.Name.GetUnqualifiedName().Equals(name, StringComparison.CurrentCultureIgnoreCase)
+ );
+ if (matchParam is not null)
+ {
+ return matchParam.Name;
+ }
+
+ // Find any top level function definitions in the currentscope that might match the parameter
+ if (reference is CommandParameterAst parameterAst)
+ {
+ string? commandName = (parameterAst.Parent as CommandAst)?.GetCommandName()?.ToLower();
+
+ if (commandName is not null)
+ {
+ VariableExpressionAst? paramDefinition = parameterAst.FindClosestParameterInFunction(commandName, parameterAst.ParameterName);
+ if (paramDefinition is not null)
+ {
+ return paramDefinition;
+ }
+ }
+ }
+
+ // Will find the outermost assignment within the scope that matches the reference.
+ varAssignment = reference switch
+ {
+ VariableExpressionAst => scope.FindStartsBefore(var =>
+ var.GetUnqualifiedName().Equals(name, StringComparison.CurrentCultureIgnoreCase)
+ && (
+ (var.IsVariableAssignment() && !var.IsOperatorAssignment())
+ || var.IsScopedVariableAssignment()
+ )
+ , crossScopeBoundaries: false, searchNestedScriptBlocks: false
+ ),
+
+ CommandParameterAst param => scope.FindStartsBefore(var =>
+ var.GetUnqualifiedName().Equals(name, StringComparison.CurrentCultureIgnoreCase)
+ && var.Parent is ParameterAst paramAst
+ && paramAst.TryGetFunction(out FunctionDefinitionAst? foundFunction)
+ && foundFunction?.Name.ToLower()
+ == (param.Parent as CommandAst)?.GetCommandName()?.ToLower()
+ && foundFunction?.Parent?.Parent == scope
+ ),
+
+ _ => null
+ };
+
+ if (varAssignment is not null)
+ {
+ return varAssignment;
+ }
+
+ if (reference is VariableExpressionAst varAst
+ &&
+ (
+ varAst.IsScopedVariableAssignment()
+ || (varAst.IsVariableAssignment() && !varAst.IsOperatorAssignment())
+ )
+ )
+ {
+ // The current variable reference is the top level assignment because we didn't find any other assignments above it
+ return reference;
+ }
+
+ // Get the next highest scope
+ scope = scope.GetScopeBoundary();
+ }
+
+ // If we make it this far we didn't find any references.
+
+ // An operator assignment can be a definition only as long as there are no assignments above it in all scopes.
+ if (reference is VariableExpressionAst variableAst
+ && variableAst.IsVariableAssignment()
+ && variableAst.IsOperatorAssignment())
+ {
+ return reference;
+ }
+
+ return null;
+ }
+
+ public static bool HasParent(this Ast ast, Ast parent)
+ {
+ Ast? current = ast;
+ while (current is not null)
+ {
+ if (current == parent)
+ {
+ return true;
+ }
+ current = current.Parent;
+ }
+ return false;
+ }
+
+ ///
+ /// Return an extent that only contains the position of the name of the function, for Client highlighting purposes.
+ ///
+ internal static ScriptExtentAdapter GetFunctionNameExtent(this FunctionDefinitionAst ast)
+ {
+ ScriptExtentAdapter funcExtent = new(ast.Extent);
+ string? extentText = ast.Extent.Text;
+
+ if (!string.IsNullOrEmpty(extentText))
+ {
+ (int nameStartOffset, int nameEndOffset) = GetFunctionNameOffsets(extentText, ast.Name);
+ ScriptPosition originalStart = funcExtent.Start;
+ funcExtent.Start = GetPositionAtOffset(originalStart, extentText, nameStartOffset);
+ funcExtent.End = GetPositionAtOffset(originalStart, extentText, nameEndOffset);
+ return funcExtent;
+ }
+
+ // Fallback for unexpected input: preserve the previous behavior as closely as possible.
+ string name = ast.Name;
+ int funcLength = "function ".Length;
+ funcExtent.Start = funcExtent.Start.Delta(0, funcLength);
+ funcExtent.End = funcExtent.Start.Delta(0, name.Length);
+
+ return funcExtent;
+ }
+
+ private static ScriptPosition GetPositionAtOffset(
+ ScriptPosition basePosition,
+ string text,
+ int offset)
+ {
+ int lineDelta = 0;
+ int columnDelta = 0;
+
+ for (int i = 0; i < offset; i++)
+ {
+ char c = text[i];
+ if (c == '\r')
+ {
+ if (i + 1 < offset && text[i + 1] == '\n')
+ {
+ i++;
+ }
+
+ lineDelta++;
+ columnDelta = 0;
+ }
+ else if (c == '\n')
+ {
+ lineDelta++;
+ columnDelta = 0;
+ }
+ else
+ {
+ columnDelta++;
+ }
+ }
+
+ return AdjustPosition(basePosition, lineDelta, columnDelta);
+ }
+
+ private static ScriptPosition AdjustPosition(
+ ScriptPosition basePosition,
+ int lineDelta,
+ int columnDelta)
+ => new(
+ basePosition.File,
+ basePosition.LineNumber + lineDelta,
+ basePosition.ColumnNumber + columnDelta,
+ basePosition.Line);
+
+ internal static (int NameStartOffset, int NameEndOffset) GetFunctionNameOffsets(
+ string text,
+ string functionName)
+ {
+ if (string.IsNullOrEmpty(text))
+ {
+ throw new ArgumentException("Function definition text cannot be null or empty.", nameof(text));
+ }
+
+ if (string.IsNullOrEmpty(functionName))
+ {
+ throw new ArgumentException("Function name cannot be null or empty.", nameof(functionName));
+ }
+
+ int keywordStart = 0;
+ while (keywordStart < text.Length && char.IsWhiteSpace(text[keywordStart]))
+ {
+ keywordStart++;
+ }
+
+ if (keywordStart >= text.Length)
+ {
+ throw new InvalidOperationException("Function definition text does not contain a declaration keyword.");
+ }
+
+ int keywordEnd = keywordStart;
+ while (keywordEnd < text.Length && !char.IsWhiteSpace(text[keywordEnd]))
+ {
+ keywordEnd++;
+ }
+
+ string keyword = text.Substring(keywordStart, keywordEnd - keywordStart);
+ bool isKnownKeyword = keyword.Equals("function", StringComparison.OrdinalIgnoreCase)
+ || keyword.Equals("filter", StringComparison.OrdinalIgnoreCase)
+ || keyword.Equals("workflow", StringComparison.OrdinalIgnoreCase);
+
+ if (!isKnownKeyword)
+ {
+ throw new InvalidOperationException($"Unexpected function definition keyword '{keyword}'.");
+ }
+
+ int nameStartOffset = text.IndexOf(functionName, keywordEnd, StringComparison.Ordinal);
+ if (nameStartOffset < 0)
+ {
+ throw new InvalidOperationException($"Could not find function name '{functionName}' in function definition text.");
+ }
+
+ int nameEndOffset = nameStartOffset + functionName.Length;
+
+ return (nameStartOffset, nameEndOffset);
+ }
+}
diff --git a/src/PowerShellEditorServices/Utility/AsyncUtils.cs b/src/PowerShellEditorServices/Utility/AsyncUtils.cs
index c3f146bb7..c94023a7e 100644
--- a/src/PowerShellEditorServices/Utility/AsyncUtils.cs
+++ b/src/PowerShellEditorServices/Utility/AsyncUtils.cs
@@ -33,6 +33,7 @@ internal static Task HandleErrorsAsync(
: LogTaskErrors(task, logger, callerName, callerSourceFile, callerLineNumber);
}
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD003:Avoid awaiting foreign Tasks", Justification = "It's a wrapper.")]
private static async Task LogTaskErrors(Task task, ILogger logger, string callerName, string callerSourceFile, int callerLineNumber)
{
try
diff --git a/src/PowerShellEditorServices/Utility/LspDebugUtils.cs b/src/PowerShellEditorServices/Utility/LspDebugUtils.cs
index 115689586..36677743c 100644
--- a/src/PowerShellEditorServices/Utility/LspDebugUtils.cs
+++ b/src/PowerShellEditorServices/Utility/LspDebugUtils.cs
@@ -56,38 +56,6 @@ public static Breakpoint CreateBreakpoint(
};
}
- public static StackFrame CreateStackFrame(
- StackFrameDetails stackFrame,
- long id)
- {
- SourcePresentationHint sourcePresentationHint =
- stackFrame.IsExternalCode ? SourcePresentationHint.Deemphasize : SourcePresentationHint.Normal;
-
- // When debugging an interactive session, the ScriptPath is which is not a valid source file.
- // We need to make sure the user can't open the file associated with this stack frame.
- // It will generate a VSCode error in this case.
- Source source = null;
- if (!stackFrame.ScriptPath.Contains("<"))
- {
- source = new Source
- {
- Path = stackFrame.ScriptPath,
- PresentationHint = sourcePresentationHint
- };
- }
-
- return new StackFrame
- {
- Id = id,
- Name = (source != null) ? stackFrame.FunctionName : "Interactive Session",
- Line = (source != null) ? stackFrame.StartLineNumber : 0,
- EndLine = stackFrame.EndLineNumber,
- Column = (source != null) ? stackFrame.StartColumnNumber : 0,
- EndColumn = stackFrame.EndColumnNumber,
- Source = source
- };
- }
-
public static Scope CreateScope(VariableScope scope)
{
return new Scope
diff --git a/src/PowerShellEditorServices/Utility/PSCommandExtensions.cs b/src/PowerShellEditorServices/Utility/PSCommandExtensions.cs
index b16129af9..4fe298424 100644
--- a/src/PowerShellEditorServices/Utility/PSCommandExtensions.cs
+++ b/src/PowerShellEditorServices/Utility/PSCommandExtensions.cs
@@ -94,10 +94,12 @@ private static StringBuilder AddCommandText(this StringBuilder sb, Command comma
public static string EscapeScriptFilePath(string f) => string.Concat("'", f.Replace("'", "''"), "'");
- public static PSCommand BuildDotSourceCommandWithArguments(string command, IEnumerable arguments)
+ // Operator defaults to dot-source but could also be call (ampersand).
+ // It can't be called that because it's a reserved keyword in C#.
+ public static PSCommand BuildDotSourceCommandWithArguments(string command, IEnumerable arguments, string executeMode = ".")
{
string args = string.Join(" ", arguments ?? Array.Empty());
- string script = string.Concat(". ", command, string.IsNullOrEmpty(args) ? "" : " ", args);
+ string script = string.Concat(executeMode, " ", command, string.IsNullOrEmpty(args) ? "" : " ", args);
// HACK: We use AddScript instead of AddArgument/AddParameter to reuse Powershell parameter binding logic.
return new PSCommand().AddScript(script);
}
diff --git a/src/PowerShellEditorServices/packages.lock.json b/src/PowerShellEditorServices/packages.lock.json
deleted file mode 100644
index a41fcb2aa..000000000
--- a/src/PowerShellEditorServices/packages.lock.json
+++ /dev/null
@@ -1,446 +0,0 @@
-{
- "version": 1,
- "dependencies": {
- ".NETStandard,Version=v2.0": {
- "Microsoft.CSharp": {
- "type": "Direct",
- "requested": "[4.7.0, )",
- "resolved": "4.7.0",
- "contentHash": "pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA=="
- },
- "Microsoft.Extensions.FileSystemGlobbing": {
- "type": "Direct",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "OK+670i7esqlQrPjdIKRbsyMCe9g5kSLpRRQGSr4Q58AOYEe/hCnfLZprh7viNisSUUQZmMrbbuDaIrP+V1ebQ=="
- },
- "Microsoft.Extensions.Logging": {
- "type": "Direct",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "tvRkov9tAJ3xP51LCv3FJ2zINmv1P8Hi8lhhtcKGqM+ImiTCC84uOPEI4z8Cdq2C3o9e+Aa0Gw0rmrsJD77W+w==",
- "dependencies": {
- "Microsoft.Bcl.AsyncInterfaces": "8.0.0",
- "Microsoft.Extensions.DependencyInjection": "8.0.0",
- "Microsoft.Extensions.Logging.Abstractions": "8.0.0",
- "Microsoft.Extensions.Options": "8.0.0",
- "System.Diagnostics.DiagnosticSource": "8.0.0"
- }
- },
- "NETStandard.Library": {
- "type": "Direct",
- "requested": "[2.0.3, )",
- "resolved": "2.0.3",
- "contentHash": "st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==",
- "dependencies": {
- "Microsoft.NETCore.Platforms": "1.1.0"
- }
- },
- "OmniSharp.Extensions.DebugAdapter.Server": {
- "type": "Direct",
- "requested": "[0.19.9, )",
- "resolved": "0.19.9",
- "contentHash": "XRJ6EW44DaODkzjAuN1XbpnPFkciJIM2sIx4KpsvV/2Rle1CdRJY4gA6vJn+2uNh5hRr1d0SqZSieqV9Ly0utw==",
- "dependencies": {
- "OmniSharp.Extensions.DebugAdapter.Shared": "0.19.9"
- }
- },
- "OmniSharp.Extensions.LanguageServer": {
- "type": "Direct",
- "requested": "[0.19.9, )",
- "resolved": "0.19.9",
- "contentHash": "g09wOOCQ/oFqtZ47Q5R9E78tz2a5ODEB+V+S65wAiiRskR7xwL78Tse4/8ToBc8G/ZgQgqLtAOPo/BSPmHNlbw==",
- "dependencies": {
- "Microsoft.Extensions.Configuration": "6.0.1",
- "OmniSharp.Extensions.JsonRpc": "0.19.9",
- "OmniSharp.Extensions.LanguageProtocol": "0.19.9",
- "OmniSharp.Extensions.LanguageServer.Shared": "0.19.9"
- }
- },
- "PowerShellStandard.Library": {
- "type": "Direct",
- "requested": "[5.1.1, )",
- "resolved": "5.1.1",
- "contentHash": "e31xJjG+Kjbv6YF3Yq6D4Dl3or8v7LrNF41k3CXrWozW6hR1zcOe5KYuZJaGSiAgLnwP8wcW+I3+IWEzMPZKXQ=="
- },
- "Serilog": {
- "type": "Direct",
- "requested": "[3.1.1, )",
- "resolved": "3.1.1",
- "contentHash": "P6G4/4Kt9bT635bhuwdXlJ2SCqqn2nhh4gqFqQueCOr9bK/e7W9ll/IoX1Ter948cV2Z/5+5v8pAfJYUISY03A==",
- "dependencies": {
- "System.Diagnostics.DiagnosticSource": "7.0.2"
- }
- },
- "Serilog.Extensions.Logging": {
- "type": "Direct",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "YEAMWu1UnWgf1c1KP85l1SgXGfiVo0Rz6x08pCiPOIBt2Qe18tcZLvdBUuV5o1QHvrs8FAry9wTIhgBRtjIlEg==",
- "dependencies": {
- "Microsoft.Extensions.Logging": "8.0.0",
- "Serilog": "3.1.1"
- }
- },
- "Serilog.Sinks.Async": {
- "type": "Direct",
- "requested": "[1.5.0, )",
- "resolved": "1.5.0",
- "contentHash": "csHYIqAwI4Gy9oAhXYRwxGrQEAtBg3Ep7WaCzsnA1cZuBZjVAU0n7hWaJhItjO7hbLHh/9gRVxALCUB4Dv+gZw==",
- "dependencies": {
- "Serilog": "2.9.0"
- }
- },
- "Serilog.Sinks.File": {
- "type": "Direct",
- "requested": "[5.0.0, )",
- "resolved": "5.0.0",
- "contentHash": "uwV5hdhWPwUH1szhO8PJpFiahqXmzPzJT/sOijH/kFgUx+cyoDTMM8MHD0adw9+Iem6itoibbUXHYslzXsLEAg==",
- "dependencies": {
- "Serilog": "2.10.0"
- }
- },
- "System.IO.Pipes.AccessControl": {
- "type": "Direct",
- "requested": "[5.0.0, )",
- "resolved": "5.0.0",
- "contentHash": "P0FIsXSFNL1AXlHO9zpJ9atRUzVyoPZCkcbkYGZfXXMx9xlGA2H3HOGBwIhpKhB+h0eL3hry/z0UcfJZ+yb2kQ==",
- "dependencies": {
- "System.Security.AccessControl": "5.0.0",
- "System.Security.Principal.Windows": "5.0.0"
- }
- },
- "System.Security.Principal": {
- "type": "Direct",
- "requested": "[4.3.0, )",
- "resolved": "4.3.0",
- "contentHash": "I1tkfQlAoMM2URscUtpcRo/hX0jinXx6a/KUtEQoz3owaYwl3qwsO8cbzYVVnjxrzxjHo3nJC+62uolgeGIS9A==",
- "dependencies": {
- "System.Runtime": "4.3.0"
- }
- },
- "System.Security.Principal.Windows": {
- "type": "Direct",
- "requested": "[5.0.0, )",
- "resolved": "5.0.0",
- "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA=="
- },
- "MediatR": {
- "type": "Transitive",
- "resolved": "8.1.0",
- "contentHash": "KJFnA0MV83bNOhvYbjIX1iDykhwFXoQu0KV7E1SVbNA/CmO2I7SAm2Baly0eS7VJ2GwlmStLajBfeiNgTpvYzQ=="
- },
- "Microsoft.Bcl.AsyncInterfaces": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "3WA9q9yVqJp222P3x1wYIGDAkpjAku0TMUaaQV22g6L67AI0LdOIrVS7Ht2vJfLHGSPVuqN94vIr15qn+HEkHw==",
- "dependencies": {
- "System.Threading.Tasks.Extensions": "4.5.4"
- }
- },
- "Microsoft.Extensions.Configuration": {
- "type": "Transitive",
- "resolved": "6.0.1",
- "contentHash": "BUyFU9t+HzlSE7ri4B+AQN2BgTgHv/uM82s5ZkgU1BApyzWzIl48nDsG5wR1t0pniNuuyTBzG3qCW8152/NtSw==",
- "dependencies": {
- "Microsoft.Extensions.Configuration.Abstractions": "6.0.0",
- "Microsoft.Extensions.Primitives": "6.0.0"
- }
- },
- "Microsoft.Extensions.Configuration.Abstractions": {
- "type": "Transitive",
- "resolved": "6.0.0",
- "contentHash": "qWzV9o+ZRWq+pGm+1dF+R7qTgTYoXvbyowRoBxQJGfqTpqDun2eteerjRQhq5PQ/14S+lqto3Ft4gYaRyl4rdQ==",
- "dependencies": {
- "Microsoft.Extensions.Primitives": "6.0.0"
- }
- },
- "Microsoft.Extensions.Configuration.Binder": {
- "type": "Transitive",
- "resolved": "6.0.0",
- "contentHash": "b3ErKzND8LIC7o08QAVlKfaEIYEvLJbtmVbFZVBRXeu9YkKfSSzLZfR1SUfQPBIy9mKLhEtJgGYImkcMNaKE0A==",
- "dependencies": {
- "Microsoft.Extensions.Configuration.Abstractions": "6.0.0"
- }
- },
- "Microsoft.Extensions.DependencyInjection": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "V8S3bsm50ig6JSyrbcJJ8bW2b9QLGouz+G1miK3UTaOWmMtFwNNNzUf4AleyDWUmTrWMLNnFSLEQtxmxgNQnNQ==",
- "dependencies": {
- "Microsoft.Bcl.AsyncInterfaces": "8.0.0",
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "System.Threading.Tasks.Extensions": "4.5.4"
- }
- },
- "Microsoft.Extensions.DependencyInjection.Abstractions": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==",
- "dependencies": {
- "Microsoft.Bcl.AsyncInterfaces": "8.0.0",
- "System.Threading.Tasks.Extensions": "4.5.4"
- }
- },
- "Microsoft.Extensions.Logging.Abstractions": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "arDBqTgFCyS0EvRV7O3MZturChstm50OJ0y9bDJvAcmEPJm0FFpFyjU/JLYyStNGGey081DvnQYlncNX5SJJGA==",
- "dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "System.Buffers": "4.5.1",
- "System.Memory": "4.5.5"
- }
- },
- "Microsoft.Extensions.Options": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "JOVOfqpnqlVLUzINQ2fox8evY2SKLYJ3BV8QDe/Jyp21u1T7r45x/R/5QdteURMR5r01GxeJSBBUOCOyaNXA3g==",
- "dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
- "Microsoft.Extensions.Primitives": "8.0.0",
- "System.ComponentModel.Annotations": "5.0.0"
- }
- },
- "Microsoft.Extensions.Options.ConfigurationExtensions": {
- "type": "Transitive",
- "resolved": "6.0.0",
- "contentHash": "bXWINbTn0vC0FYc9GaQTISbxhQLAMrvtbuvD9N6JelEaIS/Pr62wUCinrq5bf1WRBGczt1v4wDhxFtVFNcMdUQ==",
- "dependencies": {
- "Microsoft.Extensions.Configuration.Abstractions": "6.0.0",
- "Microsoft.Extensions.Configuration.Binder": "6.0.0",
- "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
- "Microsoft.Extensions.Options": "6.0.0",
- "Microsoft.Extensions.Primitives": "6.0.0"
- }
- },
- "Microsoft.Extensions.Primitives": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==",
- "dependencies": {
- "System.Memory": "4.5.5",
- "System.Runtime.CompilerServices.Unsafe": "6.0.0"
- }
- },
- "Microsoft.NETCore.Platforms": {
- "type": "Transitive",
- "resolved": "1.1.0",
- "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A=="
- },
- "Microsoft.NETCore.Targets": {
- "type": "Transitive",
- "resolved": "1.1.0",
- "contentHash": "aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg=="
- },
- "Microsoft.VisualStudio.Threading": {
- "type": "Transitive",
- "resolved": "17.6.40",
- "contentHash": "hLa/0xargG7p3bF7aeq2/lRYn/bVnfZXurUWVHx+MNqxxAUjIDMKi4OIOWbYQ/DTkbn9gv8TLvgso+6EtHVQQg==",
- "dependencies": {
- "Microsoft.Bcl.AsyncInterfaces": "7.0.0",
- "Microsoft.VisualStudio.Threading.Analyzers": "17.6.40",
- "Microsoft.VisualStudio.Validation": "17.0.71",
- "Microsoft.Win32.Registry": "5.0.0",
- "System.Threading.Tasks.Extensions": "4.5.4"
- }
- },
- "Microsoft.VisualStudio.Threading.Analyzers": {
- "type": "Transitive",
- "resolved": "17.6.40",
- "contentHash": "uU8vYr/Nx3ldEWcsbiHiyAX1G7od3eFK1+Aga6ZvgCvU+nQkcXYVkIMcSEkIDWkFaldx1dkoVvX3KRNQD0R7dw=="
- },
- "Microsoft.VisualStudio.Validation": {
- "type": "Transitive",
- "resolved": "17.6.11",
- "contentHash": "J+9L/iac6c8cwcgVSCMuoIYOlD1Jw4mbZ8XMe1IZVj8p8+3dJ46LnnkIkTRMjK7xs9UtU9MoUp1JGhWoN6fAEw=="
- },
- "Microsoft.Win32.Registry": {
- "type": "Transitive",
- "resolved": "5.0.0",
- "contentHash": "dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==",
- "dependencies": {
- "System.Buffers": "4.5.1",
- "System.Memory": "4.5.4",
- "System.Security.AccessControl": "5.0.0",
- "System.Security.Principal.Windows": "5.0.0"
- }
- },
- "Nerdbank.Streams": {
- "type": "Transitive",
- "resolved": "2.10.69",
- "contentHash": "YIudzeVyQRJAqytjpo1jdHkh2t+vqQqyusBqb2sFSOAOGEnyOXhcHx/rQqSuCIXUDr50a3XuZnamGRfQVBOf4g==",
- "dependencies": {
- "Microsoft.Bcl.AsyncInterfaces": "7.0.0",
- "Microsoft.VisualStudio.Threading": "17.6.40",
- "Microsoft.VisualStudio.Validation": "17.6.11",
- "System.IO.Pipelines": "7.0.0",
- "System.Runtime.CompilerServices.Unsafe": "6.0.0"
- }
- },
- "Newtonsoft.Json": {
- "type": "Transitive",
- "resolved": "13.0.3",
- "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
- },
- "OmniSharp.Extensions.DebugAdapter": {
- "type": "Transitive",
- "resolved": "0.19.9",
- "contentHash": "Jy9RlVei7ay3LavvPH4F8BnIIMAo5th5EI8JnVe1RQlOxvu18H8hOyZ8fLFHtzbObs+oTONsJ9aynqeyMOErgA==",
- "dependencies": {
- "Microsoft.Extensions.Configuration": "6.0.1",
- "OmniSharp.Extensions.JsonRpc": "0.19.9",
- "OmniSharp.Extensions.JsonRpc.Generators": "0.19.9"
- }
- },
- "OmniSharp.Extensions.DebugAdapter.Shared": {
- "type": "Transitive",
- "resolved": "0.19.9",
- "contentHash": "A4psuqk+slrs585cCkZkwUO08nW0I6SVH4u7B7d8wU9lH0LLRTvQBlo3QlxrVAMxjwljPFzXaaRHv7D7X1BXbw==",
- "dependencies": {
- "OmniSharp.Extensions.DebugAdapter": "0.19.9",
- "OmniSharp.Extensions.JsonRpc": "0.19.9"
- }
- },
- "OmniSharp.Extensions.JsonRpc": {
- "type": "Transitive",
- "resolved": "0.19.9",
- "contentHash": "utFvrx9OYXhCS5rnfWAVeedJCrucuDLAOrKXjohf/NOjG9FFVbcp+hLqj9Ng+AxoADRD+rSJYHfBOeqGl5zW0A==",
- "dependencies": {
- "MediatR": "8.1.0",
- "Microsoft.Extensions.DependencyInjection": "6.0.1",
- "Microsoft.Extensions.Logging": "6.0.0",
- "Nerdbank.Streams": "2.10.69",
- "Newtonsoft.Json": "13.0.3",
- "OmniSharp.Extensions.JsonRpc.Generators": "0.19.9",
- "System.Collections.Immutable": "5.0.0",
- "System.Reactive": "6.0.0",
- "System.Threading.Channels": "6.0.0"
- }
- },
- "OmniSharp.Extensions.JsonRpc.Generators": {
- "type": "Transitive",
- "resolved": "0.19.9",
- "contentHash": "hiWC0yGcKM+K00fgiL7KBmlvULmkKNhm40ZSzxqT+jNV21r+YZgKzEREhQe40ufb4tjcIxdYkif++IzGl/3H/Q=="
- },
- "OmniSharp.Extensions.LanguageProtocol": {
- "type": "Transitive",
- "resolved": "0.19.9",
- "contentHash": "d0crY6w5SyunGlERP27YeUeJnJfUjvJoALFlPMU4CHu3jovG1Y8RxLpihCPX8fKdjzgy7Ii+VjFYtIpDEEQqYQ==",
- "dependencies": {
- "Microsoft.Extensions.Configuration": "6.0.1",
- "Microsoft.Extensions.Configuration.Binder": "6.0.0",
- "Microsoft.Extensions.Options.ConfigurationExtensions": "6.0.0",
- "OmniSharp.Extensions.JsonRpc": "0.19.9",
- "OmniSharp.Extensions.JsonRpc.Generators": "0.19.9"
- }
- },
- "OmniSharp.Extensions.LanguageServer.Shared": {
- "type": "Transitive",
- "resolved": "0.19.9",
- "contentHash": "+p+py79MrNG3QnqRrBp5J7Wc810HFFczMH8/WLIiUqih1bqmKPFY9l/uzBvq1Ko8+YO/8tzI7BDffHvaguISEw==",
- "dependencies": {
- "OmniSharp.Extensions.LanguageProtocol": "0.19.9"
- }
- },
- "System.Buffers": {
- "type": "Transitive",
- "resolved": "4.5.1",
- "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg=="
- },
- "System.Collections.Immutable": {
- "type": "Transitive",
- "resolved": "5.0.0",
- "contentHash": "FXkLXiK0sVVewcso0imKQoOxjoPAj42R8HtjjbSjVPAzwDfzoyoznWxgA3c38LDbN9SJux1xXoXYAhz98j7r2g==",
- "dependencies": {
- "System.Memory": "4.5.4"
- }
- },
- "System.ComponentModel.Annotations": {
- "type": "Transitive",
- "resolved": "5.0.0",
- "contentHash": "dMkqfy2el8A8/I76n2Hi1oBFEbG1SfxD2l5nhwXV3XjlnOmwxJlQbYpJH4W51odnU9sARCSAgv7S3CyAFMkpYg=="
- },
- "System.Diagnostics.DiagnosticSource": {
- "type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "c9xLpVz6PL9lp/djOWtk5KPDZq3cSYpmXoJQY524EOtuFl5z9ZtsotpsyrDW40U1DRnQSYvcPKEUV0X//u6gkQ==",
- "dependencies": {
- "System.Memory": "4.5.5",
- "System.Runtime.CompilerServices.Unsafe": "6.0.0"
- }
- },
- "System.IO.Pipelines": {
- "type": "Transitive",
- "resolved": "7.0.0",
- "contentHash": "jRn6JYnNPW6xgQazROBLSfpdoczRw694vO5kKvMcNnpXuolEixUyw6IBuBs2Y2mlSX/LdLvyyWmfXhaI3ND1Yg==",
- "dependencies": {
- "System.Buffers": "4.5.1",
- "System.Memory": "4.5.5",
- "System.Threading.Tasks.Extensions": "4.5.4"
- }
- },
- "System.Memory": {
- "type": "Transitive",
- "resolved": "4.5.5",
- "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==",
- "dependencies": {
- "System.Buffers": "4.5.1",
- "System.Numerics.Vectors": "4.4.0",
- "System.Runtime.CompilerServices.Unsafe": "4.5.3"
- }
- },
- "System.Numerics.Vectors": {
- "type": "Transitive",
- "resolved": "4.4.0",
- "contentHash": "UiLzLW+Lw6HLed1Hcg+8jSRttrbuXv7DANVj0DkL9g6EnnzbL75EB7EWsw5uRbhxd/4YdG8li5XizGWepmG3PQ=="
- },
- "System.Reactive": {
- "type": "Transitive",
- "resolved": "6.0.0",
- "contentHash": "31kfaW4ZupZzPsI5PVe77VhnvFF55qgma7KZr/E0iFTs6fmdhhG8j0mgEx620iLTey1EynOkEfnyTjtNEpJzGw==",
- "dependencies": {
- "System.Threading.Tasks.Extensions": "4.5.4"
- }
- },
- "System.Runtime": {
- "type": "Transitive",
- "resolved": "4.3.0",
- "contentHash": "JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==",
- "dependencies": {
- "Microsoft.NETCore.Platforms": "1.1.0",
- "Microsoft.NETCore.Targets": "1.1.0"
- }
- },
- "System.Runtime.CompilerServices.Unsafe": {
- "type": "Transitive",
- "resolved": "6.0.0",
- "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
- },
- "System.Security.AccessControl": {
- "type": "Transitive",
- "resolved": "5.0.0",
- "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==",
- "dependencies": {
- "System.Security.Principal.Windows": "5.0.0"
- }
- },
- "System.Threading.Channels": {
- "type": "Transitive",
- "resolved": "6.0.0",
- "contentHash": "TY8/9+tI0mNaUMgntOxxaq2ndTkdXqLSxvPmas7XEqOlv9lQtB7wLjYGd756lOaO7Dvb5r/WXhluM+0Xe87v5Q==",
- "dependencies": {
- "System.Threading.Tasks.Extensions": "4.5.4"
- }
- },
- "System.Threading.Tasks.Extensions": {
- "type": "Transitive",
- "resolved": "4.5.4",
- "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==",
- "dependencies": {
- "System.Runtime.CompilerServices.Unsafe": "4.5.3"
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/test/PowerShellEditorServices.Test.E2E/DebugAdapterClientExtensions.cs b/test/PowerShellEditorServices.Test.E2E/DebugAdapterClientExtensions.cs
deleted file mode 100644
index bdf785ede..000000000
--- a/test/PowerShellEditorServices.Test.E2E/DebugAdapterClientExtensions.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using System;
-using System.Threading.Tasks;
-using Microsoft.PowerShell.EditorServices.Handlers;
-using OmniSharp.Extensions.DebugAdapter.Client;
-using OmniSharp.Extensions.DebugAdapter.Protocol.Requests;
-
-namespace PowerShellEditorServices.Test.E2E
-{
- public static class DebugAdapterClientExtensions
- {
- public static async Task LaunchScript(this DebugAdapterClient debugAdapterClient, string script, TaskCompletionSource